Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  i2c-pca-isa.c driver for PCA9564 on ISA boards
0004  *    Copyright (C) 2004 Arcom Control Systems
0005  *    Copyright (C) 2008 Pengutronix
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/ioport.h>
0010 #include <linux/module.h>
0011 #include <linux/moduleparam.h>
0012 #include <linux/delay.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/init.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/wait.h>
0017 #include <linux/isa.h>
0018 #include <linux/i2c.h>
0019 #include <linux/i2c-algo-pca.h>
0020 #include <linux/io.h>
0021 
0022 #include <asm/irq.h>
0023 
0024 #define DRIVER "i2c-pca-isa"
0025 #define IO_SIZE 4
0026 
0027 static unsigned long base;
0028 static int irq = -1;
0029 
0030 /* Data sheet recommends 59kHz for 100kHz operation due to variation
0031  * in the actual clock rate */
0032 static int clock  = 59000;
0033 
0034 static struct i2c_adapter pca_isa_ops;
0035 static wait_queue_head_t pca_wait;
0036 
0037 static void pca_isa_writebyte(void *pd, int reg, int val)
0038 {
0039 #ifdef DEBUG_IO
0040     static char *names[] = { "T/O", "DAT", "ADR", "CON" };
0041     printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],
0042            base+reg, val);
0043 #endif
0044     outb(val, base+reg);
0045 }
0046 
0047 static int pca_isa_readbyte(void *pd, int reg)
0048 {
0049     int res = inb(base+reg);
0050 #ifdef DEBUG_IO
0051     {
0052         static char *names[] = { "STA", "DAT", "ADR", "CON" };
0053         printk(KERN_DEBUG "*** read  %s => %#04x\n", names[reg], res);
0054     }
0055 #endif
0056     return res;
0057 }
0058 
0059 static int pca_isa_waitforcompletion(void *pd)
0060 {
0061     unsigned long timeout;
0062     long ret;
0063 
0064     if (irq > -1) {
0065         ret = wait_event_timeout(pca_wait,
0066                 pca_isa_readbyte(pd, I2C_PCA_CON)
0067                 & I2C_PCA_CON_SI, pca_isa_ops.timeout);
0068     } else {
0069         /* Do polling */
0070         timeout = jiffies + pca_isa_ops.timeout;
0071         do {
0072             ret = time_before(jiffies, timeout);
0073             if (pca_isa_readbyte(pd, I2C_PCA_CON)
0074                     & I2C_PCA_CON_SI)
0075                 break;
0076             udelay(100);
0077         } while (ret);
0078     }
0079 
0080     return ret > 0;
0081 }
0082 
0083 static void pca_isa_resetchip(void *pd)
0084 {
0085     /* apparently only an external reset will do it. not a lot can be done */
0086     printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");
0087 }
0088 
0089 static irqreturn_t pca_handler(int this_irq, void *dev_id) {
0090     wake_up(&pca_wait);
0091     return IRQ_HANDLED;
0092 }
0093 
0094 static struct i2c_algo_pca_data pca_isa_data = {
0095     /* .data intentionally left NULL, not needed with ISA */
0096     .write_byte     = pca_isa_writebyte,
0097     .read_byte      = pca_isa_readbyte,
0098     .wait_for_completion    = pca_isa_waitforcompletion,
0099     .reset_chip     = pca_isa_resetchip,
0100 };
0101 
0102 static struct i2c_adapter pca_isa_ops = {
0103     .owner          = THIS_MODULE,
0104     .algo_data  = &pca_isa_data,
0105     .name       = "PCA9564/PCA9665 ISA Adapter",
0106     .timeout    = HZ,
0107 };
0108 
0109 static int pca_isa_match(struct device *dev, unsigned int id)
0110 {
0111     int match = base != 0;
0112 
0113     if (match) {
0114         if (irq <= -1)
0115             dev_warn(dev, "Using polling mode (specify irq)\n");
0116     } else
0117         dev_err(dev, "Please specify I/O base\n");
0118 
0119     return match;
0120 }
0121 
0122 static int pca_isa_probe(struct device *dev, unsigned int id)
0123 {
0124     init_waitqueue_head(&pca_wait);
0125 
0126     dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
0127 
0128 #ifdef CONFIG_PPC
0129     if (check_legacy_ioport(base)) {
0130         dev_err(dev, "I/O address %#08lx is not available\n", base);
0131         goto out;
0132     }
0133 #endif
0134 
0135     if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
0136         dev_err(dev, "I/O address %#08lx is in use\n", base);
0137         goto out;
0138     }
0139 
0140     if (irq > -1) {
0141         if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
0142             dev_err(dev, "Request irq%d failed\n", irq);
0143             goto out_region;
0144         }
0145     }
0146 
0147     pca_isa_data.i2c_clock = clock;
0148     if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
0149         dev_err(dev, "Failed to add i2c bus\n");
0150         goto out_irq;
0151     }
0152 
0153     return 0;
0154 
0155  out_irq:
0156     if (irq > -1)
0157         free_irq(irq, &pca_isa_ops);
0158  out_region:
0159     release_region(base, IO_SIZE);
0160  out:
0161     return -ENODEV;
0162 }
0163 
0164 static void pca_isa_remove(struct device *dev, unsigned int id)
0165 {
0166     i2c_del_adapter(&pca_isa_ops);
0167 
0168     if (irq > -1) {
0169         disable_irq(irq);
0170         free_irq(irq, &pca_isa_ops);
0171     }
0172     release_region(base, IO_SIZE);
0173 }
0174 
0175 static struct isa_driver pca_isa_driver = {
0176     .match      = pca_isa_match,
0177     .probe      = pca_isa_probe,
0178     .remove     = pca_isa_remove,
0179     .driver = {
0180         .owner  = THIS_MODULE,
0181         .name   = DRIVER,
0182     }
0183 };
0184 
0185 MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
0186 MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
0187 MODULE_LICENSE("GPL");
0188 
0189 module_param_hw(base, ulong, ioport, 0);
0190 MODULE_PARM_DESC(base, "I/O base address");
0191 module_param_hw(irq, int, irq, 0);
0192 MODULE_PARM_DESC(irq, "IRQ");
0193 module_param(clock, int, 0);
0194 MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"
0195         "For PCA9564: 330000,288000,217000,146000,"
0196         "88000,59000,44000,36000\n"
0197         "\t\tFor PCA9665:\tStandard: 60300 - 100099\n"
0198         "\t\t\t\tFast: 100100 - 400099\n"
0199         "\t\t\t\tFast+: 400100 - 10000099\n"
0200         "\t\t\t\tTurbo: Up to 1265800");
0201 module_isa_driver(pca_isa_driver, 1);