linux/drivers/gpio/gpio-tc3589x.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson SA 2010
   3 *
   4 * License Terms: GNU General Public License, version 2
   5 * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
   6 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/platform_device.h>
  11#include <linux/slab.h>
  12#include <linux/gpio/driver.h>
  13#include <linux/of.h>
  14#include <linux/interrupt.h>
  15#include <linux/mfd/tc3589x.h>
  16#include <linux/bitops.h>
  17
  18/*
  19 * These registers are modified under the irq bus lock and cached to avoid
  20 * unnecessary writes in bus_sync_unlock.
  21 */
  22enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
  23
  24#define CACHE_NR_REGS   4
  25#define CACHE_NR_BANKS  3
  26
  27struct tc3589x_gpio {
  28        struct gpio_chip chip;
  29        struct tc3589x *tc3589x;
  30        struct device *dev;
  31        struct mutex irq_lock;
  32        /* Caches of interrupt control registers for bus_lock */
  33        u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
  34        u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
  35};
  36
  37static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned int offset)
  38{
  39        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
  40        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
  41        u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
  42        u8 mask = BIT(offset % 8);
  43        int ret;
  44
  45        ret = tc3589x_reg_read(tc3589x, reg);
  46        if (ret < 0)
  47                return ret;
  48
  49        return !!(ret & mask);
  50}
  51
  52static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
  53{
  54        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
  55        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
  56        u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
  57        unsigned int pos = offset % 8;
  58        u8 data[] = {val ? BIT(pos) : 0, BIT(pos)};
  59
  60        tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
  61}
  62
  63static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
  64                                         unsigned int offset, int val)
  65{
  66        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
  67        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
  68        u8 reg = TC3589x_GPIODIR0 + offset / 8;
  69        unsigned int pos = offset % 8;
  70
  71        tc3589x_gpio_set(chip, offset, val);
  72
  73        return tc3589x_set_bits(tc3589x, reg, BIT(pos), BIT(pos));
  74}
  75
  76static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
  77                                        unsigned int offset)
  78{
  79        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
  80        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
  81        u8 reg = TC3589x_GPIODIR0 + offset / 8;
  82        unsigned int pos = offset % 8;
  83
  84        return tc3589x_set_bits(tc3589x, reg, BIT(pos), 0);
  85}
  86
  87static int tc3589x_gpio_get_direction(struct gpio_chip *chip,
  88                                      unsigned int offset)
  89{
  90        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
  91        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
  92        u8 reg = TC3589x_GPIODIR0 + offset / 8;
  93        unsigned int pos = offset % 8;
  94        int ret;
  95
  96        ret = tc3589x_reg_read(tc3589x, reg);
  97        if (ret < 0)
  98                return ret;
  99
 100        return !(ret & BIT(pos));
 101}
 102
 103static int tc3589x_gpio_set_single_ended(struct gpio_chip *chip,
 104                                         unsigned int offset,
 105                                         enum single_ended_mode mode)
 106{
 107        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 108        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 109        /*
 110         * These registers are alterated at each second address
 111         * ODM bit 0 = drive to GND or Hi-Z (open drain)
 112         * ODM bit 1 = drive to VDD or Hi-Z (open source)
 113         */
 114        u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2;
 115        u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2;
 116        unsigned int pos = offset % 8;
 117        int ret;
 118
 119        switch(mode) {
 120        case LINE_MODE_OPEN_DRAIN:
 121                /* Set open drain mode */
 122                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0);
 123                if (ret)
 124                        return ret;
 125                /* Enable open drain/source mode */
 126                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
 127        case LINE_MODE_OPEN_SOURCE:
 128                /* Set open source mode */
 129                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos));
 130                if (ret)
 131                        return ret;
 132                /* Enable open drain/source mode */
 133                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
 134        case LINE_MODE_PUSH_PULL:
 135                /* Disable open drain/source mode */
 136                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0);
 137        default:
 138                break;
 139        }
 140        return -ENOTSUPP;
 141}
 142
 143static const struct gpio_chip template_chip = {
 144        .label                  = "tc3589x",
 145        .owner                  = THIS_MODULE,
 146        .get                    = tc3589x_gpio_get,
 147        .set                    = tc3589x_gpio_set,
 148        .direction_output       = tc3589x_gpio_direction_output,
 149        .direction_input        = tc3589x_gpio_direction_input,
 150        .get_direction          = tc3589x_gpio_get_direction,
 151        .set_single_ended       = tc3589x_gpio_set_single_ended,
 152        .can_sleep              = true,
 153};
 154
 155static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 156{
 157        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 158        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 159        int offset = d->hwirq;
 160        int regoffset = offset / 8;
 161        int mask = BIT(offset % 8);
 162
 163        if (type == IRQ_TYPE_EDGE_BOTH) {
 164                tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
 165                return 0;
 166        }
 167
 168        tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask;
 169
 170        if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
 171                tc3589x_gpio->regs[REG_IS][regoffset] |= mask;
 172        else
 173                tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask;
 174
 175        if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
 176                tc3589x_gpio->regs[REG_IEV][regoffset] |= mask;
 177        else
 178                tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask;
 179
 180        return 0;
 181}
 182
 183static void tc3589x_gpio_irq_lock(struct irq_data *d)
 184{
 185        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 186        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 187
 188        mutex_lock(&tc3589x_gpio->irq_lock);
 189}
 190
 191static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
 192{
 193        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 194        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 195        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 196        static const u8 regmap[] = {
 197                [REG_IBE]       = TC3589x_GPIOIBE0,
 198                [REG_IEV]       = TC3589x_GPIOIEV0,
 199                [REG_IS]        = TC3589x_GPIOIS0,
 200                [REG_IE]        = TC3589x_GPIOIE0,
 201        };
 202        int i, j;
 203
 204        for (i = 0; i < CACHE_NR_REGS; i++) {
 205                for (j = 0; j < CACHE_NR_BANKS; j++) {
 206                        u8 old = tc3589x_gpio->oldregs[i][j];
 207                        u8 new = tc3589x_gpio->regs[i][j];
 208
 209                        if (new == old)
 210                                continue;
 211
 212                        tc3589x_gpio->oldregs[i][j] = new;
 213                        tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
 214                }
 215        }
 216
 217        mutex_unlock(&tc3589x_gpio->irq_lock);
 218}
 219
 220static void tc3589x_gpio_irq_mask(struct irq_data *d)
 221{
 222        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 223        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 224        int offset = d->hwirq;
 225        int regoffset = offset / 8;
 226        int mask = BIT(offset % 8);
 227
 228        tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
 229}
 230
 231static void tc3589x_gpio_irq_unmask(struct irq_data *d)
 232{
 233        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 234        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 235        int offset = d->hwirq;
 236        int regoffset = offset / 8;
 237        int mask = BIT(offset % 8);
 238
 239        tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
 240}
 241
 242static struct irq_chip tc3589x_gpio_irq_chip = {
 243        .name                   = "tc3589x-gpio",
 244        .irq_bus_lock           = tc3589x_gpio_irq_lock,
 245        .irq_bus_sync_unlock    = tc3589x_gpio_irq_sync_unlock,
 246        .irq_mask               = tc3589x_gpio_irq_mask,
 247        .irq_unmask             = tc3589x_gpio_irq_unmask,
 248        .irq_set_type           = tc3589x_gpio_irq_set_type,
 249};
 250
 251static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
 252{
 253        struct tc3589x_gpio *tc3589x_gpio = dev;
 254        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 255        u8 status[CACHE_NR_BANKS];
 256        int ret;
 257        int i;
 258
 259        ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0,
 260                                 ARRAY_SIZE(status), status);
 261        if (ret < 0)
 262                return IRQ_NONE;
 263
 264        for (i = 0; i < ARRAY_SIZE(status); i++) {
 265                unsigned int stat = status[i];
 266                if (!stat)
 267                        continue;
 268
 269                while (stat) {
 270                        int bit = __ffs(stat);
 271                        int line = i * 8 + bit;
 272                        int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
 273                                                   line);
 274
 275                        handle_nested_irq(irq);
 276                        stat &= ~(1 << bit);
 277                }
 278
 279                tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]);
 280        }
 281
 282        return IRQ_HANDLED;
 283}
 284
 285static int tc3589x_gpio_probe(struct platform_device *pdev)
 286{
 287        struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
 288        struct device_node *np = pdev->dev.of_node;
 289        struct tc3589x_gpio *tc3589x_gpio;
 290        int ret;
 291        int irq;
 292
 293        if (!np) {
 294                dev_err(&pdev->dev, "No Device Tree node found\n");
 295                return -EINVAL;
 296        }
 297
 298        irq = platform_get_irq(pdev, 0);
 299        if (irq < 0)
 300                return irq;
 301
 302        tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio),
 303                                    GFP_KERNEL);
 304        if (!tc3589x_gpio)
 305                return -ENOMEM;
 306
 307        mutex_init(&tc3589x_gpio->irq_lock);
 308
 309        tc3589x_gpio->dev = &pdev->dev;
 310        tc3589x_gpio->tc3589x = tc3589x;
 311
 312        tc3589x_gpio->chip = template_chip;
 313        tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
 314        tc3589x_gpio->chip.parent = &pdev->dev;
 315        tc3589x_gpio->chip.base = -1;
 316        tc3589x_gpio->chip.of_node = np;
 317
 318        /* Bring the GPIO module out of reset */
 319        ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
 320                               TC3589x_RSTCTRL_GPIRST, 0);
 321        if (ret < 0)
 322                return ret;
 323
 324        ret = devm_request_threaded_irq(&pdev->dev,
 325                                        irq, NULL, tc3589x_gpio_irq,
 326                                        IRQF_ONESHOT, "tc3589x-gpio",
 327                                        tc3589x_gpio);
 328        if (ret) {
 329                dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
 330                return ret;
 331        }
 332
 333        ret = devm_gpiochip_add_data(&pdev->dev, &tc3589x_gpio->chip,
 334                                     tc3589x_gpio);
 335        if (ret) {
 336                dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 337                return ret;
 338        }
 339
 340        ret =  gpiochip_irqchip_add(&tc3589x_gpio->chip,
 341                                    &tc3589x_gpio_irq_chip,
 342                                    0,
 343                                    handle_simple_irq,
 344                                    IRQ_TYPE_NONE);
 345        if (ret) {
 346                dev_err(&pdev->dev,
 347                        "could not connect irqchip to gpiochip\n");
 348                return ret;
 349        }
 350
 351        gpiochip_set_chained_irqchip(&tc3589x_gpio->chip,
 352                                     &tc3589x_gpio_irq_chip,
 353                                     irq,
 354                                     NULL);
 355
 356        platform_set_drvdata(pdev, tc3589x_gpio);
 357
 358        return 0;
 359}
 360
 361static struct platform_driver tc3589x_gpio_driver = {
 362        .driver.name    = "tc3589x-gpio",
 363        .probe          = tc3589x_gpio_probe,
 364};
 365
 366static int __init tc3589x_gpio_init(void)
 367{
 368        return platform_driver_register(&tc3589x_gpio_driver);
 369}
 370subsys_initcall(tc3589x_gpio_init);
 371