Commit 8c30a9fa authored by Ian Campbell's avatar Ian Campbell Committed by Greg Kroah-Hartman

[PATCH] I2C: algorithm and bus driver for PCA9564

Attached is a driver for the PCA9564 "Parallel to I2C" chip, it is
similar in principle to the PCF8584 which is supported by the
i2c-algo-pcf and i2c-elektor code, however it's not code compatible in
any way: http://www.semiconductors.philips.com/pip/PCA9564PW.html

The patch contains the PCA algorithm driver and a bus driver for an ISA
card. It only supports master send and receive but I'm not sure that the
Linux i2c stack supports client side operation anyhow, and I have no
hardware to test on.

It was tested on a PC104 card containing the PCA chip and an Atmel TPM
device and also on a separate PC104 card with a DS1307 RTC hotwired onto
it for testing purposes.

The driver is against a 2.6 BK tree pulled on Friday. I also have a
fairly trivial 2.4 backport if that is of interest.

From: Ian Campbell <icampbell@arcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 4f6de4ab
...@@ -27,6 +27,17 @@ config I2C_ALGOPCF ...@@ -27,6 +27,17 @@ config I2C_ALGOPCF
This support is also available as a module. If so, the module This support is also available as a module. If so, the module
will be called i2c-algo-pcf. will be called i2c-algo-pcf.
config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
depends on I2C
help
This allows you to use a range of I2C adapters called PCA adapters.
Say Y if you own an I2C adapter belonging to this class and then say
Y to the specific driver for you adapter below.
This support is also available as a module. If so, the module
will be called i2c-algo-pca.
config I2C_ALGOITE config I2C_ALGOITE
tristate "ITE I2C Algorithm" tristate "ITE I2C Algorithm"
depends on MIPS_ITE8172 && I2C depends on MIPS_ITE8172 && I2C
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y) ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
......
This diff is collapsed.
#ifndef I2C_PCA9564_H
#define I2C_PCA9564_H 1
#define I2C_PCA_STA 0x00 /* STATUS Read Only */
#define I2C_PCA_TO 0x00 /* TIMEOUT Write Only */
#define I2C_PCA_DAT 0x01 /* DATA Read/Write */
#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */
#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */
#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */
#define I2C_PCA_CON_ENSIO 0x40 /* Enable */
#define I2C_PCA_CON_STA 0x20 /* Start */
#define I2C_PCA_CON_STO 0x10 /* Stop */
#define I2C_PCA_CON_SI 0x08 /* Serial Interrupt */
#define I2C_PCA_CON_CR 0x07 /* Clock Rate (MASK) */
#define I2C_PCA_CON_330kHz 0x00
#define I2C_PCA_CON_288kHz 0x01
#define I2C_PCA_CON_217kHz 0x02
#define I2C_PCA_CON_146kHz 0x03
#define I2C_PCA_CON_88kHz 0x04
#define I2C_PCA_CON_59kHz 0x05
#define I2C_PCA_CON_44kHz 0x06
#define I2C_PCA_CON_36kHz 0x07
#endif /* I2C_PCA9564_H */
...@@ -419,4 +419,15 @@ config I2C_VOODOO3 ...@@ -419,4 +419,15 @@ config I2C_VOODOO3
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-voodoo3. will be called i2c-voodoo3.
config I2C_PCA_ISA
tristate "PCA9564 on an ISA bus"
depends on I2C
select I2C_ALGOPCA
help
This driver supports ISA boards using the Philips PCA 9564
Parallel bus to I2C bus controller
This driver can also be built as a module. If so, the module
will be called i2c-pca-isa.
endmenu endmenu
...@@ -22,6 +22,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o ...@@ -22,6 +22,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
......
/*
* i2c-pca-isa.c driver for PCA9564 on ISA boards
* Copyright (C) 2004 Arcom Control Systems
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/wait.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pca.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "../algos/i2c-algo-pca.h"
#define IO_SIZE 4
#undef DEBUG_IO
//#define DEBUG_IO
static unsigned long base = 0x330;
static int irq = 10;
/* Data sheet recommends 59kHz for 100kHz operation due to variation
* in the actual clock rate */
static int clock = I2C_PCA_CON_59kHz;
static int own = 0x55;
static wait_queue_head_t pca_wait;
static int pca_isa_getown(struct i2c_algo_pca_data *adap)
{
return (own);
}
static int pca_isa_getclock(struct i2c_algo_pca_data *adap)
{
return (clock);
}
static void
pca_isa_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
{
#ifdef DEBUG_IO
static char *names[] = { "T/O", "DAT", "ADR", "CON" };
printk("*** write %s at %#lx <= %#04x\n", names[reg], base+reg, val);
#endif
outb(val, base+reg);
}
static int
pca_isa_readbyte(struct i2c_algo_pca_data *adap, int reg)
{
int res = inb(base+reg);
#ifdef DEBUG_IO
{
static char *names[] = { "STA", "DAT", "ADR", "CON" };
printk("*** read %s => %#04x\n", names[reg], res);
}
#endif
return res;
}
static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
{
int ret = 0;
if (irq > -1) {
ret = wait_event_interruptible(pca_wait,
pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI);
} else {
while ((pca_isa_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
udelay(100);
}
return ret;
}
static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
wake_up_interruptible(&pca_wait);
return IRQ_HANDLED;
}
static struct i2c_algo_pca_data pca_isa_data = {
.get_own = pca_isa_getown,
.get_clock = pca_isa_getclock,
.write_byte = pca_isa_writebyte,
.read_byte = pca_isa_readbyte,
.wait_for_interrupt = pca_isa_waitforinterrupt,
};
static struct i2c_adapter pca_isa_ops = {
.owner = THIS_MODULE,
.id = I2C_HW_A_ISA,
.algo_data = &pca_isa_data,
.name = "PCA9564 ISA Adapter",
};
static int __init pca_isa_init(void)
{
init_waitqueue_head(&pca_wait);
printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq);
if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base);
goto out;
}
if (irq > -1) {
if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq);
goto out_region;
}
}
if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n");
goto out_irq;
}
return 0;
out_irq:
if (irq > -1)
free_irq(irq, &pca_isa_ops);
out_region:
release_region(base, IO_SIZE);
out:
return -ENODEV;
}
static void pca_isa_exit(void)
{
i2c_pca_del_bus(&pca_isa_ops);
if (irq > 0) {
disable_irq(irq);
free_irq(irq, &pca_isa_ops);
}
release_region(base, IO_SIZE);
}
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
MODULE_DESCRIPTION("ISA base PCA9564 driver");
MODULE_LICENSE("GPL");
module_param(base, ulong, 0);
MODULE_PARM_DESC(base, "I/O base address");
module_param(irq, int, 0);
MODULE_PARM_DESC(irq, "IRQ");
module_param(clock, int, 0);
MODULE_PARM_DESC(clock, "Clock rate as described in table 1 of PCA9564 datasheet");
module_param(own, int, 0); /* the driver can't do slave mode, so there's no real point in this */
module_init(pca_isa_init);
module_exit(pca_isa_exit);
#ifndef _LINUX_I2C_ALGO_PCA_H
#define _LINUX_I2C_ALGO_PCA_H
struct i2c_algo_pca_data {
int (*get_own) (struct i2c_algo_pca_data *adap); /* Obtain own address */
int (*get_clock) (struct i2c_algo_pca_data *adap);
void (*write_byte) (struct i2c_algo_pca_data *adap, int reg, int val);
int (*read_byte) (struct i2c_algo_pca_data *adap, int reg);
int (*wait_for_interrupt) (struct i2c_algo_pca_data *adap);
};
#define I2C_PCA_ADAP_MAX 16
int i2c_pca_add_bus(struct i2c_adapter *);
int i2c_pca_del_bus(struct i2c_adapter *);
#endif /* _LINUX_I2C_ALGO_PCA_H */
...@@ -194,6 +194,7 @@ ...@@ -194,6 +194,7 @@
#define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */
#define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */
#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ #define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */
#define I2C_ALGO_PCA 0x150000 /* PCA 9564 style adapters */
#define I2C_ALGO_EXP 0x800000 /* experimental */ #define I2C_ALGO_EXP 0x800000 /* experimental */
...@@ -239,6 +240,9 @@ ...@@ -239,6 +240,9 @@
#define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */ #define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */
#define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */ #define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
/* --- PCA 9564 based algorithms */
#define I2C_HW_A_ISA 0x00 /* generic ISA Bus interface card */
/* --- ACPI Embedded controller algorithms */ /* --- ACPI Embedded controller algorithms */
#define I2C_HW_ACPI_EC 0x00 #define I2C_HW_ACPI_EC 0x00
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment