linux/drivers/i2c/busses/i2c-elektor.c
<<
>>
Prefs
   1/* ------------------------------------------------------------------------- */
   2/* i2c-elektor.c i2c-hw access for PCF8584 style isa bus adaptes             */
   3/* ------------------------------------------------------------------------- */
   4/*   Copyright (C) 1995-97 Simon G. Vogl
   5                   1998-99 Hans Berglund
   6
   7    This program is free software; you can redistribute it and/or modify
   8    it under the terms of the GNU General Public License as published by
   9    the Free Software Foundation; either version 2 of the License, or
  10    (at your option) any later version.
  11
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15    GNU General Public License for more details.                             */
  16/* ------------------------------------------------------------------------- */
  17
  18/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
  19   Frodo Looijaard <frodol@dds.nl> */
  20
  21/* Partially rewriten by Oleg I. Vdovikin for mmapped support of
  22   for Alpha Processor Inc. UP-2000(+) boards */
  23
  24#include <linux/kernel.h>
  25#include <linux/ioport.h>
  26#include <linux/module.h>
  27#include <linux/delay.h>
  28#include <linux/init.h>
  29#include <linux/interrupt.h>
  30#include <linux/pci.h>
  31#include <linux/wait.h>
  32
  33#include <linux/isa.h>
  34#include <linux/i2c.h>
  35#include <linux/i2c-algo-pcf.h>
  36#include <linux/io.h>
  37
  38#include <asm/irq.h>
  39
  40#include "../algos/i2c-algo-pcf.h"
  41
  42#define DEFAULT_BASE 0x330
  43
  44static int base;
  45static u8 __iomem *base_iomem;
  46
  47static int irq;
  48static int clock  = 0x1c;
  49static int own    = 0x55;
  50static int mmapped;
  51
  52/* vdovikin: removed static struct i2c_pcf_isa gpi; code -
  53  this module in real supports only one device, due to missing arguments
  54  in some functions, called from the algo-pcf module. Sometimes it's
  55  need to be rewriten - but for now just remove this for simpler reading */
  56
  57static wait_queue_head_t pcf_wait;
  58static int pcf_pending;
  59static spinlock_t lock;
  60
  61static struct i2c_adapter pcf_isa_ops;
  62
  63/* ----- local functions ---------------------------------------------- */
  64
  65static void pcf_isa_setbyte(void *data, int ctl, int val)
  66{
  67        u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
  68
  69        /* enable irq if any specified for serial operation */
  70        if (ctl && irq && (val & I2C_PCF_ESO)) {
  71                val |= I2C_PCF_ENI;
  72        }
  73
  74        pr_debug("%s: Write %p 0x%02X\n", pcf_isa_ops.name, address, val);
  75        iowrite8(val, address);
  76#ifdef __alpha__
  77        /* API UP2000 needs some hardware fudging to make the write stick */
  78        iowrite8(val, address);
  79#endif
  80}
  81
  82static int pcf_isa_getbyte(void *data, int ctl)
  83{
  84        u8 __iomem *address = ctl ? (base_iomem + 1) : base_iomem;
  85        int val = ioread8(address);
  86
  87        pr_debug("%s: Read %p 0x%02X\n", pcf_isa_ops.name, address, val);
  88        return (val);
  89}
  90
  91static int pcf_isa_getown(void *data)
  92{
  93        return (own);
  94}
  95
  96
  97static int pcf_isa_getclock(void *data)
  98{
  99        return (clock);
 100}
 101
 102static void pcf_isa_waitforpin(void *data)
 103{
 104        DEFINE_WAIT(wait);
 105        int timeout = 2;
 106        unsigned long flags;
 107
 108        if (irq > 0) {
 109                spin_lock_irqsave(&lock, flags);
 110                if (pcf_pending == 0) {
 111                        spin_unlock_irqrestore(&lock, flags);
 112                        prepare_to_wait(&pcf_wait, &wait, TASK_INTERRUPTIBLE);
 113                        if (schedule_timeout(timeout*HZ)) {
 114                                spin_lock_irqsave(&lock, flags);
 115                                if (pcf_pending == 1) {
 116                                        pcf_pending = 0;
 117                                }
 118                                spin_unlock_irqrestore(&lock, flags);
 119                        }
 120                        finish_wait(&pcf_wait, &wait);
 121                } else {
 122                        pcf_pending = 0;
 123                        spin_unlock_irqrestore(&lock, flags);
 124                }
 125        } else {
 126                udelay(100);
 127        }
 128}
 129
 130
 131static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
 132        spin_lock(&lock);
 133        pcf_pending = 1;
 134        spin_unlock(&lock);
 135        wake_up_interruptible(&pcf_wait);
 136        return IRQ_HANDLED;
 137}
 138
 139
 140static int pcf_isa_init(void)
 141{
 142        spin_lock_init(&lock);
 143        if (!mmapped) {
 144                if (!request_region(base, 2, pcf_isa_ops.name)) {
 145                        printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
 146                               "in use\n", pcf_isa_ops.name, base);
 147                        return -ENODEV;
 148                }
 149                base_iomem = ioport_map(base, 2);
 150                if (!base_iomem) {
 151                        printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
 152                               pcf_isa_ops.name, base);
 153                        release_region(base, 2);
 154                        return -ENODEV;
 155                }
 156        } else {
 157                if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
 158                        printk(KERN_ERR "%s: requested memory region (%#x:2) "
 159                               "is in use\n", pcf_isa_ops.name, base);
 160                        return -ENODEV;
 161                }
 162                base_iomem = ioremap(base, 2);
 163                if (base_iomem == NULL) {
 164                        printk(KERN_ERR "%s: remap of memory region %#x "
 165                               "failed\n", pcf_isa_ops.name, base);
 166                        release_mem_region(base, 2);
 167                        return -ENODEV;
 168                }
 169        }
 170        pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
 171                 base_iomem);
 172
 173        if (irq > 0) {
 174                if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
 175                                NULL) < 0) {
 176                        printk(KERN_ERR "%s: Request irq%d failed\n",
 177                               pcf_isa_ops.name, irq);
 178                        irq = 0;
 179                } else
 180                        enable_irq(irq);
 181        }
 182        return 0;
 183}
 184
 185/* ------------------------------------------------------------------------
 186 * Encapsulate the above functions in the correct operations structure.
 187 * This is only done when more than one hardware adapter is supported.
 188 */
 189static struct i2c_algo_pcf_data pcf_isa_data = {
 190        .setpcf     = pcf_isa_setbyte,
 191        .getpcf     = pcf_isa_getbyte,
 192        .getown     = pcf_isa_getown,
 193        .getclock   = pcf_isa_getclock,
 194        .waitforpin = pcf_isa_waitforpin,
 195};
 196
 197static struct i2c_adapter pcf_isa_ops = {
 198        .owner          = THIS_MODULE,
 199        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 200        .algo_data      = &pcf_isa_data,
 201        .name           = "i2c-elektor",
 202};
 203
 204static int elektor_match(struct device *dev, unsigned int id)
 205{
 206#ifdef __alpha__
 207        /* check to see we have memory mapped PCF8584 connected to the
 208        Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
 209        if (base == 0) {
 210                struct pci_dev *cy693_dev;
 211
 212                cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
 213                                           PCI_DEVICE_ID_CONTAQ_82C693, NULL);
 214                if (cy693_dev) {
 215                        unsigned char config;
 216                        /* yeap, we've found cypress, let's check config */
 217                        if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
 218
 219                                dev_dbg(dev, "found cy82c693, config "
 220                                        "register 0x47 = 0x%02x\n", config);
 221
 222                                /* UP2000 board has this register set to 0xe1,
 223                                   but the most significant bit as seems can be
 224                                   reset during the proper initialisation
 225                                   sequence if guys from API decides to do that
 226                                   (so, we can even enable Tsunami Pchip
 227                                   window for the upper 1 Gb) */
 228
 229                                /* so just check for ROMCS at 0xe0000,
 230                                   ROMCS enabled for writes
 231                                   and external XD Bus buffer in use. */
 232                                if ((config & 0x7f) == 0x61) {
 233                                        /* seems to be UP2000 like board */
 234                                        base = 0xe0000;
 235                                        mmapped = 1;
 236                                        /* UP2000 drives ISA with
 237                                           8.25 MHz (PCI/4) clock
 238                                           (this can be read from cypress) */
 239                                        clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
 240                                        dev_info(dev, "found API UP2000 like "
 241                                                 "board, will probe PCF8584 "
 242                                                 "later\n");
 243                                }
 244                        }
 245                        pci_dev_put(cy693_dev);
 246                }
 247        }
 248#endif
 249
 250        /* sanity checks for mmapped I/O */
 251        if (mmapped && base < 0xc8000) {
 252                dev_err(dev, "incorrect base address (%#x) specified "
 253                       "for mmapped I/O\n", base);
 254                return 0;
 255        }
 256
 257        if (base == 0) {
 258                base = DEFAULT_BASE;
 259        }
 260        return 1;
 261}
 262
 263static int elektor_probe(struct device *dev, unsigned int id)
 264{
 265        init_waitqueue_head(&pcf_wait);
 266        if (pcf_isa_init())
 267                return -ENODEV;
 268        pcf_isa_ops.dev.parent = dev;
 269        if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
 270                goto fail;
 271
 272        dev_info(dev, "found device at %#x\n", base);
 273
 274        return 0;
 275
 276 fail:
 277        if (irq > 0) {
 278                disable_irq(irq);
 279                free_irq(irq, NULL);
 280        }
 281
 282        if (!mmapped) {
 283                ioport_unmap(base_iomem);
 284                release_region(base, 2);
 285        } else {
 286                iounmap(base_iomem);
 287                release_mem_region(base, 2);
 288        }
 289        return -ENODEV;
 290}
 291
 292static int elektor_remove(struct device *dev, unsigned int id)
 293{
 294        i2c_del_adapter(&pcf_isa_ops);
 295
 296        if (irq > 0) {
 297                disable_irq(irq);
 298                free_irq(irq, NULL);
 299        }
 300
 301        if (!mmapped) {
 302                ioport_unmap(base_iomem);
 303                release_region(base, 2);
 304        } else {
 305                iounmap(base_iomem);
 306                release_mem_region(base, 2);
 307        }
 308
 309        return 0;
 310}
 311
 312static struct isa_driver i2c_elektor_driver = {
 313        .match          = elektor_match,
 314        .probe          = elektor_probe,
 315        .remove         = elektor_remove,
 316        .driver = {
 317                .owner  = THIS_MODULE,
 318                .name   = "i2c-elektor",
 319        },
 320};
 321
 322MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
 323MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
 324MODULE_LICENSE("GPL");
 325
 326module_param_hw(base, int, ioport_or_iomem, 0);
 327module_param_hw(irq, int, irq, 0);
 328module_param(clock, int, 0);
 329module_param(own, int, 0);
 330module_param_hw(mmapped, int, other, 0);
 331module_isa_driver(i2c_elektor_driver, 1);
 332