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_config(struct gpio_chip *chip, unsigned int offset,
 104                                   unsigned long config)
 105{
 106        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(chip);
 107        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 108        /*
 109         * These registers are alterated at each second address
 110         * ODM bit 0 = drive to GND or Hi-Z (open drain)
 111         * ODM bit 1 = drive to VDD or Hi-Z (open source)
 112         */
 113        u8 odmreg = TC3589x_GPIOODM0 + (offset / 8) * 2;
 114        u8 odereg = TC3589x_GPIOODE0 + (offset / 8) * 2;
 115        unsigned int pos = offset % 8;
 116        int ret;
 117
 118        switch (pinconf_to_config_param(config)) {
 119        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 120                /* Set open drain mode */
 121                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), 0);
 122                if (ret)
 123                        return ret;
 124                /* Enable open drain/source mode */
 125                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
 126        case PIN_CONFIG_DRIVE_OPEN_SOURCE:
 127                /* Set open source mode */
 128                ret = tc3589x_set_bits(tc3589x, odmreg, BIT(pos), BIT(pos));
 129                if (ret)
 130                        return ret;
 131                /* Enable open drain/source mode */
 132                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), BIT(pos));
 133        case PIN_CONFIG_DRIVE_PUSH_PULL:
 134                /* Disable open drain/source mode */
 135                return tc3589x_set_bits(tc3589x, odereg, BIT(pos), 0);
 136        default:
 137                break;
 138        }
 139        return -ENOTSUPP;
 140}
 141
 142static const struct gpio_chip template_chip = {
 143        .label                  = "tc3589x",
 144        .owner                  = THIS_MODULE,
 145        .get                    = tc3589x_gpio_get,
 146        .set                    = tc3589x_gpio_set,
 147        .direction_output       = tc3589x_gpio_direction_output,
 148        .direction_input        = tc3589x_gpio_direction_input,
 149        .get_direction          = tc3589x_gpio_get_direction,
 150        .set_config             = tc3589x_gpio_set_config,
 151        .can_sleep              = true,
 152};
 153
 154static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 155{
 156        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 157        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 158        int offset = d->hwirq;
 159        int regoffset = offset / 8;
 160        int mask = BIT(offset % 8);
 161
 162        if (type == IRQ_TYPE_EDGE_BOTH) {
 163                tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
 164                return 0;
 165        }
 166
 167        tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask;
 168
 169        if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
 170                tc3589x_gpio->regs[REG_IS][regoffset] |= mask;
 171        else
 172                tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask;
 173
 174        if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
 175                tc3589x_gpio->regs[REG_IEV][regoffset] |= mask;
 176        else
 177                tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask;
 178
 179        return 0;
 180}
 181
 182static void tc3589x_gpio_irq_lock(struct irq_data *d)
 183{
 184        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 185        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 186
 187        mutex_lock(&tc3589x_gpio->irq_lock);
 188}
 189
 190static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d)
 191{
 192        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 193        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 194        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 195        static const u8 regmap[] = {
 196                [REG_IBE]       = TC3589x_GPIOIBE0,
 197                [REG_IEV]       = TC3589x_GPIOIEV0,
 198                [REG_IS]        = TC3589x_GPIOIS0,
 199                [REG_IE]        = TC3589x_GPIOIE0,
 200        };
 201        int i, j;
 202
 203        for (i = 0; i < CACHE_NR_REGS; i++) {
 204                for (j = 0; j < CACHE_NR_BANKS; j++) {
 205                        u8 old = tc3589x_gpio->oldregs[i][j];
 206                        u8 new = tc3589x_gpio->regs[i][j];
 207
 208                        if (new == old)
 209                                continue;
 210
 211                        tc3589x_gpio->oldregs[i][j] = new;
 212                        tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
 213                }
 214        }
 215
 216        mutex_unlock(&tc3589x_gpio->irq_lock);
 217}
 218
 219static void tc3589x_gpio_irq_mask(struct irq_data *d)
 220{
 221        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 222        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 223        int offset = d->hwirq;
 224        int regoffset = offset / 8;
 225        int mask = BIT(offset % 8);
 226
 227        tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
 228}
 229
 230static void tc3589x_gpio_irq_unmask(struct irq_data *d)
 231{
 232        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 233        struct tc3589x_gpio *tc3589x_gpio = gpiochip_get_data(gc);
 234        int offset = d->hwirq;
 235        int regoffset = offset / 8;
 236        int mask = BIT(offset % 8);
 237
 238        tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
 239}
 240
 241static struct irq_chip tc3589x_gpio_irq_chip = {
 242        .name                   = "tc3589x-gpio",
 243        .irq_bus_lock           = tc3589x_gpio_irq_lock,
 244        .irq_bus_sync_unlock    = tc3589x_gpio_irq_sync_unlock,
 245        .irq_mask               = tc3589x_gpio_irq_mask,
 246        .irq_unmask             = tc3589x_gpio_irq_unmask,
 247        .irq_set_type           = tc3589x_gpio_irq_set_type,
 248};
 249
 250static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
 251{
 252        struct tc3589x_gpio *tc3589x_gpio = dev;
 253        struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
 254        u8 status[CACHE_NR_BANKS];
 255        int ret;
 256        int i;
 257
 258        ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0,
 259                                 ARRAY_SIZE(status), status);
 260        if (ret < 0)
 261                return IRQ_NONE;
 262
 263        for (i = 0; i < ARRAY_SIZE(status); i++) {
 264                unsigned int stat = status[i];
 265                if (!stat)
 266                        continue;
 267
 268                while (stat) {
 269                        int bit = __ffs(stat);
 270                        int line = i * 8 + bit;
 271                        int irq = irq_find_mapping(tc3589x_gpio->chip.irq.domain,
 272                                                   line);
 273
 274                        handle_nested_irq(irq);
 275                        stat &= ~(1 << bit);
 276                }
 277
 278                tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]);
 279        }
 280
 281        return IRQ_HANDLED;
 282}
 283
 284static int tc3589x_gpio_probe(struct platform_device *pdev)
 285{
 286        struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
 287        struct device_node *np = pdev->dev.of_node;
 288        struct tc3589x_gpio *tc3589x_gpio;
 289        int ret;
 290        int irq;
 291
 292        if (!np) {
 293                dev_err(&pdev->dev, "No Device Tree node found\n");
 294                return -EINVAL;
 295        }
 296
 297        irq = platform_get_irq(pdev, 0);
 298        if (irq < 0)
 299                return irq;
 300
 301        tc3589x_gpio = devm_kzalloc(&pdev->dev, sizeof(struct tc3589x_gpio),
 302                                    GFP_KERNEL);
 303        if (!tc3589x_gpio)
 304                return -ENOMEM;
 305
 306        mutex_init(&tc3589x_gpio->irq_lock);
 307
 308        tc3589x_gpio->dev = &pdev->dev;
 309        tc3589x_gpio->tc3589x = tc3589x;
 310
 311        tc3589x_gpio->chip = template_chip;
 312        tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
 313        tc3589x_gpio->chip.parent = &pdev->dev;
 314        tc3589x_gpio->chip.base = -1;
 315        tc3589x_gpio->chip.of_node = np;
 316
 317        /* Bring the GPIO module out of reset */
 318        ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
 319                               TC3589x_RSTCTRL_GPIRST, 0);
 320        if (ret < 0)
 321                return ret;
 322
 323        ret = devm_request_threaded_irq(&pdev->dev,
 324                                        irq, NULL, tc3589x_gpio_irq,
 325                                        IRQF_ONESHOT, "tc3589x-gpio",
 326                                        tc3589x_gpio);
 327        if (ret) {
 328                dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
 329                return ret;
 330        }
 331
 332        ret = devm_gpiochip_add_data(&pdev->dev, &tc3589x_gpio->chip,
 333                                     tc3589x_gpio);
 334        if (ret) {
 335                dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
 336                return ret;
 337        }
 338
 339        ret =  gpiochip_irqchip_add_nested(&tc3589x_gpio->chip,
 340                                           &tc3589x_gpio_irq_chip,
 341                                           0,
 342                                           handle_simple_irq,
 343                                           IRQ_TYPE_NONE);
 344        if (ret) {
 345                dev_err(&pdev->dev,
 346                        "could not connect irqchip to gpiochip\n");
 347                return ret;
 348        }
 349
 350        gpiochip_set_nested_irqchip(&tc3589x_gpio->chip,
 351                                    &tc3589x_gpio_irq_chip,
 352                                    irq);
 353
 354        platform_set_drvdata(pdev, tc3589x_gpio);
 355
 356        return 0;
 357}
 358
 359static struct platform_driver tc3589x_gpio_driver = {
 360        .driver.name    = "tc3589x-gpio",
 361        .probe          = tc3589x_gpio_probe,
 362};
 363
 364static int __init tc3589x_gpio_init(void)
 365{
 366        return platform_driver_register(&tc3589x_gpio_driver);
 367}
 368subsys_initcall(tc3589x_gpio_init);
 369