Path: blob/master/drivers/i2c/busses/i2c-pca-isa.c
15111 views
/*1* i2c-pca-isa.c driver for PCA9564 on ISA boards2* Copyright (C) 2004 Arcom Control Systems3* Copyright (C) 2008 Pengutronix4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.18*/1920#include <linux/kernel.h>21#include <linux/ioport.h>22#include <linux/module.h>23#include <linux/moduleparam.h>24#include <linux/delay.h>25#include <linux/jiffies.h>26#include <linux/init.h>27#include <linux/interrupt.h>28#include <linux/wait.h>29#include <linux/isa.h>30#include <linux/i2c.h>31#include <linux/i2c-algo-pca.h>32#include <linux/io.h>3334#include <asm/irq.h>3536#define DRIVER "i2c-pca-isa"37#define IO_SIZE 43839static unsigned long base;40static int irq = -1;4142/* Data sheet recommends 59kHz for 100kHz operation due to variation43* in the actual clock rate */44static int clock = 59000;4546static struct i2c_adapter pca_isa_ops;47static wait_queue_head_t pca_wait;4849static void pca_isa_writebyte(void *pd, int reg, int val)50{51#ifdef DEBUG_IO52static char *names[] = { "T/O", "DAT", "ADR", "CON" };53printk(KERN_DEBUG "*** write %s at %#lx <= %#04x\n", names[reg],54base+reg, val);55#endif56outb(val, base+reg);57}5859static int pca_isa_readbyte(void *pd, int reg)60{61int res = inb(base+reg);62#ifdef DEBUG_IO63{64static char *names[] = { "STA", "DAT", "ADR", "CON" };65printk(KERN_DEBUG "*** read %s => %#04x\n", names[reg], res);66}67#endif68return res;69}7071static int pca_isa_waitforcompletion(void *pd)72{73unsigned long timeout;74long ret;7576if (irq > -1) {77ret = wait_event_timeout(pca_wait,78pca_isa_readbyte(pd, I2C_PCA_CON)79& I2C_PCA_CON_SI, pca_isa_ops.timeout);80} else {81/* Do polling */82timeout = jiffies + pca_isa_ops.timeout;83do {84ret = time_before(jiffies, timeout);85if (pca_isa_readbyte(pd, I2C_PCA_CON)86& I2C_PCA_CON_SI)87break;88udelay(100);89} while (ret);90}9192return ret > 0;93}9495static void pca_isa_resetchip(void *pd)96{97/* apparently only an external reset will do it. not a lot can be done */98printk(KERN_WARNING DRIVER ": Haven't figured out how to do a reset yet\n");99}100101static irqreturn_t pca_handler(int this_irq, void *dev_id) {102wake_up(&pca_wait);103return IRQ_HANDLED;104}105106static struct i2c_algo_pca_data pca_isa_data = {107/* .data intentionally left NULL, not needed with ISA */108.write_byte = pca_isa_writebyte,109.read_byte = pca_isa_readbyte,110.wait_for_completion = pca_isa_waitforcompletion,111.reset_chip = pca_isa_resetchip,112};113114static struct i2c_adapter pca_isa_ops = {115.owner = THIS_MODULE,116.algo_data = &pca_isa_data,117.name = "PCA9564/PCA9665 ISA Adapter",118.timeout = HZ,119};120121static int __devinit pca_isa_match(struct device *dev, unsigned int id)122{123int match = base != 0;124125if (match) {126if (irq <= -1)127dev_warn(dev, "Using polling mode (specify irq)\n");128} else129dev_err(dev, "Please specify I/O base\n");130131return match;132}133134static int __devinit pca_isa_probe(struct device *dev, unsigned int id)135{136init_waitqueue_head(&pca_wait);137138dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);139140#ifdef CONFIG_PPC141if (check_legacy_ioport(base)) {142dev_err(dev, "I/O address %#08lx is not available\n", base);143goto out;144}145#endif146147if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {148dev_err(dev, "I/O address %#08lx is in use\n", base);149goto out;150}151152if (irq > -1) {153if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {154dev_err(dev, "Request irq%d failed\n", irq);155goto out_region;156}157}158159pca_isa_data.i2c_clock = clock;160if (i2c_pca_add_bus(&pca_isa_ops) < 0) {161dev_err(dev, "Failed to add i2c bus\n");162goto out_irq;163}164165return 0;166167out_irq:168if (irq > -1)169free_irq(irq, &pca_isa_ops);170out_region:171release_region(base, IO_SIZE);172out:173return -ENODEV;174}175176static int __devexit pca_isa_remove(struct device *dev, unsigned int id)177{178i2c_del_adapter(&pca_isa_ops);179180if (irq > -1) {181disable_irq(irq);182free_irq(irq, &pca_isa_ops);183}184release_region(base, IO_SIZE);185186return 0;187}188189static struct isa_driver pca_isa_driver = {190.match = pca_isa_match,191.probe = pca_isa_probe,192.remove = __devexit_p(pca_isa_remove),193.driver = {194.owner = THIS_MODULE,195.name = DRIVER,196}197};198199static int __init pca_isa_init(void)200{201return isa_register_driver(&pca_isa_driver, 1);202}203204static void __exit pca_isa_exit(void)205{206isa_unregister_driver(&pca_isa_driver);207}208209MODULE_AUTHOR("Ian Campbell <[email protected]>");210MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");211MODULE_LICENSE("GPL");212213module_param(base, ulong, 0);214MODULE_PARM_DESC(base, "I/O base address");215216module_param(irq, int, 0);217MODULE_PARM_DESC(irq, "IRQ");218module_param(clock, int, 0);219MODULE_PARM_DESC(clock, "Clock rate in hertz.\n\t\t"220"For PCA9564: 330000,288000,217000,146000,"221"88000,59000,44000,36000\n"222"\t\tFor PCA9665:\tStandard: 60300 - 100099\n"223"\t\t\t\tFast: 100100 - 400099\n"224"\t\t\t\tFast+: 400100 - 10000099\n"225"\t\t\t\tTurbo: Up to 1265800");226227module_init(pca_isa_init);228module_exit(pca_isa_exit);229230231