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