linux/drivers/i2c/busses/i2c-pca-isa.c
<<
>>
Prefs
   1/*
   2 *  i2c-pca-isa.c driver for PCA9564 on ISA boards
   3 *    Copyright (C) 2004 Arcom Control Systems
   4 *    Copyright (C) 2008 Pengutronix
   5 *
   6 *  This program is free software; you can redistribute it and/or modify
   7 *  it under the terms of the GNU General Public License as published by
   8 *  the Free Software Foundation; either version 2 of the License, or
   9 *  (at your option) any later version.
  10 *
  11 *  This program is distributed in the hope that it will be useful,
  12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *  GNU General Public License for more details.
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/ioport.h>
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/delay.h>
  22#include <linux/jiffies.h>
  23#include <linux/init.h>
  24#include <linux/interrupt.h>
  25#include <linux/wait.h>
  26#include <linux/isa.h>
  27#include <linux/i2c.h>
  28#include <linux/i2c-algo-pca.h>
  29#include <linux/io.h>
  30
  31#include <asm/irq.h>
  32
  33#define DRIVER "i2c-pca-isa"
  34#define IO_SIZE 4
  35
  36static unsigned long base;
  37static int irq = -1;
  38
  39/* Data sheet recommends 59kHz for 100kHz operation due to variation
  40 * in the actual clock rate */
  41static int clock  = 59000;
  42
  43static struct i2c_adapter pca_isa_ops;
  44static wait_queue_head_t pca_wait;
  45
  46static void pca_isa_writebyte(void *pd, int reg, int val)
  47{
  48#ifdef DEBUG_IO
  49        static char *names[] = { "T/O", "DAT", "ADR", "CON" };
  50        printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],
  51               base+reg, val);
  52#endif
  53        outb(val, base+reg);
  54}
  55
  56static int pca_isa_readbyte(void *pd, int reg)
  57{
  58        int res = inb(base+reg);
  59#ifdef DEBUG_IO
  60        {
  61                static char *names[] = { "STA", "DAT", "ADR", "CON" };
  62                printk(KERN_DEBUG "*** read  %s => %#04x\n", names[reg], res);
  63        }
  64#endif
  65        return res;
  66}
  67
  68static int pca_isa_waitforcompletion(void *pd)
  69{
  70        unsigned long timeout;
  71        long ret;
  72
  73        if (irq > -1) {
  74                ret = wait_event_timeout(pca_wait,
  75                                pca_isa_readbyte(pd, I2C_PCA_CON)
  76                                & I2C_PCA_CON_SI, pca_isa_ops.timeout);
  77        } else {
  78                /* Do polling */
  79                timeout = jiffies + pca_isa_ops.timeout;
  80                do {
  81                        ret = time_before(jiffies, timeout);
  82                        if (pca_isa_readbyte(pd, I2C_PCA_CON)
  83                                        & I2C_PCA_CON_SI)
  84                                break;
  85                        udelay(100);
  86                } while (ret);
  87        }
  88
  89        return ret > 0;
  90}
  91
  92static void pca_isa_resetchip(void *pd)
  93{
  94        /* apparently only an external reset will do it. not a lot can be done */
  95        printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
  96}
  97
  98static irqreturn_t pca_handler(int this_irq, void *dev_id) {
  99        wake_up(&pca_wait);
 100        return IRQ_HANDLED;
 101}
 102
 103static struct i2c_algo_pca_data pca_isa_data = {
 104        /* .data intentionally left NULL, not needed with ISA */
 105        .write_byte             = pca_isa_writebyte,
 106        .read_byte              = pca_isa_readbyte,
 107        .wait_for_completion    = pca_isa_waitforcompletion,
 108        .reset_chip             = pca_isa_resetchip,
 109};
 110
 111static struct i2c_adapter pca_isa_ops = {
 112        .owner          = THIS_MODULE,
 113        .algo_data      = &pca_isa_data,
 114        .name           = "PCA9564/PCA9665 ISA Adapter",
 115        .timeout        = HZ,
 116};
 117
 118static int pca_isa_match(struct device *dev, unsigned int id)
 119{
 120        int match = base != 0;
 121
 122        if (match) {
 123                if (irq <= -1)
 124                        dev_warn(dev, "Using polling mode (specify irq)\n");
 125        } else
 126                dev_err(dev, "Please specify I/O base\n");
 127
 128        return match;
 129}
 130
 131static int pca_isa_probe(struct device *dev, unsigned int id)
 132{
 133        init_waitqueue_head(&pca_wait);
 134
 135        dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
 136
 137#ifdef CONFIG_PPC
 138        if (check_legacy_ioport(base)) {
 139                dev_err(dev, "I/O address %#08lx is not available\n", base);
 140                goto out;
 141        }
 142#endif
 143
 144        if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
 145                dev_err(dev, "I/O address %#08lx is in use\n", base);
 146                goto out;
 147        }
 148
 149        if (irq > -1) {
 150                if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
 151                        dev_err(dev, "Request irq%d failed\n", irq);
 152                        goto out_region;
 153                }
 154        }
 155
 156        pca_isa_data.i2c_clock = clock;
 157        if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
 158                dev_err(dev, "Failed to add i2c bus\n");
 159                goto out_irq;
 160        }
 161
 162        return 0;
 163
 164 out_irq:
 165        if (irq > -1)
 166                free_irq(irq, &pca_isa_ops);
 167 out_region:
 168        release_region(base, IO_SIZE);
 169 out:
 170        return -ENODEV;
 171}
 172
 173static int pca_isa_remove(struct device *dev, unsigned int id)
 174{
 175        i2c_del_adapter(&pca_isa_ops);
 176
 177        if (irq > -1) {
 178                disable_irq(irq);
 179                free_irq(irq, &pca_isa_ops);
 180        }
 181        release_region(base, IO_SIZE);
 182
 183        return 0;
 184}
 185
 186static struct isa_driver pca_isa_driver = {
 187        .match          = pca_isa_match,
 188        .probe          = pca_isa_probe,
 189        .remove         = pca_isa_remove,
 190        .driver = {
 191                .owner  = THIS_MODULE,
 192                .name   = DRIVER,
 193        }
 194};
 195
 196MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
 197MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
 198MODULE_LICENSE("GPL");
 199
 200module_param_hw(base, ulong, ioport, 0);
 201MODULE_PARM_DESC(base, "I/O base address");
 202module_param_hw(irq, int, irq, 0);
 203MODULE_PARM_DESC(irq, "IRQ");
 204module_param(clock, int, 0);
 205MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
 206                "For PCA9564: 330000,288000,217000,146000,"
 207                "88000,59000,44000,36000\n"
 208                "\t\tFor PCA9665:\tStandard: 60300 - 100099\n"
 209                "\t\t\t\tFast: 100100 - 400099\n"
 210                "\t\t\t\tFast+: 400100 - 10000099\n"
 211                "\t\t\t\tTurbo: Up to 1265800");
 212module_isa_driver(pca_isa_driver, 1);
 213