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 DEFINE_SPINLOCK(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        if (!mmapped) {
 136                if (!request_region(base, 2, pcf_isa_ops.name)) {
 137                        printk(KERN_ERR "%s: requested I/O region (%#x:2) is "
 138                               "in use\n", pcf_isa_ops.name, base);
 139                        return -ENODEV;
 140                }
 141                base_iomem = ioport_map(base, 2);
 142                if (!base_iomem) {
 143                        printk(KERN_ERR "%s: remap of I/O region %#x failed\n",
 144                               pcf_isa_ops.name, base);
 145                        release_region(base, 2);
 146                        return -ENODEV;
 147                }
 148        } else {
 149                if (!request_mem_region(base, 2, pcf_isa_ops.name)) {
 150                        printk(KERN_ERR "%s: requested memory region (%#x:2) "
 151                               "is in use\n", pcf_isa_ops.name, base);
 152                        return -ENODEV;
 153                }
 154                base_iomem = ioremap(base, 2);
 155                if (base_iomem == NULL) {
 156                        printk(KERN_ERR "%s: remap of memory region %#x "
 157                               "failed\n", pcf_isa_ops.name, base);
 158                        release_mem_region(base, 2);
 159                        return -ENODEV;
 160                }
 161        }
 162        pr_debug("%s: registers %#x remapped to %p\n", pcf_isa_ops.name, base,
 163                 base_iomem);
 164
 165        if (irq > 0) {
 166                if (request_irq(irq, pcf_isa_handler, 0, pcf_isa_ops.name,
 167                                NULL) < 0) {
 168                        printk(KERN_ERR "%s: Request irq%d failed\n",
 169                               pcf_isa_ops.name, irq);
 170                        irq = 0;
 171                } else
 172                        enable_irq(irq);
 173        }
 174        return 0;
 175}
 176
 177/* ------------------------------------------------------------------------
 178 * Encapsulate the above functions in the correct operations structure.
 179 * This is only done when more than one hardware adapter is supported.
 180 */
 181static struct i2c_algo_pcf_data pcf_isa_data = {
 182        .setpcf     = pcf_isa_setbyte,
 183        .getpcf     = pcf_isa_getbyte,
 184        .getown     = pcf_isa_getown,
 185        .getclock   = pcf_isa_getclock,
 186        .waitforpin = pcf_isa_waitforpin,
 187};
 188
 189static struct i2c_adapter pcf_isa_ops = {
 190        .owner          = THIS_MODULE,
 191        .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
 192        .algo_data      = &pcf_isa_data,
 193        .name           = "i2c-elektor",
 194};
 195
 196static int elektor_match(struct device *dev, unsigned int id)
 197{
 198#ifdef __alpha__
 199        /* check to see we have memory mapped PCF8584 connected to the
 200        Cypress cy82c693 PCI-ISA bridge as on UP2000 board */
 201        if (base == 0) {
 202                struct pci_dev *cy693_dev;
 203
 204                cy693_dev = pci_get_device(PCI_VENDOR_ID_CONTAQ,
 205                                           PCI_DEVICE_ID_CONTAQ_82C693, NULL);
 206                if (cy693_dev) {
 207                        unsigned char config;
 208                        /* yeap, we've found cypress, let's check config */
 209                        if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
 210
 211                                dev_dbg(dev, "found cy82c693, config "
 212                                        "register 0x47 = 0x%02x\n", config);
 213
 214                                /* UP2000 board has this register set to 0xe1,
 215                                   but the most significant bit as seems can be
 216                                   reset during the proper initialisation
 217                                   sequence if guys from API decides to do that
 218                                   (so, we can even enable Tsunami Pchip
 219                                   window for the upper 1 Gb) */
 220
 221                                /* so just check for ROMCS at 0xe0000,
 222                                   ROMCS enabled for writes
 223                                   and external XD Bus buffer in use. */
 224                                if ((config & 0x7f) == 0x61) {
 225                                        /* seems to be UP2000 like board */
 226                                        base = 0xe0000;
 227                                        mmapped = 1;
 228                                        /* UP2000 drives ISA with
 229                                           8.25 MHz (PCI/4) clock
 230                                           (this can be read from cypress) */
 231                                        clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
 232                                        dev_info(dev, "found API UP2000 like "
 233                                                 "board, will probe PCF8584 "
 234                                                 "later\n");
 235                                }
 236                        }
 237                        pci_dev_put(cy693_dev);
 238                }
 239        }
 240#endif
 241
 242        /* sanity checks for mmapped I/O */
 243        if (mmapped && base < 0xc8000) {
 244                dev_err(dev, "incorrect base address (%#x) specified "
 245                       "for mmapped I/O\n", base);
 246                return 0;
 247        }
 248
 249        if (base == 0) {
 250                base = DEFAULT_BASE;
 251        }
 252        return 1;
 253}
 254
 255static int elektor_probe(struct device *dev, unsigned int id)
 256{
 257        init_waitqueue_head(&pcf_wait);
 258        if (pcf_isa_init())
 259                return -ENODEV;
 260        pcf_isa_ops.dev.parent = dev;
 261        if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
 262                goto fail;
 263
 264        dev_info(dev, "found device at %#x\n", base);
 265
 266        return 0;
 267
 268 fail:
 269        if (irq > 0) {
 270                disable_irq(irq);
 271                free_irq(irq, NULL);
 272        }
 273
 274        if (!mmapped) {
 275                ioport_unmap(base_iomem);
 276                release_region(base, 2);
 277        } else {
 278                iounmap(base_iomem);
 279                release_mem_region(base, 2);
 280        }
 281        return -ENODEV;
 282}
 283
 284static void elektor_remove(struct device *dev, unsigned int id)
 285{
 286        i2c_del_adapter(&pcf_isa_ops);
 287
 288        if (irq > 0) {
 289                disable_irq(irq);
 290                free_irq(irq, NULL);
 291        }
 292
 293        if (!mmapped) {
 294                ioport_unmap(base_iomem);
 295                release_region(base, 2);
 296        } else {
 297                iounmap(base_iomem);
 298                release_mem_region(base, 2);
 299        }
 300}
 301
 302static struct isa_driver i2c_elektor_driver = {
 303        .match          = elektor_match,
 304        .probe          = elektor_probe,
 305        .remove         = elektor_remove,
 306        .driver = {
 307                .owner  = THIS_MODULE,
 308                .name   = "i2c-elektor",
 309        },
 310};
 311
 312MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
 313MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
 314MODULE_LICENSE("GPL");
 315
 316module_param_hw(base, int, ioport_or_iomem, 0);
 317module_param_hw(irq, int, irq, 0);
 318module_param(clock, int, 0);
 319module_param(own, int, 0);
 320module_param_hw(mmapped, int, other, 0);
 321module_isa_driver(i2c_elektor_driver, 1);
 322
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.