linux/drivers/gpio/gpio-sch311x.c
<<
>>
Prefs
   1/*
   2 * GPIO driver for the SMSC SCH311x Super-I/O chips
   3 *
   4 * Copyright (C) 2013 Bruno Randolf <br1@einfach.org>
   5 *
   6 * SuperIO functions and chip detection:
   7 * (c) Copyright 2008 Wim Van Sebroeck <wim@iguana.be>.
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 */
  14
  15#include <linux/ioport.h>
  16#include <linux/module.h>
  17#include <linux/kernel.h>
  18#include <linux/init.h>
  19#include <linux/platform_device.h>
  20#include <linux/gpio/driver.h>
  21#include <linux/bitops.h>
  22#include <linux/io.h>
  23
  24#define DRV_NAME                        "gpio-sch311x"
  25
  26#define SCH311X_GPIO_CONF_DIR           BIT(0)
  27#define SCH311X_GPIO_CONF_INVERT        BIT(1)
  28#define SCH311X_GPIO_CONF_OPEN_DRAIN    BIT(7)
  29
  30#define SIO_CONFIG_KEY_ENTER            0x55
  31#define SIO_CONFIG_KEY_EXIT             0xaa
  32
  33#define GP1                             0x4b
  34
  35static int sch311x_ioports[] = { 0x2e, 0x4e, 0x162e, 0x164e };
  36
  37static struct platform_device *sch311x_gpio_pdev;
  38
  39struct sch311x_pdev_data {              /* platform device data */
  40        unsigned short runtime_reg;     /* runtime register base address */
  41};
  42
  43struct sch311x_gpio_block {             /* one GPIO block runtime data */
  44        struct gpio_chip chip;
  45        unsigned short data_reg;        /* from definition below */
  46        unsigned short *config_regs;    /* pointer to definition below */
  47        unsigned short runtime_reg;     /* runtime register */
  48        spinlock_t lock;                /* lock for this GPIO block */
  49};
  50
  51struct sch311x_gpio_priv {              /* driver private data */
  52        struct sch311x_gpio_block blocks[6];
  53};
  54
  55struct sch311x_gpio_block_def {         /* register address definitions */
  56        unsigned short data_reg;
  57        unsigned short config_regs[8];
  58        unsigned short base;
  59};
  60
  61/* Note: some GPIOs are not available, these are marked with 0x00 */
  62
  63static struct sch311x_gpio_block_def sch311x_gpio_blocks[] = {
  64        {
  65                .data_reg = 0x4b,       /* GP1 */
  66                .config_regs = {0x23, 0x24, 0x25, 0x26, 0x27, 0x29, 0x2a, 0x2b},
  67                .base = 10,
  68        },
  69        {
  70                .data_reg = 0x4c,       /* GP2 */
  71                .config_regs = {0x00, 0x2c, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x32},
  72                .base = 20,
  73        },
  74        {
  75                .data_reg = 0x4d,       /* GP3 */
  76                .config_regs = {0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x39, 0x3a},
  77                .base = 30,
  78        },
  79        {
  80                .data_reg = 0x4e,       /* GP4 */
  81                .config_regs = {0x3b, 0x00, 0x3d, 0x00, 0x6e, 0x6f, 0x72, 0x73},
  82                .base = 40,
  83        },
  84        {
  85                .data_reg = 0x4f,       /* GP5 */
  86                .config_regs = {0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46},
  87                .base = 50,
  88        },
  89        {
  90                .data_reg = 0x50,       /* GP6 */
  91                .config_regs = {0x47, 0x48, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59},
  92                .base = 60,
  93        },
  94};
  95
  96/*
  97 *      Super-IO functions
  98 */
  99
 100static inline int sch311x_sio_enter(int sio_config_port)
 101{
 102        /* Don't step on other drivers' I/O space by accident. */
 103        if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
 104                pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
 105                       sio_config_port);
 106                return -EBUSY;
 107        }
 108
 109        outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
 110        return 0;
 111}
 112
 113static inline void sch311x_sio_exit(int sio_config_port)
 114{
 115        outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
 116        release_region(sio_config_port, 2);
 117}
 118
 119static inline int sch311x_sio_inb(int sio_config_port, int reg)
 120{
 121        outb(reg, sio_config_port);
 122        return inb(sio_config_port + 1);
 123}
 124
 125static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
 126{
 127        outb(reg, sio_config_port);
 128        outb(val, sio_config_port + 1);
 129}
 130
 131
 132/*
 133 *      GPIO functions
 134 */
 135
 136static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
 137{
 138        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 139
 140        if (block->config_regs[offset] == 0) /* GPIO is not available */
 141                return -ENODEV;
 142
 143        if (!request_region(block->runtime_reg + block->config_regs[offset],
 144                            1, DRV_NAME)) {
 145                dev_err(chip->parent, "Failed to request region 0x%04x.\n",
 146                        block->runtime_reg + block->config_regs[offset]);
 147                return -EBUSY;
 148        }
 149        return 0;
 150}
 151
 152static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
 153{
 154        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 155
 156        if (block->config_regs[offset] == 0) /* GPIO is not available */
 157                return;
 158
 159        release_region(block->runtime_reg + block->config_regs[offset], 1);
 160}
 161
 162static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
 163{
 164        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 165        u8 data;
 166
 167        spin_lock(&block->lock);
 168        data = inb(block->runtime_reg + block->data_reg);
 169        spin_unlock(&block->lock);
 170
 171        return !!(data & BIT(offset));
 172}
 173
 174static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
 175                               unsigned offset, int value)
 176{
 177        u8 data = inb(block->runtime_reg + block->data_reg);
 178        if (value)
 179                data |= BIT(offset);
 180        else
 181                data &= ~BIT(offset);
 182        outb(data, block->runtime_reg + block->data_reg);
 183}
 184
 185static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
 186                             int value)
 187{
 188        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 189
 190        spin_lock(&block->lock);
 191         __sch311x_gpio_set(block, offset, value);
 192        spin_unlock(&block->lock);
 193}
 194
 195static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 196{
 197        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 198        u8 data;
 199
 200        spin_lock(&block->lock);
 201        data = inb(block->runtime_reg + block->config_regs[offset]);
 202        data |= SCH311X_GPIO_CONF_DIR;
 203        outb(data, block->runtime_reg + block->config_regs[offset]);
 204        spin_unlock(&block->lock);
 205
 206        return 0;
 207}
 208
 209static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
 210                                      int value)
 211{
 212        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 213        u8 data;
 214
 215        spin_lock(&block->lock);
 216
 217        data = inb(block->runtime_reg + block->config_regs[offset]);
 218        data &= ~SCH311X_GPIO_CONF_DIR;
 219        outb(data, block->runtime_reg + block->config_regs[offset]);
 220        __sch311x_gpio_set(block, offset, value);
 221
 222        spin_unlock(&block->lock);
 223        return 0;
 224}
 225
 226static int sch311x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 227{
 228        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 229        u8 data;
 230
 231        spin_lock(&block->lock);
 232        data = inb(block->runtime_reg + block->config_regs[offset]);
 233        spin_unlock(&block->lock);
 234
 235        return !!(data & SCH311X_GPIO_CONF_DIR);
 236}
 237
 238static int sch311x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
 239                                   unsigned long config)
 240{
 241        struct sch311x_gpio_block *block = gpiochip_get_data(chip);
 242        enum pin_config_param param = pinconf_to_config_param(config);
 243        u8 data;
 244
 245        switch (param) {
 246        case PIN_CONFIG_DRIVE_OPEN_DRAIN:
 247                spin_lock(&block->lock);
 248                data = inb(block->runtime_reg + block->config_regs[offset]);
 249                data |= SCH311X_GPIO_CONF_OPEN_DRAIN;
 250                outb(data, block->runtime_reg + block->config_regs[offset]);
 251                spin_unlock(&block->lock);
 252                return 0;
 253        case PIN_CONFIG_DRIVE_PUSH_PULL:
 254                spin_lock(&block->lock);
 255                data = inb(block->runtime_reg + block->config_regs[offset]);
 256                data &= ~SCH311X_GPIO_CONF_OPEN_DRAIN;
 257                outb(data, block->runtime_reg + block->config_regs[offset]);
 258                spin_unlock(&block->lock);
 259                return 0;
 260        default:
 261                break;
 262        }
 263        return -ENOTSUPP;
 264}
 265
 266static int sch311x_gpio_probe(struct platform_device *pdev)
 267{
 268        struct sch311x_pdev_data *pdata = dev_get_platdata(&pdev->dev);
 269        struct sch311x_gpio_priv *priv;
 270        struct sch311x_gpio_block *block;
 271        int err, i;
 272
 273        /* we can register all GPIO data registers at once */
 274        if (!devm_request_region(&pdev->dev, pdata->runtime_reg + GP1, 6,
 275                DRV_NAME)) {
 276                dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
 277                        pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
 278                return -EBUSY;
 279        }
 280
 281        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 282        if (!priv)
 283                return -ENOMEM;
 284
 285        platform_set_drvdata(pdev, priv);
 286
 287        for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
 288                block = &priv->blocks[i];
 289
 290                spin_lock_init(&block->lock);
 291
 292                block->chip.label = DRV_NAME;
 293                block->chip.owner = THIS_MODULE;
 294                block->chip.request = sch311x_gpio_request;
 295                block->chip.free = sch311x_gpio_free;
 296                block->chip.direction_input = sch311x_gpio_direction_in;
 297                block->chip.direction_output = sch311x_gpio_direction_out;
 298                block->chip.get_direction = sch311x_gpio_get_direction;
 299                block->chip.set_config = sch311x_gpio_set_config;
 300                block->chip.get = sch311x_gpio_get;
 301                block->chip.set = sch311x_gpio_set;
 302                block->chip.ngpio = 8;
 303                block->chip.parent = &pdev->dev;
 304                block->chip.base = sch311x_gpio_blocks[i].base;
 305                block->config_regs = sch311x_gpio_blocks[i].config_regs;
 306                block->data_reg = sch311x_gpio_blocks[i].data_reg;
 307                block->runtime_reg = pdata->runtime_reg;
 308
 309                err = gpiochip_add_data(&block->chip, block);
 310                if (err < 0) {
 311                        dev_err(&pdev->dev,
 312                                "Could not register gpiochip, %d\n", err);
 313                        goto exit_err;
 314                }
 315                dev_info(&pdev->dev,
 316                         "SMSC SCH311x GPIO block %d registered.\n", i);
 317        }
 318
 319        return 0;
 320
 321exit_err:
 322        /* release already registered chips */
 323        for (--i; i >= 0; i--)
 324                gpiochip_remove(&priv->blocks[i].chip);
 325        return err;
 326}
 327
 328static int sch311x_gpio_remove(struct platform_device *pdev)
 329{
 330        struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
 331        int i;
 332
 333        for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
 334                gpiochip_remove(&priv->blocks[i].chip);
 335                dev_info(&pdev->dev,
 336                         "SMSC SCH311x GPIO block %d unregistered.\n", i);
 337        }
 338        return 0;
 339}
 340
 341static struct platform_driver sch311x_gpio_driver = {
 342        .driver.name    = DRV_NAME,
 343        .probe          = sch311x_gpio_probe,
 344        .remove         = sch311x_gpio_remove,
 345};
 346
 347
 348/*
 349 *      Init & exit routines
 350 */
 351
 352static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
 353{
 354        int err = 0, reg;
 355        unsigned short base_addr;
 356        u8 dev_id;
 357
 358        err = sch311x_sio_enter(sio_config_port);
 359        if (err)
 360                return err;
 361
 362        /* Check device ID. */
 363        reg = sch311x_sio_inb(sio_config_port, 0x20);
 364        switch (reg) {
 365        case 0x7c: /* SCH3112 */
 366                dev_id = 2;
 367                break;
 368        case 0x7d: /* SCH3114 */
 369                dev_id = 4;
 370                break;
 371        case 0x7f: /* SCH3116 */
 372                dev_id = 6;
 373                break;
 374        default:
 375                err = -ENODEV;
 376                goto exit;
 377        }
 378
 379        /* Select logical device A (runtime registers) */
 380        sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
 381
 382        /* Check if Logical Device Register is currently active */
 383        if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
 384                pr_info("Seems that LDN 0x0a is not active...\n");
 385
 386        /* Get the base address of the runtime registers */
 387        base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
 388                           sch311x_sio_inb(sio_config_port, 0x61);
 389        if (!base_addr) {
 390                pr_err("Base address not set\n");
 391                err = -ENODEV;
 392                goto exit;
 393        }
 394        *addr = base_addr;
 395
 396        pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
 397
 398exit:
 399        sch311x_sio_exit(sio_config_port);
 400        return err;
 401}
 402
 403static int __init sch311x_gpio_pdev_add(const unsigned short addr)
 404{
 405        struct sch311x_pdev_data pdata;
 406        int err;
 407
 408        pdata.runtime_reg = addr;
 409
 410        sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
 411        if (!sch311x_gpio_pdev)
 412                return -ENOMEM;
 413
 414        err = platform_device_add_data(sch311x_gpio_pdev,
 415                                       &pdata, sizeof(pdata));
 416        if (err) {
 417                pr_err(DRV_NAME "Platform data allocation failed\n");
 418                goto err;
 419        }
 420
 421        err = platform_device_add(sch311x_gpio_pdev);
 422        if (err) {
 423                pr_err(DRV_NAME "Device addition failed\n");
 424                goto err;
 425        }
 426        return 0;
 427
 428err:
 429        platform_device_put(sch311x_gpio_pdev);
 430        return err;
 431}
 432
 433static int __init sch311x_gpio_init(void)
 434{
 435        int err, i;
 436        unsigned short addr = 0;
 437
 438        for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
 439                if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
 440                        break;
 441
 442        if (!addr)
 443                return -ENODEV;
 444
 445        err = platform_driver_register(&sch311x_gpio_driver);
 446        if (err)
 447                return err;
 448
 449        err = sch311x_gpio_pdev_add(addr);
 450        if (err)
 451                goto unreg_platform_driver;
 452
 453        return 0;
 454
 455unreg_platform_driver:
 456        platform_driver_unregister(&sch311x_gpio_driver);
 457        return err;
 458}
 459
 460static void __exit sch311x_gpio_exit(void)
 461{
 462        platform_device_unregister(sch311x_gpio_pdev);
 463        platform_driver_unregister(&sch311x_gpio_driver);
 464}
 465
 466module_init(sch311x_gpio_init);
 467module_exit(sch311x_gpio_exit);
 468
 469MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
 470MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
 471MODULE_LICENSE("GPL");
 472MODULE_ALIAS("platform:gpio-sch311x");
 473