1e9f4d569SChristian Lamparter /* 2e9f4d569SChristian Lamparter * Generic driver for memory-mapped GPIO controllers. 3e9f4d569SChristian Lamparter * 4e9f4d569SChristian Lamparter * Copyright 2008 MontaVista Software, Inc. 5e9f4d569SChristian Lamparter * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> 6e9f4d569SChristian Lamparter * 7e9f4d569SChristian Lamparter * This program is free software; you can redistribute it and/or modify it 8e9f4d569SChristian Lamparter * under the terms of the GNU General Public License as published by the 9e9f4d569SChristian Lamparter * Free Software Foundation; either version 2 of the License, or (at your 10e9f4d569SChristian Lamparter * option) any later version. 11e9f4d569SChristian Lamparter * 12e9f4d569SChristian Lamparter * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... 13e9f4d569SChristian Lamparter * ...`` ```````.. 14e9f4d569SChristian Lamparter * ..The simplest form of a GPIO controller that the driver supports is`` 15e9f4d569SChristian Lamparter * `.just a single "data" register, where GPIO state can be read and/or ` 16e9f4d569SChristian Lamparter * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.``````` 17e9f4d569SChristian Lamparter * ````````` 18e9f4d569SChristian Lamparter ___ 19e9f4d569SChristian Lamparter _/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,... 20e9f4d569SChristian Lamparter __________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO . 21e9f4d569SChristian Lamparter o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` 22e9f4d569SChristian Lamparter `....trivial..'~`.```.``` 23e9f4d569SChristian Lamparter * ``````` 24e9f4d569SChristian Lamparter * .```````~~~~`..`.``.``. 25e9f4d569SChristian Lamparter * . The driver supports `... ,..```.`~~~```````````````....````.``,, 26e9f4d569SChristian Lamparter * . big-endian notation, just`. .. A bit more sophisticated controllers , 27e9f4d569SChristian Lamparter * . register the device with -be`. .with a pair of set/clear-bit registers , 28e9f4d569SChristian Lamparter * `.. suffix. ```~~`````....`.` . affecting the data register and the .` 29e9f4d569SChristian Lamparter * ``.`.``...``` ```.. output pins are also supported.` 30e9f4d569SChristian Lamparter * ^^ `````.`````````.,``~``~``~~`````` 31e9f4d569SChristian Lamparter * . ^^ 32e9f4d569SChristian Lamparter * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`.. 33e9f4d569SChristian Lamparter * .. The expectation is that in at least some cases . ,-~~~-, 34e9f4d569SChristian Lamparter * .this will be used with roll-your-own ASIC/FPGA .` \ / 35e9f4d569SChristian Lamparter * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ / 36e9f4d569SChristian Lamparter * ..````````......``````````` \o_ 37e9f4d569SChristian Lamparter * | 38e9f4d569SChristian Lamparter * ^^ / \ 39e9f4d569SChristian Lamparter * 40e9f4d569SChristian Lamparter * ...`````~~`.....``.`..........``````.`.``.```........``. 41e9f4d569SChristian Lamparter * ` 8, 16, 32 and 64 bits registers are supported, and``. 42e9f4d569SChristian Lamparter * . the number of GPIOs is determined by the width of ~ 43e9f4d569SChristian Lamparter * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~ 44e9f4d569SChristian Lamparter * `.......````.``` 45e9f4d569SChristian Lamparter */ 46e9f4d569SChristian Lamparter 47e9f4d569SChristian Lamparter #include <linux/init.h> 48e9f4d569SChristian Lamparter #include <linux/err.h> 49e9f4d569SChristian Lamparter #include <linux/bug.h> 50e9f4d569SChristian Lamparter #include <linux/kernel.h> 51e9f4d569SChristian Lamparter #include <linux/module.h> 52e9f4d569SChristian Lamparter #include <linux/spinlock.h> 53e9f4d569SChristian Lamparter #include <linux/compiler.h> 54e9f4d569SChristian Lamparter #include <linux/types.h> 55e9f4d569SChristian Lamparter #include <linux/errno.h> 56e9f4d569SChristian Lamparter #include <linux/log2.h> 57e9f4d569SChristian Lamparter #include <linux/ioport.h> 58e9f4d569SChristian Lamparter #include <linux/io.h> 59e9f4d569SChristian Lamparter #include <linux/gpio/driver.h> 60e9f4d569SChristian Lamparter #include <linux/slab.h> 61e9f4d569SChristian Lamparter #include <linux/bitops.h> 62e9f4d569SChristian Lamparter #include <linux/platform_device.h> 63e9f4d569SChristian Lamparter #include <linux/mod_devicetable.h> 64e698613aSÁlvaro Fernández Rojas #include <linux/of.h> 65e698613aSÁlvaro Fernández Rojas #include <linux/of_device.h> 66e9f4d569SChristian Lamparter 67e9f4d569SChristian Lamparter static void bgpio_write8(void __iomem *reg, unsigned long data) 68e9f4d569SChristian Lamparter { 69e9f4d569SChristian Lamparter writeb(data, reg); 70e9f4d569SChristian Lamparter } 71e9f4d569SChristian Lamparter 72e9f4d569SChristian Lamparter static unsigned long bgpio_read8(void __iomem *reg) 73e9f4d569SChristian Lamparter { 74e9f4d569SChristian Lamparter return readb(reg); 75e9f4d569SChristian Lamparter } 76e9f4d569SChristian Lamparter 77e9f4d569SChristian Lamparter static void bgpio_write16(void __iomem *reg, unsigned long data) 78e9f4d569SChristian Lamparter { 79e9f4d569SChristian Lamparter writew(data, reg); 80e9f4d569SChristian Lamparter } 81e9f4d569SChristian Lamparter 82e9f4d569SChristian Lamparter static unsigned long bgpio_read16(void __iomem *reg) 83e9f4d569SChristian Lamparter { 84e9f4d569SChristian Lamparter return readw(reg); 85e9f4d569SChristian Lamparter } 86e9f4d569SChristian Lamparter 87e9f4d569SChristian Lamparter static void bgpio_write32(void __iomem *reg, unsigned long data) 88e9f4d569SChristian Lamparter { 89e9f4d569SChristian Lamparter writel(data, reg); 90e9f4d569SChristian Lamparter } 91e9f4d569SChristian Lamparter 92e9f4d569SChristian Lamparter static unsigned long bgpio_read32(void __iomem *reg) 93e9f4d569SChristian Lamparter { 94e9f4d569SChristian Lamparter return readl(reg); 95e9f4d569SChristian Lamparter } 96e9f4d569SChristian Lamparter 97e9f4d569SChristian Lamparter #if BITS_PER_LONG >= 64 98e9f4d569SChristian Lamparter static void bgpio_write64(void __iomem *reg, unsigned long data) 99e9f4d569SChristian Lamparter { 100e9f4d569SChristian Lamparter writeq(data, reg); 101e9f4d569SChristian Lamparter } 102e9f4d569SChristian Lamparter 103e9f4d569SChristian Lamparter static unsigned long bgpio_read64(void __iomem *reg) 104e9f4d569SChristian Lamparter { 105e9f4d569SChristian Lamparter return readq(reg); 106e9f4d569SChristian Lamparter } 107e9f4d569SChristian Lamparter #endif /* BITS_PER_LONG >= 64 */ 108e9f4d569SChristian Lamparter 109e9f4d569SChristian Lamparter static void bgpio_write16be(void __iomem *reg, unsigned long data) 110e9f4d569SChristian Lamparter { 111e9f4d569SChristian Lamparter iowrite16be(data, reg); 112e9f4d569SChristian Lamparter } 113e9f4d569SChristian Lamparter 114e9f4d569SChristian Lamparter static unsigned long bgpio_read16be(void __iomem *reg) 115e9f4d569SChristian Lamparter { 116e9f4d569SChristian Lamparter return ioread16be(reg); 117e9f4d569SChristian Lamparter } 118e9f4d569SChristian Lamparter 119e9f4d569SChristian Lamparter static void bgpio_write32be(void __iomem *reg, unsigned long data) 120e9f4d569SChristian Lamparter { 121e9f4d569SChristian Lamparter iowrite32be(data, reg); 122e9f4d569SChristian Lamparter } 123e9f4d569SChristian Lamparter 124e9f4d569SChristian Lamparter static unsigned long bgpio_read32be(void __iomem *reg) 125e9f4d569SChristian Lamparter { 126e9f4d569SChristian Lamparter return ioread32be(reg); 127e9f4d569SChristian Lamparter } 128e9f4d569SChristian Lamparter 129e9f4d569SChristian Lamparter static unsigned long bgpio_pin2mask(struct gpio_chip *gc, unsigned int pin) 130e9f4d569SChristian Lamparter { 131e9f4d569SChristian Lamparter return BIT(pin); 132e9f4d569SChristian Lamparter } 133e9f4d569SChristian Lamparter 134e9f4d569SChristian Lamparter static unsigned long bgpio_pin2mask_be(struct gpio_chip *gc, 135e9f4d569SChristian Lamparter unsigned int pin) 136e9f4d569SChristian Lamparter { 137e9f4d569SChristian Lamparter return BIT(gc->bgpio_bits - 1 - pin); 138e9f4d569SChristian Lamparter } 139e9f4d569SChristian Lamparter 140e9f4d569SChristian Lamparter static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) 141e9f4d569SChristian Lamparter { 142e9f4d569SChristian Lamparter unsigned long pinmask = gc->pin2mask(gc, gpio); 143e9f4d569SChristian Lamparter 144e9f4d569SChristian Lamparter if (gc->bgpio_dir & pinmask) 145e9f4d569SChristian Lamparter return !!(gc->read_reg(gc->reg_set) & pinmask); 146e9f4d569SChristian Lamparter else 147e9f4d569SChristian Lamparter return !!(gc->read_reg(gc->reg_dat) & pinmask); 148e9f4d569SChristian Lamparter } 149e9f4d569SChristian Lamparter 150e9f4d569SChristian Lamparter static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) 151e9f4d569SChristian Lamparter { 152e9f4d569SChristian Lamparter return !!(gc->read_reg(gc->reg_dat) & gc->pin2mask(gc, gpio)); 153e9f4d569SChristian Lamparter } 154e9f4d569SChristian Lamparter 155e9f4d569SChristian Lamparter static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) 156e9f4d569SChristian Lamparter { 157e9f4d569SChristian Lamparter } 158e9f4d569SChristian Lamparter 159e9f4d569SChristian Lamparter static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 160e9f4d569SChristian Lamparter { 161e9f4d569SChristian Lamparter unsigned long mask = gc->pin2mask(gc, gpio); 162e9f4d569SChristian Lamparter unsigned long flags; 163e9f4d569SChristian Lamparter 164e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 165e9f4d569SChristian Lamparter 166e9f4d569SChristian Lamparter if (val) 167e9f4d569SChristian Lamparter gc->bgpio_data |= mask; 168e9f4d569SChristian Lamparter else 169e9f4d569SChristian Lamparter gc->bgpio_data &= ~mask; 170e9f4d569SChristian Lamparter 171e9f4d569SChristian Lamparter gc->write_reg(gc->reg_dat, gc->bgpio_data); 172e9f4d569SChristian Lamparter 173e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 174e9f4d569SChristian Lamparter } 175e9f4d569SChristian Lamparter 176e9f4d569SChristian Lamparter static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, 177e9f4d569SChristian Lamparter int val) 178e9f4d569SChristian Lamparter { 179e9f4d569SChristian Lamparter unsigned long mask = gc->pin2mask(gc, gpio); 180e9f4d569SChristian Lamparter 181e9f4d569SChristian Lamparter if (val) 182e9f4d569SChristian Lamparter gc->write_reg(gc->reg_set, mask); 183e9f4d569SChristian Lamparter else 184e9f4d569SChristian Lamparter gc->write_reg(gc->reg_clr, mask); 185e9f4d569SChristian Lamparter } 186e9f4d569SChristian Lamparter 187e9f4d569SChristian Lamparter static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) 188e9f4d569SChristian Lamparter { 189e9f4d569SChristian Lamparter unsigned long mask = gc->pin2mask(gc, gpio); 190e9f4d569SChristian Lamparter unsigned long flags; 191e9f4d569SChristian Lamparter 192e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 193e9f4d569SChristian Lamparter 194e9f4d569SChristian Lamparter if (val) 195e9f4d569SChristian Lamparter gc->bgpio_data |= mask; 196e9f4d569SChristian Lamparter else 197e9f4d569SChristian Lamparter gc->bgpio_data &= ~mask; 198e9f4d569SChristian Lamparter 199e9f4d569SChristian Lamparter gc->write_reg(gc->reg_set, gc->bgpio_data); 200e9f4d569SChristian Lamparter 201e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 202e9f4d569SChristian Lamparter } 203e9f4d569SChristian Lamparter 204e9f4d569SChristian Lamparter static void bgpio_multiple_get_masks(struct gpio_chip *gc, 205e9f4d569SChristian Lamparter unsigned long *mask, unsigned long *bits, 206e9f4d569SChristian Lamparter unsigned long *set_mask, 207e9f4d569SChristian Lamparter unsigned long *clear_mask) 208e9f4d569SChristian Lamparter { 209e9f4d569SChristian Lamparter int i; 210e9f4d569SChristian Lamparter 211e9f4d569SChristian Lamparter *set_mask = 0; 212e9f4d569SChristian Lamparter *clear_mask = 0; 213e9f4d569SChristian Lamparter 214e9f4d569SChristian Lamparter for (i = 0; i < gc->bgpio_bits; i++) { 215e9f4d569SChristian Lamparter if (*mask == 0) 216e9f4d569SChristian Lamparter break; 217e9f4d569SChristian Lamparter if (__test_and_clear_bit(i, mask)) { 218e9f4d569SChristian Lamparter if (test_bit(i, bits)) 219e9f4d569SChristian Lamparter *set_mask |= gc->pin2mask(gc, i); 220e9f4d569SChristian Lamparter else 221e9f4d569SChristian Lamparter *clear_mask |= gc->pin2mask(gc, i); 222e9f4d569SChristian Lamparter } 223e9f4d569SChristian Lamparter } 224e9f4d569SChristian Lamparter } 225e9f4d569SChristian Lamparter 226e9f4d569SChristian Lamparter static void bgpio_set_multiple_single_reg(struct gpio_chip *gc, 227e9f4d569SChristian Lamparter unsigned long *mask, 228e9f4d569SChristian Lamparter unsigned long *bits, 229e9f4d569SChristian Lamparter void __iomem *reg) 230e9f4d569SChristian Lamparter { 231e9f4d569SChristian Lamparter unsigned long flags; 232e9f4d569SChristian Lamparter unsigned long set_mask, clear_mask; 233e9f4d569SChristian Lamparter 234e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 235e9f4d569SChristian Lamparter 236e9f4d569SChristian Lamparter bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); 237e9f4d569SChristian Lamparter 238e9f4d569SChristian Lamparter gc->bgpio_data |= set_mask; 239e9f4d569SChristian Lamparter gc->bgpio_data &= ~clear_mask; 240e9f4d569SChristian Lamparter 241e9f4d569SChristian Lamparter gc->write_reg(reg, gc->bgpio_data); 242e9f4d569SChristian Lamparter 243e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 244e9f4d569SChristian Lamparter } 245e9f4d569SChristian Lamparter 246e9f4d569SChristian Lamparter static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, 247e9f4d569SChristian Lamparter unsigned long *bits) 248e9f4d569SChristian Lamparter { 249e9f4d569SChristian Lamparter bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_dat); 250e9f4d569SChristian Lamparter } 251e9f4d569SChristian Lamparter 252e9f4d569SChristian Lamparter static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, 253e9f4d569SChristian Lamparter unsigned long *bits) 254e9f4d569SChristian Lamparter { 255e9f4d569SChristian Lamparter bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_set); 256e9f4d569SChristian Lamparter } 257e9f4d569SChristian Lamparter 258e9f4d569SChristian Lamparter static void bgpio_set_multiple_with_clear(struct gpio_chip *gc, 259e9f4d569SChristian Lamparter unsigned long *mask, 260e9f4d569SChristian Lamparter unsigned long *bits) 261e9f4d569SChristian Lamparter { 262e9f4d569SChristian Lamparter unsigned long set_mask, clear_mask; 263e9f4d569SChristian Lamparter 264e9f4d569SChristian Lamparter bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); 265e9f4d569SChristian Lamparter 266e9f4d569SChristian Lamparter if (set_mask) 267e9f4d569SChristian Lamparter gc->write_reg(gc->reg_set, set_mask); 268e9f4d569SChristian Lamparter if (clear_mask) 269e9f4d569SChristian Lamparter gc->write_reg(gc->reg_clr, clear_mask); 270e9f4d569SChristian Lamparter } 271e9f4d569SChristian Lamparter 272e9f4d569SChristian Lamparter static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) 273e9f4d569SChristian Lamparter { 274e9f4d569SChristian Lamparter return 0; 275e9f4d569SChristian Lamparter } 276e9f4d569SChristian Lamparter 277e9f4d569SChristian Lamparter static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, 278e9f4d569SChristian Lamparter int val) 279e9f4d569SChristian Lamparter { 280e9f4d569SChristian Lamparter return -EINVAL; 281e9f4d569SChristian Lamparter } 282e9f4d569SChristian Lamparter 283e9f4d569SChristian Lamparter static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, 284e9f4d569SChristian Lamparter int val) 285e9f4d569SChristian Lamparter { 286e9f4d569SChristian Lamparter gc->set(gc, gpio, val); 287e9f4d569SChristian Lamparter 288e9f4d569SChristian Lamparter return 0; 289e9f4d569SChristian Lamparter } 290e9f4d569SChristian Lamparter 291e9f4d569SChristian Lamparter static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 292e9f4d569SChristian Lamparter { 293e9f4d569SChristian Lamparter unsigned long flags; 294e9f4d569SChristian Lamparter 295e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 296e9f4d569SChristian Lamparter 297e9f4d569SChristian Lamparter gc->bgpio_dir &= ~gc->pin2mask(gc, gpio); 298e9f4d569SChristian Lamparter gc->write_reg(gc->reg_dir, gc->bgpio_dir); 299e9f4d569SChristian Lamparter 300e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 301e9f4d569SChristian Lamparter 302e9f4d569SChristian Lamparter return 0; 303e9f4d569SChristian Lamparter } 304e9f4d569SChristian Lamparter 305e9f4d569SChristian Lamparter static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) 306e9f4d569SChristian Lamparter { 307e9f4d569SChristian Lamparter /* Return 0 if output, 1 of input */ 308e9f4d569SChristian Lamparter return !(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio)); 309e9f4d569SChristian Lamparter } 310e9f4d569SChristian Lamparter 311e9f4d569SChristian Lamparter static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 312e9f4d569SChristian Lamparter { 313e9f4d569SChristian Lamparter unsigned long flags; 314e9f4d569SChristian Lamparter 315e9f4d569SChristian Lamparter gc->set(gc, gpio, val); 316e9f4d569SChristian Lamparter 317e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 318e9f4d569SChristian Lamparter 319e9f4d569SChristian Lamparter gc->bgpio_dir |= gc->pin2mask(gc, gpio); 320e9f4d569SChristian Lamparter gc->write_reg(gc->reg_dir, gc->bgpio_dir); 321e9f4d569SChristian Lamparter 322e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 323e9f4d569SChristian Lamparter 324e9f4d569SChristian Lamparter return 0; 325e9f4d569SChristian Lamparter } 326e9f4d569SChristian Lamparter 327e9f4d569SChristian Lamparter static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio) 328e9f4d569SChristian Lamparter { 329e9f4d569SChristian Lamparter unsigned long flags; 330e9f4d569SChristian Lamparter 331e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 332e9f4d569SChristian Lamparter 333e9f4d569SChristian Lamparter gc->bgpio_dir |= gc->pin2mask(gc, gpio); 334e9f4d569SChristian Lamparter gc->write_reg(gc->reg_dir, gc->bgpio_dir); 335e9f4d569SChristian Lamparter 336e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 337e9f4d569SChristian Lamparter 338e9f4d569SChristian Lamparter return 0; 339e9f4d569SChristian Lamparter } 340e9f4d569SChristian Lamparter 341e9f4d569SChristian Lamparter static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) 342e9f4d569SChristian Lamparter { 343e9f4d569SChristian Lamparter unsigned long flags; 344e9f4d569SChristian Lamparter 345e9f4d569SChristian Lamparter gc->set(gc, gpio, val); 346e9f4d569SChristian Lamparter 347e9f4d569SChristian Lamparter spin_lock_irqsave(&gc->bgpio_lock, flags); 348e9f4d569SChristian Lamparter 349e9f4d569SChristian Lamparter gc->bgpio_dir &= ~gc->pin2mask(gc, gpio); 350e9f4d569SChristian Lamparter gc->write_reg(gc->reg_dir, gc->bgpio_dir); 351e9f4d569SChristian Lamparter 352e9f4d569SChristian Lamparter spin_unlock_irqrestore(&gc->bgpio_lock, flags); 353e9f4d569SChristian Lamparter 354e9f4d569SChristian Lamparter return 0; 355e9f4d569SChristian Lamparter } 356e9f4d569SChristian Lamparter 357e9f4d569SChristian Lamparter static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) 358e9f4d569SChristian Lamparter { 359e9f4d569SChristian Lamparter /* Return 0 if output, 1 if input */ 360e9f4d569SChristian Lamparter return !!(gc->read_reg(gc->reg_dir) & gc->pin2mask(gc, gpio)); 361e9f4d569SChristian Lamparter } 362e9f4d569SChristian Lamparter 363e9f4d569SChristian Lamparter static int bgpio_setup_accessors(struct device *dev, 364e9f4d569SChristian Lamparter struct gpio_chip *gc, 365e9f4d569SChristian Lamparter bool bit_be, 366e9f4d569SChristian Lamparter bool byte_be) 367e9f4d569SChristian Lamparter { 368e9f4d569SChristian Lamparter 369e9f4d569SChristian Lamparter switch (gc->bgpio_bits) { 370e9f4d569SChristian Lamparter case 8: 371e9f4d569SChristian Lamparter gc->read_reg = bgpio_read8; 372e9f4d569SChristian Lamparter gc->write_reg = bgpio_write8; 373e9f4d569SChristian Lamparter break; 374e9f4d569SChristian Lamparter case 16: 375e9f4d569SChristian Lamparter if (byte_be) { 376e9f4d569SChristian Lamparter gc->read_reg = bgpio_read16be; 377e9f4d569SChristian Lamparter gc->write_reg = bgpio_write16be; 378e9f4d569SChristian Lamparter } else { 379e9f4d569SChristian Lamparter gc->read_reg = bgpio_read16; 380e9f4d569SChristian Lamparter gc->write_reg = bgpio_write16; 381e9f4d569SChristian Lamparter } 382e9f4d569SChristian Lamparter break; 383e9f4d569SChristian Lamparter case 32: 384e9f4d569SChristian Lamparter if (byte_be) { 385e9f4d569SChristian Lamparter gc->read_reg = bgpio_read32be; 386e9f4d569SChristian Lamparter gc->write_reg = bgpio_write32be; 387e9f4d569SChristian Lamparter } else { 388e9f4d569SChristian Lamparter gc->read_reg = bgpio_read32; 389e9f4d569SChristian Lamparter gc->write_reg = bgpio_write32; 390e9f4d569SChristian Lamparter } 391e9f4d569SChristian Lamparter break; 392e9f4d569SChristian Lamparter #if BITS_PER_LONG >= 64 393e9f4d569SChristian Lamparter case 64: 394e9f4d569SChristian Lamparter if (byte_be) { 395e9f4d569SChristian Lamparter dev_err(dev, 396e9f4d569SChristian Lamparter "64 bit big endian byte order unsupported\n"); 397e9f4d569SChristian Lamparter return -EINVAL; 398e9f4d569SChristian Lamparter } else { 399e9f4d569SChristian Lamparter gc->read_reg = bgpio_read64; 400e9f4d569SChristian Lamparter gc->write_reg = bgpio_write64; 401e9f4d569SChristian Lamparter } 402e9f4d569SChristian Lamparter break; 403e9f4d569SChristian Lamparter #endif /* BITS_PER_LONG >= 64 */ 404e9f4d569SChristian Lamparter default: 405e9f4d569SChristian Lamparter dev_err(dev, "unsupported data width %u bits\n", gc->bgpio_bits); 406e9f4d569SChristian Lamparter return -EINVAL; 407e9f4d569SChristian Lamparter } 408e9f4d569SChristian Lamparter 409e9f4d569SChristian Lamparter gc->pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask; 410e9f4d569SChristian Lamparter 411e9f4d569SChristian Lamparter return 0; 412e9f4d569SChristian Lamparter } 413e9f4d569SChristian Lamparter 414e9f4d569SChristian Lamparter /* 415e9f4d569SChristian Lamparter * Create the device and allocate the resources. For setting GPIO's there are 416e9f4d569SChristian Lamparter * three supported configurations: 417e9f4d569SChristian Lamparter * 418e9f4d569SChristian Lamparter * - single input/output register resource (named "dat"). 419e9f4d569SChristian Lamparter * - set/clear pair (named "set" and "clr"). 420e9f4d569SChristian Lamparter * - single output register resource and single input resource ("set" and 421e9f4d569SChristian Lamparter * dat"). 422e9f4d569SChristian Lamparter * 423e9f4d569SChristian Lamparter * For the single output register, this drives a 1 by setting a bit and a zero 424e9f4d569SChristian Lamparter * by clearing a bit. For the set clr pair, this drives a 1 by setting a bit 425e9f4d569SChristian Lamparter * in the set register and clears it by setting a bit in the clear register. 426e9f4d569SChristian Lamparter * The configuration is detected by which resources are present. 427e9f4d569SChristian Lamparter * 428e9f4d569SChristian Lamparter * For setting the GPIO direction, there are three supported configurations: 429e9f4d569SChristian Lamparter * 430e9f4d569SChristian Lamparter * - simple bidirection GPIO that requires no configuration. 431e9f4d569SChristian Lamparter * - an output direction register (named "dirout") where a 1 bit 432e9f4d569SChristian Lamparter * indicates the GPIO is an output. 433e9f4d569SChristian Lamparter * - an input direction register (named "dirin") where a 1 bit indicates 434e9f4d569SChristian Lamparter * the GPIO is an input. 435e9f4d569SChristian Lamparter */ 436e9f4d569SChristian Lamparter static int bgpio_setup_io(struct gpio_chip *gc, 437e9f4d569SChristian Lamparter void __iomem *dat, 438e9f4d569SChristian Lamparter void __iomem *set, 439e9f4d569SChristian Lamparter void __iomem *clr, 440e9f4d569SChristian Lamparter unsigned long flags) 441e9f4d569SChristian Lamparter { 442e9f4d569SChristian Lamparter 443e9f4d569SChristian Lamparter gc->reg_dat = dat; 444e9f4d569SChristian Lamparter if (!gc->reg_dat) 445e9f4d569SChristian Lamparter return -EINVAL; 446e9f4d569SChristian Lamparter 447e9f4d569SChristian Lamparter if (set && clr) { 448e9f4d569SChristian Lamparter gc->reg_set = set; 449e9f4d569SChristian Lamparter gc->reg_clr = clr; 450e9f4d569SChristian Lamparter gc->set = bgpio_set_with_clear; 451e9f4d569SChristian Lamparter gc->set_multiple = bgpio_set_multiple_with_clear; 452e9f4d569SChristian Lamparter } else if (set && !clr) { 453e9f4d569SChristian Lamparter gc->reg_set = set; 454e9f4d569SChristian Lamparter gc->set = bgpio_set_set; 455e9f4d569SChristian Lamparter gc->set_multiple = bgpio_set_multiple_set; 456e9f4d569SChristian Lamparter } else if (flags & BGPIOF_NO_OUTPUT) { 457e9f4d569SChristian Lamparter gc->set = bgpio_set_none; 458e9f4d569SChristian Lamparter gc->set_multiple = NULL; 459e9f4d569SChristian Lamparter } else { 460e9f4d569SChristian Lamparter gc->set = bgpio_set; 461e9f4d569SChristian Lamparter gc->set_multiple = bgpio_set_multiple; 462e9f4d569SChristian Lamparter } 463e9f4d569SChristian Lamparter 464e9f4d569SChristian Lamparter if (!(flags & BGPIOF_UNREADABLE_REG_SET) && 465e9f4d569SChristian Lamparter (flags & BGPIOF_READ_OUTPUT_REG_SET)) 466e9f4d569SChristian Lamparter gc->get = bgpio_get_set; 467e9f4d569SChristian Lamparter else 468e9f4d569SChristian Lamparter gc->get = bgpio_get; 469e9f4d569SChristian Lamparter 470e9f4d569SChristian Lamparter return 0; 471e9f4d569SChristian Lamparter } 472e9f4d569SChristian Lamparter 473e9f4d569SChristian Lamparter static int bgpio_setup_direction(struct gpio_chip *gc, 474e9f4d569SChristian Lamparter void __iomem *dirout, 475e9f4d569SChristian Lamparter void __iomem *dirin, 476e9f4d569SChristian Lamparter unsigned long flags) 477e9f4d569SChristian Lamparter { 478e9f4d569SChristian Lamparter if (dirout && dirin) { 479e9f4d569SChristian Lamparter return -EINVAL; 480e9f4d569SChristian Lamparter } else if (dirout) { 481e9f4d569SChristian Lamparter gc->reg_dir = dirout; 482e9f4d569SChristian Lamparter gc->direction_output = bgpio_dir_out; 483e9f4d569SChristian Lamparter gc->direction_input = bgpio_dir_in; 484e9f4d569SChristian Lamparter gc->get_direction = bgpio_get_dir; 485e9f4d569SChristian Lamparter } else if (dirin) { 486e9f4d569SChristian Lamparter gc->reg_dir = dirin; 487e9f4d569SChristian Lamparter gc->direction_output = bgpio_dir_out_inv; 488e9f4d569SChristian Lamparter gc->direction_input = bgpio_dir_in_inv; 489e9f4d569SChristian Lamparter gc->get_direction = bgpio_get_dir_inv; 490e9f4d569SChristian Lamparter } else { 491e9f4d569SChristian Lamparter if (flags & BGPIOF_NO_OUTPUT) 492e9f4d569SChristian Lamparter gc->direction_output = bgpio_dir_out_err; 493e9f4d569SChristian Lamparter else 494e9f4d569SChristian Lamparter gc->direction_output = bgpio_simple_dir_out; 495e9f4d569SChristian Lamparter gc->direction_input = bgpio_simple_dir_in; 496e9f4d569SChristian Lamparter } 497e9f4d569SChristian Lamparter 498e9f4d569SChristian Lamparter return 0; 499e9f4d569SChristian Lamparter } 500e9f4d569SChristian Lamparter 501e9f4d569SChristian Lamparter static int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) 502e9f4d569SChristian Lamparter { 503e9f4d569SChristian Lamparter if (gpio_pin < chip->ngpio) 504e9f4d569SChristian Lamparter return 0; 505e9f4d569SChristian Lamparter 506e9f4d569SChristian Lamparter return -EINVAL; 507e9f4d569SChristian Lamparter } 508e9f4d569SChristian Lamparter 509e9f4d569SChristian Lamparter int bgpio_init(struct gpio_chip *gc, struct device *dev, 510e9f4d569SChristian Lamparter unsigned long sz, void __iomem *dat, void __iomem *set, 511e9f4d569SChristian Lamparter void __iomem *clr, void __iomem *dirout, void __iomem *dirin, 512e9f4d569SChristian Lamparter unsigned long flags) 513e9f4d569SChristian Lamparter { 514e9f4d569SChristian Lamparter int ret; 515e9f4d569SChristian Lamparter 516e9f4d569SChristian Lamparter if (!is_power_of_2(sz)) 517e9f4d569SChristian Lamparter return -EINVAL; 518e9f4d569SChristian Lamparter 519e9f4d569SChristian Lamparter gc->bgpio_bits = sz * 8; 520e9f4d569SChristian Lamparter if (gc->bgpio_bits > BITS_PER_LONG) 521e9f4d569SChristian Lamparter return -EINVAL; 522e9f4d569SChristian Lamparter 523e9f4d569SChristian Lamparter spin_lock_init(&gc->bgpio_lock); 524e9f4d569SChristian Lamparter gc->parent = dev; 525e9f4d569SChristian Lamparter gc->label = dev_name(dev); 526e9f4d569SChristian Lamparter gc->base = -1; 527e9f4d569SChristian Lamparter gc->ngpio = gc->bgpio_bits; 528e9f4d569SChristian Lamparter gc->request = bgpio_request; 529e9f4d569SChristian Lamparter 530e9f4d569SChristian Lamparter ret = bgpio_setup_io(gc, dat, set, clr, flags); 531e9f4d569SChristian Lamparter if (ret) 532e9f4d569SChristian Lamparter return ret; 533e9f4d569SChristian Lamparter 534e9f4d569SChristian Lamparter ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN, 535e9f4d569SChristian Lamparter flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER); 536e9f4d569SChristian Lamparter if (ret) 537e9f4d569SChristian Lamparter return ret; 538e9f4d569SChristian Lamparter 539e9f4d569SChristian Lamparter ret = bgpio_setup_direction(gc, dirout, dirin, flags); 540e9f4d569SChristian Lamparter if (ret) 541e9f4d569SChristian Lamparter return ret; 542e9f4d569SChristian Lamparter 543e9f4d569SChristian Lamparter gc->bgpio_data = gc->read_reg(gc->reg_dat); 544e9f4d569SChristian Lamparter if (gc->set == bgpio_set_set && 545e9f4d569SChristian Lamparter !(flags & BGPIOF_UNREADABLE_REG_SET)) 546e9f4d569SChristian Lamparter gc->bgpio_data = gc->read_reg(gc->reg_set); 547e9f4d569SChristian Lamparter if (gc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR)) 548e9f4d569SChristian Lamparter gc->bgpio_dir = gc->read_reg(gc->reg_dir); 549e9f4d569SChristian Lamparter 550e9f4d569SChristian Lamparter return ret; 551e9f4d569SChristian Lamparter } 552e9f4d569SChristian Lamparter EXPORT_SYMBOL_GPL(bgpio_init); 553e9f4d569SChristian Lamparter 554e9f4d569SChristian Lamparter #if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM) 555e9f4d569SChristian Lamparter 556e9f4d569SChristian Lamparter static void __iomem *bgpio_map(struct platform_device *pdev, 557e9f4d569SChristian Lamparter const char *name, 558e9f4d569SChristian Lamparter resource_size_t sane_sz) 559e9f4d569SChristian Lamparter { 560e9f4d569SChristian Lamparter struct resource *r; 561e9f4d569SChristian Lamparter resource_size_t sz; 562e9f4d569SChristian Lamparter 563e9f4d569SChristian Lamparter r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 564e9f4d569SChristian Lamparter if (!r) 565e9f4d569SChristian Lamparter return NULL; 566e9f4d569SChristian Lamparter 567e9f4d569SChristian Lamparter sz = resource_size(r); 568e9f4d569SChristian Lamparter if (sz != sane_sz) 569e9f4d569SChristian Lamparter return IOMEM_ERR_PTR(-EINVAL); 570e9f4d569SChristian Lamparter 571e9f4d569SChristian Lamparter return devm_ioremap_resource(&pdev->dev, r); 572e9f4d569SChristian Lamparter } 573e9f4d569SChristian Lamparter 574e698613aSÁlvaro Fernández Rojas #ifdef CONFIG_OF 575e698613aSÁlvaro Fernández Rojas static const struct of_device_id bgpio_of_match[] = { 57605cc995fSChristian Lamparter { .compatible = "brcm,bcm6345-gpio" }, 577c0d30ecfSChristian Lamparter { .compatible = "wd,mbl-gpio" }, 578*b8c90199SNathan Sullivan { .compatible = "ni,169445-nand-gpio" }, 579e698613aSÁlvaro Fernández Rojas { } 580e698613aSÁlvaro Fernández Rojas }; 581e698613aSÁlvaro Fernández Rojas MODULE_DEVICE_TABLE(of, bgpio_of_match); 582e698613aSÁlvaro Fernández Rojas 583e698613aSÁlvaro Fernández Rojas static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, 584e698613aSÁlvaro Fernández Rojas unsigned long *flags) 585e698613aSÁlvaro Fernández Rojas { 586e698613aSÁlvaro Fernández Rojas struct bgpio_pdata *pdata; 587e698613aSÁlvaro Fernández Rojas 588e698613aSÁlvaro Fernández Rojas if (!of_match_device(bgpio_of_match, &pdev->dev)) 589e698613aSÁlvaro Fernández Rojas return NULL; 590e698613aSÁlvaro Fernández Rojas 591e698613aSÁlvaro Fernández Rojas pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata), 592e698613aSÁlvaro Fernández Rojas GFP_KERNEL); 593e698613aSÁlvaro Fernández Rojas if (!pdata) 594e698613aSÁlvaro Fernández Rojas return ERR_PTR(-ENOMEM); 595e698613aSÁlvaro Fernández Rojas 596e698613aSÁlvaro Fernández Rojas pdata->base = -1; 597e698613aSÁlvaro Fernández Rojas 59805cc995fSChristian Lamparter if (of_device_is_big_endian(pdev->dev.of_node)) 59905cc995fSChristian Lamparter *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER; 60005cc995fSChristian Lamparter 601c0d30ecfSChristian Lamparter if (of_property_read_bool(pdev->dev.of_node, "no-output")) 602c0d30ecfSChristian Lamparter *flags |= BGPIOF_NO_OUTPUT; 603c0d30ecfSChristian Lamparter 604e698613aSÁlvaro Fernández Rojas return pdata; 605e698613aSÁlvaro Fernández Rojas } 606e698613aSÁlvaro Fernández Rojas #else 607e698613aSÁlvaro Fernández Rojas static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, 608e698613aSÁlvaro Fernández Rojas unsigned long *flags) 609e698613aSÁlvaro Fernández Rojas { 610e698613aSÁlvaro Fernández Rojas return NULL; 611e698613aSÁlvaro Fernández Rojas } 612e698613aSÁlvaro Fernández Rojas #endif /* CONFIG_OF */ 613e698613aSÁlvaro Fernández Rojas 614e9f4d569SChristian Lamparter static int bgpio_pdev_probe(struct platform_device *pdev) 615e9f4d569SChristian Lamparter { 616e9f4d569SChristian Lamparter struct device *dev = &pdev->dev; 617e9f4d569SChristian Lamparter struct resource *r; 618e9f4d569SChristian Lamparter void __iomem *dat; 619e9f4d569SChristian Lamparter void __iomem *set; 620e9f4d569SChristian Lamparter void __iomem *clr; 621e9f4d569SChristian Lamparter void __iomem *dirout; 622e9f4d569SChristian Lamparter void __iomem *dirin; 623e9f4d569SChristian Lamparter unsigned long sz; 624e698613aSÁlvaro Fernández Rojas unsigned long flags = 0; 625e9f4d569SChristian Lamparter int err; 626e9f4d569SChristian Lamparter struct gpio_chip *gc; 627e698613aSÁlvaro Fernández Rojas struct bgpio_pdata *pdata; 628e698613aSÁlvaro Fernández Rojas 629e698613aSÁlvaro Fernández Rojas pdata = bgpio_parse_dt(pdev, &flags); 630e698613aSÁlvaro Fernández Rojas if (IS_ERR(pdata)) 631e698613aSÁlvaro Fernández Rojas return PTR_ERR(pdata); 632e698613aSÁlvaro Fernández Rojas 633e698613aSÁlvaro Fernández Rojas if (!pdata) { 634e698613aSÁlvaro Fernández Rojas pdata = dev_get_platdata(dev); 635e698613aSÁlvaro Fernández Rojas flags = pdev->id_entry->driver_data; 636e698613aSÁlvaro Fernández Rojas } 637e9f4d569SChristian Lamparter 638e9f4d569SChristian Lamparter r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 639e9f4d569SChristian Lamparter if (!r) 640e9f4d569SChristian Lamparter return -EINVAL; 641e9f4d569SChristian Lamparter 642e9f4d569SChristian Lamparter sz = resource_size(r); 643e9f4d569SChristian Lamparter 644e9f4d569SChristian Lamparter dat = bgpio_map(pdev, "dat", sz); 645e9f4d569SChristian Lamparter if (IS_ERR(dat)) 646e9f4d569SChristian Lamparter return PTR_ERR(dat); 647e9f4d569SChristian Lamparter 648e9f4d569SChristian Lamparter set = bgpio_map(pdev, "set", sz); 649e9f4d569SChristian Lamparter if (IS_ERR(set)) 650e9f4d569SChristian Lamparter return PTR_ERR(set); 651e9f4d569SChristian Lamparter 652e9f4d569SChristian Lamparter clr = bgpio_map(pdev, "clr", sz); 653e9f4d569SChristian Lamparter if (IS_ERR(clr)) 654e9f4d569SChristian Lamparter return PTR_ERR(clr); 655e9f4d569SChristian Lamparter 656e9f4d569SChristian Lamparter dirout = bgpio_map(pdev, "dirout", sz); 657e9f4d569SChristian Lamparter if (IS_ERR(dirout)) 658e9f4d569SChristian Lamparter return PTR_ERR(dirout); 659e9f4d569SChristian Lamparter 660e9f4d569SChristian Lamparter dirin = bgpio_map(pdev, "dirin", sz); 661e9f4d569SChristian Lamparter if (IS_ERR(dirin)) 662e9f4d569SChristian Lamparter return PTR_ERR(dirin); 663e9f4d569SChristian Lamparter 664e9f4d569SChristian Lamparter gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); 665e9f4d569SChristian Lamparter if (!gc) 666e9f4d569SChristian Lamparter return -ENOMEM; 667e9f4d569SChristian Lamparter 668e9f4d569SChristian Lamparter err = bgpio_init(gc, dev, sz, dat, set, clr, dirout, dirin, flags); 669e9f4d569SChristian Lamparter if (err) 670e9f4d569SChristian Lamparter return err; 671e9f4d569SChristian Lamparter 672e9f4d569SChristian Lamparter if (pdata) { 673e9f4d569SChristian Lamparter if (pdata->label) 674e9f4d569SChristian Lamparter gc->label = pdata->label; 675e9f4d569SChristian Lamparter gc->base = pdata->base; 676e9f4d569SChristian Lamparter if (pdata->ngpio > 0) 677e9f4d569SChristian Lamparter gc->ngpio = pdata->ngpio; 678e9f4d569SChristian Lamparter } 679e9f4d569SChristian Lamparter 680e9f4d569SChristian Lamparter platform_set_drvdata(pdev, gc); 681e9f4d569SChristian Lamparter 682e9f4d569SChristian Lamparter return devm_gpiochip_add_data(&pdev->dev, gc, NULL); 683e9f4d569SChristian Lamparter } 684e9f4d569SChristian Lamparter 685e9f4d569SChristian Lamparter static const struct platform_device_id bgpio_id_table[] = { 686e9f4d569SChristian Lamparter { 687e9f4d569SChristian Lamparter .name = "basic-mmio-gpio", 688e9f4d569SChristian Lamparter .driver_data = 0, 689e9f4d569SChristian Lamparter }, { 690e9f4d569SChristian Lamparter .name = "basic-mmio-gpio-be", 691e9f4d569SChristian Lamparter .driver_data = BGPIOF_BIG_ENDIAN, 692e9f4d569SChristian Lamparter }, 693e9f4d569SChristian Lamparter { } 694e9f4d569SChristian Lamparter }; 695e9f4d569SChristian Lamparter MODULE_DEVICE_TABLE(platform, bgpio_id_table); 696e9f4d569SChristian Lamparter 697e9f4d569SChristian Lamparter static struct platform_driver bgpio_driver = { 698e9f4d569SChristian Lamparter .driver = { 699e9f4d569SChristian Lamparter .name = "basic-mmio-gpio", 700e698613aSÁlvaro Fernández Rojas .of_match_table = of_match_ptr(bgpio_of_match), 701e9f4d569SChristian Lamparter }, 702e9f4d569SChristian Lamparter .id_table = bgpio_id_table, 703e9f4d569SChristian Lamparter .probe = bgpio_pdev_probe, 704e9f4d569SChristian Lamparter }; 705e9f4d569SChristian Lamparter 706e9f4d569SChristian Lamparter module_platform_driver(bgpio_driver); 707e9f4d569SChristian Lamparter 708e9f4d569SChristian Lamparter #endif /* CONFIG_GPIO_GENERIC_PLATFORM */ 709e9f4d569SChristian Lamparter 710e9f4d569SChristian Lamparter MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); 711e9f4d569SChristian Lamparter MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 712e9f4d569SChristian Lamparter MODULE_LICENSE("GPL"); 713