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/module.h>
  16#include <linux/kernel.h>
  17#include <linux/init.h>
  18#include <linux/platform_device.h>
  19#include <linux/gpio.h>
  20#include <linux/bitops.h>
  21#include <linux/io.h>
  22
  23#define DRV_NAME                        "gpio-sch311x"
  24
  25#define SCH311X_GPIO_CONF_OUT           0x00
  26#define SCH311X_GPIO_CONF_IN            0x01
  27#define SCH311X_GPIO_CONF_INVERT        0x02
  28#define SCH311X_GPIO_CONF_OPEN_DRAIN    0x80
  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
  96static inline struct sch311x_gpio_block *
  97to_sch311x_gpio_block(struct gpio_chip *chip)
  98{
  99        return container_of(chip, struct sch311x_gpio_block, chip);
 100}
 101
 102
 103/*
 104 *      Super-IO functions
 105 */
 106
 107static inline int sch311x_sio_enter(int sio_config_port)
 108{
 109        /* Don't step on other drivers' I/O space by accident. */
 110        if (!request_muxed_region(sio_config_port, 2, DRV_NAME)) {
 111                pr_err(DRV_NAME "I/O address 0x%04x already in use\n",
 112                       sio_config_port);
 113                return -EBUSY;
 114        }
 115
 116        outb(SIO_CONFIG_KEY_ENTER, sio_config_port);
 117        return 0;
 118}
 119
 120static inline void sch311x_sio_exit(int sio_config_port)
 121{
 122        outb(SIO_CONFIG_KEY_EXIT, sio_config_port);
 123        release_region(sio_config_port, 2);
 124}
 125
 126static inline int sch311x_sio_inb(int sio_config_port, int reg)
 127{
 128        outb(reg, sio_config_port);
 129        return inb(sio_config_port + 1);
 130}
 131
 132static inline void sch311x_sio_outb(int sio_config_port, int reg, int val)
 133{
 134        outb(reg, sio_config_port);
 135        outb(val, sio_config_port + 1);
 136}
 137
 138
 139/*
 140 *      GPIO functions
 141 */
 142
 143static int sch311x_gpio_request(struct gpio_chip *chip, unsigned offset)
 144{
 145        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 146
 147        if (block->config_regs[offset] == 0) /* GPIO is not available */
 148                return -ENODEV;
 149
 150        if (!request_region(block->runtime_reg + block->config_regs[offset],
 151                            1, DRV_NAME)) {
 152                dev_err(chip->dev, "Failed to request region 0x%04x.\n",
 153                        block->runtime_reg + block->config_regs[offset]);
 154                return -EBUSY;
 155        }
 156        return 0;
 157}
 158
 159static void sch311x_gpio_free(struct gpio_chip *chip, unsigned offset)
 160{
 161        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 162
 163        if (block->config_regs[offset] == 0) /* GPIO is not available */
 164                return;
 165
 166        release_region(block->runtime_reg + block->config_regs[offset], 1);
 167}
 168
 169static int sch311x_gpio_get(struct gpio_chip *chip, unsigned offset)
 170{
 171        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 172        unsigned char data;
 173
 174        spin_lock(&block->lock);
 175        data = inb(block->runtime_reg + block->data_reg);
 176        spin_unlock(&block->lock);
 177
 178        return !!(data & BIT(offset));
 179}
 180
 181static void __sch311x_gpio_set(struct sch311x_gpio_block *block,
 182                               unsigned offset, int value)
 183{
 184        unsigned char data = inb(block->runtime_reg + block->data_reg);
 185        if (value)
 186                data |= BIT(offset);
 187        else
 188                data &= ~BIT(offset);
 189        outb(data, block->runtime_reg + block->data_reg);
 190}
 191
 192static void sch311x_gpio_set(struct gpio_chip *chip, unsigned offset,
 193                             int value)
 194{
 195        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 196
 197        spin_lock(&block->lock);
 198         __sch311x_gpio_set(block, offset, value);
 199        spin_unlock(&block->lock);
 200}
 201
 202static int sch311x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 203{
 204        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 205
 206        spin_lock(&block->lock);
 207        outb(SCH311X_GPIO_CONF_IN, block->runtime_reg +
 208             block->config_regs[offset]);
 209        spin_unlock(&block->lock);
 210
 211        return 0;
 212}
 213
 214static int sch311x_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
 215                                      int value)
 216{
 217        struct sch311x_gpio_block *block = to_sch311x_gpio_block(chip);
 218
 219        spin_lock(&block->lock);
 220
 221        outb(SCH311X_GPIO_CONF_OUT, block->runtime_reg +
 222             block->config_regs[offset]);
 223
 224        __sch311x_gpio_set(block, offset, value);
 225
 226        spin_unlock(&block->lock);
 227        return 0;
 228}
 229
 230static int sch311x_gpio_probe(struct platform_device *pdev)
 231{
 232        struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
 233        struct sch311x_gpio_priv *priv;
 234        struct sch311x_gpio_block *block;
 235        int err, i;
 236
 237        /* we can register all GPIO data registers at once */
 238        if (!request_region(pdata->runtime_reg + GP1, 6, DRV_NAME)) {
 239                dev_err(&pdev->dev, "Failed to request region 0x%04x-0x%04x.\n",
 240                        pdata->runtime_reg + GP1, pdata->runtime_reg + GP1 + 5);
 241                return -EBUSY;
 242        }
 243
 244        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 245        if (!priv)
 246                return -ENOMEM;
 247
 248        platform_set_drvdata(pdev, priv);
 249
 250        for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
 251                block = &priv->blocks[i];
 252
 253                spin_lock_init(&block->lock);
 254
 255                block->chip.label = DRV_NAME;
 256                block->chip.owner = THIS_MODULE;
 257                block->chip.request = sch311x_gpio_request;
 258                block->chip.free = sch311x_gpio_free;
 259                block->chip.direction_input = sch311x_gpio_direction_in;
 260                block->chip.direction_output = sch311x_gpio_direction_out;
 261                block->chip.get = sch311x_gpio_get;
 262                block->chip.set = sch311x_gpio_set;
 263                block->chip.ngpio = 8;
 264                block->chip.dev = &pdev->dev;
 265                block->chip.base = sch311x_gpio_blocks[i].base;
 266                block->config_regs = sch311x_gpio_blocks[i].config_regs;
 267                block->data_reg = sch311x_gpio_blocks[i].data_reg;
 268                block->runtime_reg = pdata->runtime_reg;
 269
 270                err = gpiochip_add(&block->chip);
 271                if (err < 0) {
 272                        dev_err(&pdev->dev,
 273                                "Could not register gpiochip, %d\n", err);
 274                        goto exit_err;
 275                }
 276                dev_info(&pdev->dev,
 277                         "SMSC SCH311x GPIO block %d registered.\n", i);
 278        }
 279
 280        return 0;
 281
 282exit_err:
 283        release_region(pdata->runtime_reg + GP1, 6);
 284        /* release already registered chips */
 285        for (--i; i >= 0; i--)
 286                gpiochip_remove(&priv->blocks[i].chip);
 287        return err;
 288}
 289
 290static int sch311x_gpio_remove(struct platform_device *pdev)
 291{
 292        struct sch311x_pdev_data *pdata = pdev->dev.platform_data;
 293        struct sch311x_gpio_priv *priv = platform_get_drvdata(pdev);
 294        int i;
 295
 296        release_region(pdata->runtime_reg + GP1, 6);
 297
 298        for (i = 0; i < ARRAY_SIZE(priv->blocks); i++) {
 299                gpiochip_remove(&priv->blocks[i].chip);
 300                dev_info(&pdev->dev,
 301                         "SMSC SCH311x GPIO block %d unregistered.\n", i);
 302        }
 303        return 0;
 304}
 305
 306static struct platform_driver sch311x_gpio_driver = {
 307        .driver.name    = DRV_NAME,
 308        .driver.owner   = THIS_MODULE,
 309        .probe          = sch311x_gpio_probe,
 310        .remove         = sch311x_gpio_remove,
 311};
 312
 313
 314/*
 315 *      Init & exit routines
 316 */
 317
 318static int __init sch311x_detect(int sio_config_port, unsigned short *addr)
 319{
 320        int err = 0, reg;
 321        unsigned short base_addr;
 322        unsigned char dev_id;
 323
 324        err = sch311x_sio_enter(sio_config_port);
 325        if (err)
 326                return err;
 327
 328        /* Check device ID. */
 329        reg = sch311x_sio_inb(sio_config_port, 0x20);
 330        switch (reg) {
 331        case 0x7c: /* SCH3112 */
 332                dev_id = 2;
 333                break;
 334        case 0x7d: /* SCH3114 */
 335                dev_id = 4;
 336                break;
 337        case 0x7f: /* SCH3116 */
 338                dev_id = 6;
 339                break;
 340        default:
 341                err = -ENODEV;
 342                goto exit;
 343        }
 344
 345        /* Select logical device A (runtime registers) */
 346        sch311x_sio_outb(sio_config_port, 0x07, 0x0a);
 347
 348        /* Check if Logical Device Register is currently active */
 349        if ((sch311x_sio_inb(sio_config_port, 0x30) & 0x01) == 0)
 350                pr_info("Seems that LDN 0x0a is not active...\n");
 351
 352        /* Get the base address of the runtime registers */
 353        base_addr = (sch311x_sio_inb(sio_config_port, 0x60) << 8) |
 354                           sch311x_sio_inb(sio_config_port, 0x61);
 355        if (!base_addr) {
 356                pr_err("Base address not set\n");
 357                err = -ENODEV;
 358                goto exit;
 359        }
 360        *addr = base_addr;
 361
 362        pr_info("Found an SMSC SCH311%d chip at 0x%04x\n", dev_id, base_addr);
 363
 364exit:
 365        sch311x_sio_exit(sio_config_port);
 366        return err;
 367}
 368
 369static int __init sch311x_gpio_pdev_add(const unsigned short addr)
 370{
 371        struct sch311x_pdev_data pdata;
 372        int err;
 373
 374        pdata.runtime_reg = addr;
 375
 376        sch311x_gpio_pdev = platform_device_alloc(DRV_NAME, -1);
 377        if (!sch311x_gpio_pdev)
 378                return -ENOMEM;
 379
 380        err = platform_device_add_data(sch311x_gpio_pdev,
 381                                       &pdata, sizeof(pdata));
 382        if (err) {
 383                pr_err(DRV_NAME "Platform data allocation failed\n");
 384                goto err;
 385        }
 386
 387        err = platform_device_add(sch311x_gpio_pdev);
 388        if (err) {
 389                pr_err(DRV_NAME "Device addition failed\n");
 390                goto err;
 391        }
 392        return 0;
 393
 394err:
 395        platform_device_put(sch311x_gpio_pdev);
 396        return err;
 397}
 398
 399static int __init sch311x_gpio_init(void)
 400{
 401        int err, i;
 402        unsigned short addr = 0;
 403
 404        for (i = 0; i < ARRAY_SIZE(sch311x_ioports); i++)
 405                if (sch311x_detect(sch311x_ioports[i], &addr) == 0)
 406                        break;
 407
 408        if (!addr)
 409                return -ENODEV;
 410
 411        err = platform_driver_register(&sch311x_gpio_driver);
 412        if (err)
 413                return err;
 414
 415        err = sch311x_gpio_pdev_add(addr);
 416        if (err)
 417                goto unreg_platform_driver;
 418
 419        return 0;
 420
 421unreg_platform_driver:
 422        platform_driver_unregister(&sch311x_gpio_driver);
 423        return err;
 424}
 425
 426static void __exit sch311x_gpio_exit(void)
 427{
 428        platform_device_unregister(sch311x_gpio_pdev);
 429        platform_driver_unregister(&sch311x_gpio_driver);
 430}
 431
 432module_init(sch311x_gpio_init);
 433module_exit(sch311x_gpio_exit);
 434
 435MODULE_AUTHOR("Bruno Randolf <br1@einfach.org>");
 436MODULE_DESCRIPTION("SMSC SCH311x GPIO Driver");
 437MODULE_LICENSE("GPL");
 438MODULE_ALIAS("platform:gpio-sch311x");
 439