linux/drivers/gpio/gpio-it87.c
<<
>>
Prefs
   1/*
   2 *  GPIO interface for IT87xx Super I/O chips
   3 *
   4 *  Author: Diego Elio Pettenò <flameeyes@flameeyes.eu>
   5 *
   6 *  Based on it87_wdt.c     by Oliver Schuster
   7 *           gpio-it8761e.c by Denis Turischev
   8 *           gpio-stmpe.c   by Rabin Vincent
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License 2 as published
  12 *  by the Free Software Foundation.
  13 *
  14 *  This program is distributed in the hope that it will be useful,
  15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 *  GNU General Public License for more details.
  18 *
  19 *  You should have received a copy of the GNU General Public License
  20 *  along with this program; see the file COPYING.  If not, write to
  21 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  22 */
  23
  24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  25
  26#include <linux/init.h>
  27#include <linux/kernel.h>
  28#include <linux/module.h>
  29#include <linux/io.h>
  30#include <linux/errno.h>
  31#include <linux/ioport.h>
  32#include <linux/slab.h>
  33#include <linux/gpio.h>
  34
  35/* Chip Id numbers */
  36#define NO_DEV_ID       0xffff
  37#define IT8620_ID       0x8620
  38#define IT8628_ID       0x8628
  39#define IT8728_ID       0x8728
  40#define IT8732_ID       0x8732
  41#define IT8761_ID       0x8761
  42
  43/* IO Ports */
  44#define REG             0x2e
  45#define VAL             0x2f
  46
  47/* Logical device Numbers LDN */
  48#define GPIO            0x07
  49
  50/* Configuration Registers and Functions */
  51#define LDNREG          0x07
  52#define CHIPID          0x20
  53#define CHIPREV         0x22
  54
  55/**
  56 * struct it87_gpio - it87-specific GPIO chip
  57 * @chip the underlying gpio_chip structure
  58 * @lock a lock to avoid races between operations
  59 * @io_base base address for gpio ports
  60 * @io_size size of the port rage starting from io_base.
  61 * @output_base Super I/O register address for Output Enable register
  62 * @simple_base Super I/O 'Simple I/O' Enable register
  63 * @simple_size Super IO 'Simple I/O' Enable register size; this is
  64 *      required because IT87xx chips might only provide Simple I/O
  65 *      switches on a subset of lines, whereas the others keep the
  66 *      same status all time.
  67 */
  68struct it87_gpio {
  69        struct gpio_chip chip;
  70        spinlock_t lock;
  71        u16 io_base;
  72        u16 io_size;
  73        u8 output_base;
  74        u8 simple_base;
  75        u8 simple_size;
  76};
  77
  78static struct it87_gpio it87_gpio_chip = {
  79        .lock = __SPIN_LOCK_UNLOCKED(it87_gpio_chip.lock),
  80};
  81
  82/* Superio chip access functions; copied from wdt_it87 */
  83
  84static inline int superio_enter(void)
  85{
  86        /*
  87         * Try to reserve REG and REG + 1 for exclusive access.
  88         */
  89        if (!request_muxed_region(REG, 2, KBUILD_MODNAME))
  90                return -EBUSY;
  91
  92        outb(0x87, REG);
  93        outb(0x01, REG);
  94        outb(0x55, REG);
  95        outb(0x55, REG);
  96        return 0;
  97}
  98
  99static inline void superio_exit(void)
 100{
 101        outb(0x02, REG);
 102        outb(0x02, VAL);
 103        release_region(REG, 2);
 104}
 105
 106static inline void superio_select(int ldn)
 107{
 108        outb(LDNREG, REG);
 109        outb(ldn, VAL);
 110}
 111
 112static inline int superio_inb(int reg)
 113{
 114        outb(reg, REG);
 115        return inb(VAL);
 116}
 117
 118static inline void superio_outb(int val, int reg)
 119{
 120        outb(reg, REG);
 121        outb(val, VAL);
 122}
 123
 124static inline int superio_inw(int reg)
 125{
 126        int val;
 127
 128        outb(reg++, REG);
 129        val = inb(VAL) << 8;
 130        outb(reg, REG);
 131        val |= inb(VAL);
 132        return val;
 133}
 134
 135static inline void superio_outw(int val, int reg)
 136{
 137        outb(reg++, REG);
 138        outb(val >> 8, VAL);
 139        outb(reg, REG);
 140        outb(val, VAL);
 141}
 142
 143static inline void superio_set_mask(int mask, int reg)
 144{
 145        u8 curr_val = superio_inb(reg);
 146        u8 new_val = curr_val | mask;
 147
 148        if (curr_val != new_val)
 149                superio_outb(new_val, reg);
 150}
 151
 152static inline void superio_clear_mask(int mask, int reg)
 153{
 154        u8 curr_val = superio_inb(reg);
 155        u8 new_val = curr_val & ~mask;
 156
 157        if (curr_val != new_val)
 158                superio_outb(new_val, reg);
 159}
 160
 161static int it87_gpio_request(struct gpio_chip *chip, unsigned gpio_num)
 162{
 163        u8 mask, group;
 164        int rc = 0;
 165        struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 166
 167        mask = 1 << (gpio_num % 8);
 168        group = (gpio_num / 8);
 169
 170        spin_lock(&it87_gpio->lock);
 171
 172        rc = superio_enter();
 173        if (rc)
 174                goto exit;
 175
 176        /* not all the IT87xx chips support Simple I/O and not all of
 177         * them allow all the lines to be set/unset to Simple I/O.
 178         */
 179        if (group < it87_gpio->simple_size)
 180                superio_set_mask(mask, group + it87_gpio->simple_base);
 181
 182        /* clear output enable, setting the pin to input, as all the
 183         * newly-exported GPIO interfaces are set to input.
 184         */
 185        superio_clear_mask(mask, group + it87_gpio->output_base);
 186
 187        superio_exit();
 188
 189exit:
 190        spin_unlock(&it87_gpio->lock);
 191        return rc;
 192}
 193
 194static int it87_gpio_get(struct gpio_chip *chip, unsigned gpio_num)
 195{
 196        u16 reg;
 197        u8 mask;
 198        struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 199
 200        mask = 1 << (gpio_num % 8);
 201        reg = (gpio_num / 8) + it87_gpio->io_base;
 202
 203        return !!(inb(reg) & mask);
 204}
 205
 206static int it87_gpio_direction_in(struct gpio_chip *chip, unsigned gpio_num)
 207{
 208        u8 mask, group;
 209        int rc = 0;
 210        struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 211
 212        mask = 1 << (gpio_num % 8);
 213        group = (gpio_num / 8);
 214
 215        spin_lock(&it87_gpio->lock);
 216
 217        rc = superio_enter();
 218        if (rc)
 219                goto exit;
 220
 221        /* clear the output enable bit */
 222        superio_clear_mask(mask, group + it87_gpio->output_base);
 223
 224        superio_exit();
 225
 226exit:
 227        spin_unlock(&it87_gpio->lock);
 228        return rc;
 229}
 230
 231static void it87_gpio_set(struct gpio_chip *chip,
 232                          unsigned gpio_num, int val)
 233{
 234        u8 mask, curr_vals;
 235        u16 reg;
 236        struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 237
 238        mask = 1 << (gpio_num % 8);
 239        reg = (gpio_num / 8) + it87_gpio->io_base;
 240
 241        curr_vals = inb(reg);
 242        if (val)
 243                outb(curr_vals | mask, reg);
 244        else
 245                outb(curr_vals & ~mask, reg);
 246}
 247
 248static int it87_gpio_direction_out(struct gpio_chip *chip,
 249                                   unsigned gpio_num, int val)
 250{
 251        u8 mask, group;
 252        int rc = 0;
 253        struct it87_gpio *it87_gpio = gpiochip_get_data(chip);
 254
 255        mask = 1 << (gpio_num % 8);
 256        group = (gpio_num / 8);
 257
 258        spin_lock(&it87_gpio->lock);
 259
 260        rc = superio_enter();
 261        if (rc)
 262                goto exit;
 263
 264        /* set the output enable bit */
 265        superio_set_mask(mask, group + it87_gpio->output_base);
 266
 267        it87_gpio_set(chip, gpio_num, val);
 268
 269        superio_exit();
 270
 271exit:
 272        spin_unlock(&it87_gpio->lock);
 273        return rc;
 274}
 275
 276static const struct gpio_chip it87_template_chip = {
 277        .label                  = KBUILD_MODNAME,
 278        .owner                  = THIS_MODULE,
 279        .request                = it87_gpio_request,
 280        .get                    = it87_gpio_get,
 281        .direction_input        = it87_gpio_direction_in,
 282        .set                    = it87_gpio_set,
 283        .direction_output       = it87_gpio_direction_out,
 284        .base                   = -1
 285};
 286
 287static int __init it87_gpio_init(void)
 288{
 289        int rc = 0, i;
 290        u16 chip_type;
 291        u8 chip_rev, gpio_ba_reg;
 292        char *labels, **labels_table;
 293
 294        struct it87_gpio *it87_gpio = &it87_gpio_chip;
 295
 296        rc = superio_enter();
 297        if (rc)
 298                return rc;
 299
 300        chip_type = superio_inw(CHIPID);
 301        chip_rev  = superio_inb(CHIPREV) & 0x0f;
 302        superio_exit();
 303
 304        it87_gpio->chip = it87_template_chip;
 305
 306        switch (chip_type) {
 307        case IT8620_ID:
 308        case IT8628_ID:
 309                gpio_ba_reg = 0x62;
 310                it87_gpio->io_size = 11;
 311                it87_gpio->output_base = 0xc8;
 312                it87_gpio->simple_size = 0;
 313                it87_gpio->chip.ngpio = 64;
 314                break;
 315        case IT8728_ID:
 316        case IT8732_ID:
 317                gpio_ba_reg = 0x62;
 318                it87_gpio->io_size = 8;
 319                it87_gpio->output_base = 0xc8;
 320                it87_gpio->simple_base = 0xc0;
 321                it87_gpio->simple_size = 5;
 322                it87_gpio->chip.ngpio = 64;
 323                break;
 324        case IT8761_ID:
 325                gpio_ba_reg = 0x60;
 326                it87_gpio->io_size = 4;
 327                it87_gpio->output_base = 0xf0;
 328                it87_gpio->simple_size = 0;
 329                it87_gpio->chip.ngpio = 16;
 330                break;
 331        case NO_DEV_ID:
 332                pr_err("no device\n");
 333                return -ENODEV;
 334        default:
 335                pr_err("Unknown Chip found, Chip %04x Revision %x\n",
 336                       chip_type, chip_rev);
 337                return -ENODEV;
 338        }
 339
 340        rc = superio_enter();
 341        if (rc)
 342                return rc;
 343
 344        superio_select(GPIO);
 345
 346        /* fetch GPIO base address */
 347        it87_gpio->io_base = superio_inw(gpio_ba_reg);
 348
 349        superio_exit();
 350
 351        pr_info("Found Chip IT%04x rev %x. %u GPIO lines starting at %04xh\n",
 352                chip_type, chip_rev, it87_gpio->chip.ngpio,
 353                it87_gpio->io_base);
 354
 355        if (!request_region(it87_gpio->io_base, it87_gpio->io_size,
 356                                                        KBUILD_MODNAME))
 357                return -EBUSY;
 358
 359        /* Set up aliases for the GPIO connection.
 360         *
 361         * ITE documentation for recent chips such as the IT8728F
 362         * refers to the GPIO lines as GPxy, with a coordinates system
 363         * where x is the GPIO group (starting from 1) and y is the
 364         * bit within the group.
 365         *
 366         * By creating these aliases, we make it easier to understand
 367         * to which GPIO pin we're referring to.
 368         */
 369        labels = kcalloc(it87_gpio->chip.ngpio, sizeof("it87_gpXY"),
 370                                                                GFP_KERNEL);
 371        labels_table = kcalloc(it87_gpio->chip.ngpio, sizeof(const char *),
 372                                                                GFP_KERNEL);
 373
 374        if (!labels || !labels_table) {
 375                rc = -ENOMEM;
 376                goto labels_free;
 377        }
 378
 379        for (i = 0; i < it87_gpio->chip.ngpio; i++) {
 380                char *label = &labels[i * sizeof("it87_gpXY")];
 381
 382                sprintf(label, "it87_gp%u%u", 1+(i/8), i%8);
 383                labels_table[i] = label;
 384        }
 385
 386        it87_gpio->chip.names = (const char *const*)labels_table;
 387
 388        rc = gpiochip_add_data(&it87_gpio->chip, it87_gpio);
 389        if (rc)
 390                goto labels_free;
 391
 392        return 0;
 393
 394labels_free:
 395        kfree(labels_table);
 396        kfree(labels);
 397        release_region(it87_gpio->io_base, it87_gpio->io_size);
 398        return rc;
 399}
 400
 401static void __exit it87_gpio_exit(void)
 402{
 403        struct it87_gpio *it87_gpio = &it87_gpio_chip;
 404
 405        gpiochip_remove(&it87_gpio->chip);
 406        release_region(it87_gpio->io_base, it87_gpio->io_size);
 407        kfree(it87_gpio->chip.names[0]);
 408        kfree(it87_gpio->chip.names);
 409}
 410
 411module_init(it87_gpio_init);
 412module_exit(it87_gpio_exit);
 413
 414MODULE_AUTHOR("Diego Elio Pettenò <flameeyes@flameeyes.eu>");
 415MODULE_DESCRIPTION("GPIO interface for IT87xx Super I/O chips");
 416MODULE_LICENSE("GPL");
 417