root/drivers/i2c/busses/i2c-pca-isa.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pca_isa_writebyte
  2. pca_isa_readbyte
  3. pca_isa_waitforcompletion
  4. pca_isa_resetchip
  5. pca_handler
  6. pca_isa_match
  7. pca_isa_probe
  8. pca_isa_remove

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

/* [<][>][^][v][top][bottom][index][help] */