linux/drivers/gpio/gpio-menz127.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * MEN 16Z127 GPIO driver
   4 *
   5 * Copyright (C) 2016 MEN Mikroelektronik GmbH (www.men.de)
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/io.h>
  11#include <linux/err.h>
  12#include <linux/mcb.h>
  13#include <linux/bitops.h>
  14#include <linux/gpio/driver.h>
  15
  16#define MEN_Z127_CTRL   0x00
  17#define MEN_Z127_PSR    0x04
  18#define MEN_Z127_IRQR   0x08
  19#define MEN_Z127_GPIODR 0x0c
  20#define MEN_Z127_IER1   0x10
  21#define MEN_Z127_IER2   0x14
  22#define MEN_Z127_DBER   0x18
  23#define MEN_Z127_ODER   0x1C
  24#define GPIO_TO_DBCNT_REG(gpio) ((gpio * 4) + 0x80)
  25
  26#define MEN_Z127_DB_MIN_US      50
  27/* 16 bit compare register. Each bit represents 50us */
  28#define MEN_Z127_DB_MAX_US      (0xffff * MEN_Z127_DB_MIN_US)
  29#define MEN_Z127_DB_IN_RANGE(db)        ((db >= MEN_Z127_DB_MIN_US) && \
  30                                         (db <= MEN_Z127_DB_MAX_US))
  31
  32struct men_z127_gpio {
  33        struct gpio_chip gc;
  34        void __iomem *reg_base;
  35        struct resource *mem;
  36};
  37
  38static int men_z127_debounce(struct gpio_chip *gc, unsigned gpio,
  39                             unsigned debounce)
  40{
  41        struct men_z127_gpio *priv = gpiochip_get_data(gc);
  42        struct device *dev = gc->parent;
  43        unsigned int rnd;
  44        u32 db_en, db_cnt;
  45
  46        if (!MEN_Z127_DB_IN_RANGE(debounce)) {
  47                dev_err(dev, "debounce value %u out of range", debounce);
  48                return -EINVAL;
  49        }
  50
  51        if (debounce > 0) {
  52                /* round up or down depending on MSB-1 */
  53                rnd = fls(debounce) - 1;
  54
  55                if (rnd && (debounce & BIT(rnd - 1)))
  56                        debounce = roundup(debounce, MEN_Z127_DB_MIN_US);
  57                else
  58                        debounce = rounddown(debounce, MEN_Z127_DB_MIN_US);
  59
  60                if (debounce > MEN_Z127_DB_MAX_US)
  61                        debounce = MEN_Z127_DB_MAX_US;
  62
  63                /* 50us per register unit */
  64                debounce /= 50;
  65        }
  66
  67        raw_spin_lock(&gc->bgpio_lock);
  68
  69        db_en = readl(priv->reg_base + MEN_Z127_DBER);
  70
  71        if (debounce == 0) {
  72                db_en &= ~BIT(gpio);
  73                db_cnt = 0;
  74        } else {
  75                db_en |= BIT(gpio);
  76                db_cnt = debounce;
  77        }
  78
  79        writel(db_en, priv->reg_base + MEN_Z127_DBER);
  80        writel(db_cnt, priv->reg_base + GPIO_TO_DBCNT_REG(gpio));
  81
  82        raw_spin_unlock(&gc->bgpio_lock);
  83
  84        return 0;
  85}
  86
  87static int men_z127_set_single_ended(struct gpio_chip *gc,
  88                                     unsigned offset,
  89                                     enum pin_config_param param)
  90{
  91        struct men_z127_gpio *priv = gpiochip_get_data(gc);
  92        u32 od_en;
  93
  94        raw_spin_lock(&gc->bgpio_lock);
  95        od_en = readl(priv->reg_base + MEN_Z127_ODER);
  96
  97        if (param == PIN_CONFIG_DRIVE_OPEN_DRAIN)
  98                od_en |= BIT(offset);
  99        else
 100                /* Implicitly PIN_CONFIG_DRIVE_PUSH_PULL */
 101                od_en &= ~BIT(offset);
 102
 103        writel(od_en, priv->reg_base + MEN_Z127_ODER);
 104        raw_spin_unlock(&gc->bgpio_lock);
 105
 106        return 0;
 107}
 108
 109static int men_z127_set_config(struct gpio_chip *gc, unsigned offset,
 110                               unsigned long config)
 111{
 112        enum pin_config_param param = pinconf_to_config_param(config);
 113
 114        switch (param) {
 115        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 116        case PIN_CONFIG_DRIVE_PUSH_PULL:
 117                return men_z127_set_single_ended(gc, offset, param);
 118
 119        case PIN_CONFIG_INPUT_DEBOUNCE:
 120                return men_z127_debounce(gc, offset,
 121                        pinconf_to_config_argument(config));
 122
 123        default:
 124                break;
 125        }
 126
 127        return -ENOTSUPP;
 128}
 129
 130static int men_z127_probe(struct mcb_device *mdev,
 131                          const struct mcb_device_id *id)
 132{
 133        struct men_z127_gpio *men_z127_gpio;
 134        struct device *dev = &mdev->dev;
 135        int ret;
 136
 137        men_z127_gpio = devm_kzalloc(dev, sizeof(struct men_z127_gpio),
 138                                     GFP_KERNEL);
 139        if (!men_z127_gpio)
 140                return -ENOMEM;
 141
 142        men_z127_gpio->mem = mcb_request_mem(mdev, dev_name(dev));
 143        if (IS_ERR(men_z127_gpio->mem)) {
 144                dev_err(dev, "failed to request device memory");
 145                return PTR_ERR(men_z127_gpio->mem);
 146        }
 147
 148        men_z127_gpio->reg_base = ioremap(men_z127_gpio->mem->start,
 149                                          resource_size(men_z127_gpio->mem));
 150        if (men_z127_gpio->reg_base == NULL) {
 151                ret = -ENXIO;
 152                goto err_release;
 153        }
 154
 155        mcb_set_drvdata(mdev, men_z127_gpio);
 156
 157        ret = bgpio_init(&men_z127_gpio->gc, &mdev->dev, 4,
 158                         men_z127_gpio->reg_base + MEN_Z127_PSR,
 159                         men_z127_gpio->reg_base + MEN_Z127_CTRL,
 160                         NULL,
 161                         men_z127_gpio->reg_base + MEN_Z127_GPIODR,
 162                         NULL, 0);
 163        if (ret)
 164                goto err_unmap;
 165
 166        men_z127_gpio->gc.set_config = men_z127_set_config;
 167
 168        ret = gpiochip_add_data(&men_z127_gpio->gc, men_z127_gpio);
 169        if (ret) {
 170                dev_err(dev, "failed to register MEN 16Z127 GPIO controller");
 171                goto err_unmap;
 172        }
 173
 174        dev_info(dev, "MEN 16Z127 GPIO driver registered");
 175
 176        return 0;
 177
 178err_unmap:
 179        iounmap(men_z127_gpio->reg_base);
 180err_release:
 181        mcb_release_mem(men_z127_gpio->mem);
 182        return ret;
 183}
 184
 185static void men_z127_remove(struct mcb_device *mdev)
 186{
 187        struct men_z127_gpio *men_z127_gpio = mcb_get_drvdata(mdev);
 188
 189        gpiochip_remove(&men_z127_gpio->gc);
 190        iounmap(men_z127_gpio->reg_base);
 191        mcb_release_mem(men_z127_gpio->mem);
 192}
 193
 194static const struct mcb_device_id men_z127_ids[] = {
 195        { .device = 0x7f },
 196        { }
 197};
 198MODULE_DEVICE_TABLE(mcb, men_z127_ids);
 199
 200static struct mcb_driver men_z127_driver = {
 201        .driver = {
 202                .name = "z127-gpio",
 203        },
 204        .probe = men_z127_probe,
 205        .remove = men_z127_remove,
 206        .id_table = men_z127_ids,
 207};
 208module_mcb_driver(men_z127_driver);
 209
 210MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
 211MODULE_DESCRIPTION("MEN 16z127 GPIO Controller");
 212MODULE_LICENSE("GPL v2");
 213MODULE_ALIAS("mcb:16z127");
 214MODULE_IMPORT_NS(MCB);
 215