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