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