From: Marco Aurelio da Costa <costa-nrw9SyMmU14AvxtiuMwx3w@public.gmane.org>
To: i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
Subject: PCA9665 support added to i2c-algo-pca and i2c-pca-isa.c
Date: Fri, 19 Sep 2008 11:22:47 -0300 [thread overview]
Message-ID: <48D3B5B7.1060402@gamic.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Hi Wolfram,
Here is the patch against 2.6.26.5.
Please tell me if I did something very wrong ;)
Regards,
Marco
[-- Attachment #2: pca9665-support.patch --]
[-- Type: text/x-patch, Size: 11211 bytes --]
diff -ur linux-2.6.26.5/drivers/i2c/algos/i2c-algo-pca.c linux-2.6.26.5-new/drivers/i2c/algos/i2c-algo-pca.c
--- linux-2.6.26.5/drivers/i2c/algos/i2c-algo-pca.c 2008-09-08 14:40:20.000000000 -0300
+++ linux-2.6.26.5-new/drivers/i2c/algos/i2c-algo-pca.c 2008-09-19 10:29:33.000000000 -0300
@@ -43,6 +43,14 @@
#define pca_wait(adap) adap->wait_for_completion(adap->data)
#define pca_reset(adap) adap->reset_chip(adap->data)
+static void pca9665_reset(void *pd)
+{
+ struct i2c_algo_pca_data *adap = pd;
+ pca_outw(adap,I2C_PCA_INDPTR,I2C_PCA_IPRESET);
+ pca_outw(adap,I2C_PCA_IND,0xA5);
+ pca_outw(adap,I2C_PCA_IND,0x5A);
+}
+
/*
* Generate a start condition on the i2c bus.
*
@@ -332,24 +340,132 @@
static int pca_init(struct i2c_adapter *adap)
{
- static int freqs[] = {330,288,217,146,88,59,44,36};
- int clock;
struct i2c_algo_pca_data *pca_data = adap->algo_data;
- if (pca_data->i2c_clock > 7) {
- printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n",
- adap->name);
- pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ adap->algo = &pca_algo;
+
+ if (pca_data->i2c_chip_type != I2C_PCA_CHIP_9564 && pca_data->i2c_chip_type != I2C_PCA_CHIP_9665 ) {
+ printk(KERN_WARNING "%s: Invalid chip selected. Assuming PCA9564.\n",
+ adap->name);
+ pca_data->i2c_chip_type = I2C_PCA_CHIP_9564;
}
- adap->algo = &pca_algo;
+ if (pca_data->i2c_chip_type == I2C_PCA_CHIP_9564) {
+ static int freqs[] = {330,288,217,146,88,59,44,36};
+ int clock;
+
+ if (pca_data->i2c_clock > 7) {
+ switch (pca_data->i2c_clock) {
+ case 330000:
+ pca_data->i2c_clock = I2C_PCA_CON_330kHz;
+ break;
+ case 288000:
+ pca_data->i2c_clock = I2C_PCA_CON_288kHz;
+ break;
+ case 217000:
+ pca_data->i2c_clock = I2C_PCA_CON_217kHz;
+ break;
+ case 146000:
+ pca_data->i2c_clock = I2C_PCA_CON_146kHz;
+ break;
+ case 88000:
+ pca_data->i2c_clock = I2C_PCA_CON_88kHz;
+ break;
+ case 59000:
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ break;
+ case 44000:
+ pca_data->i2c_clock = I2C_PCA_CON_44kHz;
+ break;
+ case 36000:
+ pca_data->i2c_clock = I2C_PCA_CON_36kHz;
+ break;
+ default:
+ printk(KERN_WARNING "%s: Invalid I2C clock speed selected. Trying default.\n",
+ adap->name);
+ pca_data->i2c_clock = I2C_PCA_CON_59kHz;
+ }
+ } else {
+ printk(KERN_WARNING "%s: Choosing the clock frequency based on index is deprecated. Use the nominal frequency.\n",
+ adap->name);
+ }
+
+ pca_reset(pca_data);
+
+ clock = pca_clock(pca_data);
+ DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+ } else {
+ int clock;
+ int mode;
+ int tlow, thigh;
+ int minTLow, minTHi;
+ int tRaiseFall;
+
+ struct i2c_algo_pca_data *pca_data = adap->algo_data;
+
+ /* Ignore the reset function from the module, we can use the parallel bus reset */
+ pca_data->reset_chip = pca9665_reset;
+
+ if (pca_data->i2c_clock > 1265800) {
+ printk(KERN_WARNING "%s: I2C clock speed too high. Using 1265.8kHz.\n",
+ adap->name);
+ pca_data->i2c_clock = 1265800;
+ }
+
+ if (pca_data->i2c_clock < 60300) {
+ printk(KERN_WARNING "%s: I2C clock speed too low. Using 60.3kHz.\n",
+ adap->name);
+ pca_data->i2c_clock = 60300;
+ }
+
+ clock = pca_clock(pca_data)/100; /* Hz*100 */
+
+
+ if (pca_data->i2c_clock > 10000) {
+ mode = I2C_PCA_MODE_TURBO;
+ minTLow = 14;
+ minTHi = 5;
+ tRaiseFall = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 4000) {
+ mode = I2C_PCA_MODE_FASTP;
+ minTLow = 17;
+ minTHi = 9;
+ tRaiseFall = 22; /* Raise 11e-8s, Fall 11e-8s */
+ } else if (pca_data->i2c_clock > 1000) {
+ mode = I2C_PCA_MODE_FAST;
+ minTLow = 44;
+ minTHi = 20;
+ tRaiseFall = 58; /* Raise 29e-8s, Fall 29e-8s */
+ } else {
+ mode = I2C_PCA_MODE_STD;
+ minTLow = 157;
+ minTHi = 134;
+ tRaiseFall = 127; /* Raise 29e-8s, Fall 98e-8s */
+ }
- pca_reset(pca_data);
+ if (clock < 648) {
+ tlow = 255;
+ thigh = (1000000 - clock*tRaiseFall)/(3*clock)-tlow;
+ } else {
+ tlow = ((1000000 - clock*tRaiseFall)*minTLow)/(3*clock*(minTHi+minTLow));
+ thigh = tlow*minTHi/minTLow;
+ }
+
+ pca_reset(pca_data);
- clock = pca_clock(pca_data);
- DEB1(KERN_INFO "%s: Clock frequency is %dkHz\n", adap->name, freqs[clock]);
+ DEB1(KERN_INFO "%s: Clock frequency is %dHz\n", adap->name, clock*100);
- pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+ pca_outw(pca_data,I2C_PCA_INDPTR,I2C_PCA_IMODE);
+ pca_outw(pca_data,I2C_PCA_IND,mode);
+ pca_outw(pca_data,I2C_PCA_INDPTR,I2C_PCA_ISCLL);
+ pca_outw(pca_data,I2C_PCA_IND,tlow);
+ pca_outw(pca_data,I2C_PCA_INDPTR,I2C_PCA_ISCLH);
+ pca_outw(pca_data,I2C_PCA_IND,thigh);
+
+ pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
+ }
udelay(500); /* 500 us for oscilator to stabilise */
return 0;
@@ -384,7 +500,7 @@
MODULE_AUTHOR("Ian Campbell <icampbell-2sJRl1BP9u0AvxtiuMwx3w@public.gmane.org>, "
"Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>");
-MODULE_DESCRIPTION("I2C-Bus PCA9564 algorithm");
+MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
MODULE_LICENSE("GPL");
module_param(i2c_debug, int, 0);
diff -ur linux-2.6.26.5/drivers/i2c/busses/i2c-pca-isa.c linux-2.6.26.5-new/drivers/i2c/busses/i2c-pca-isa.c
--- linux-2.6.26.5/drivers/i2c/busses/i2c-pca-isa.c 2008-09-08 14:40:20.000000000 -0300
+++ linux-2.6.26.5-new/drivers/i2c/busses/i2c-pca-isa.c 2008-09-19 10:59:33.000000000 -0300
@@ -42,6 +42,7 @@
/* Data sheet recommends 59kHz for 100kHz operation due to variation
* in the actual clock rate */
static int clock = I2C_PCA_CON_59kHz;
+static int chip = I2C_PCA_CHIP_9564;
static wait_queue_head_t pca_wait;
@@ -103,7 +104,7 @@
.owner = THIS_MODULE,
.id = I2C_HW_A_ISA,
.algo_data = &pca_isa_data,
- .name = "PCA9564 ISA Adapter",
+ .name = "PCA9564/PCA9665 ISA Adapter",
.timeout = 100,
};
@@ -132,6 +133,7 @@
}
}
+ pca_isa_data.i2c_chip_type = chip;
pca_isa_data.i2c_clock = clock;
if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
dev_err(dev, "Failed to add i2c bus\n");
@@ -182,7 +184,7 @@
}
MODULE_AUTHOR("Ian Campbell <icampbell-2sJRl1BP9u0AvxtiuMwx3w@public.gmane.org>");
-MODULE_DESCRIPTION("ISA base PCA9564 driver");
+MODULE_DESCRIPTION("ISA base PCA9564/PCA9665 driver");
MODULE_LICENSE("GPL");
module_param(base, ulong, 0);
@@ -191,7 +193,11 @@
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_PARM_DESC(clock, "Clock rate in hertz.\n\t\tFor PCA9564: 330000,288000,217000,146000,88000,59000,44000,36000\n"
+ "\t\tFor PCA9665:\tStandard: 60300 - 100099\n\t\t\t\tFast: 100100 - 400099\n\t\t\t\tFast+: 400100 - 10000099\n"
+ "\t\t\t\tTurbo: Up to 1265800");
+module_param(chip, int, 0);
+MODULE_PARM_DESC(chip, "Chip type: 0 = PCA9564; 1 - PCA9665");
module_init(pca_isa_init);
module_exit(pca_isa_exit);
diff -ur linux-2.6.26.5/drivers/i2c/busses/i2c-pca-platform.c linux-2.6.26.5-new/drivers/i2c/busses/i2c-pca-platform.c
--- linux-2.6.26.5/drivers/i2c/busses/i2c-pca-platform.c 2008-09-08 14:40:20.000000000 -0300
+++ linux-2.6.26.5-new/drivers/i2c/busses/i2c-pca-platform.c 2008-09-19 10:11:02.000000000 -0300
@@ -172,7 +172,7 @@
i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
i2c->adap.owner = THIS_MODULE;
- snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564 at 0x%08lx",
+ snprintf(i2c->adap.name, sizeof(i2c->adap.name), "PCA9564/PCA9665 at 0x%08lx",
(unsigned long) res->start);
i2c->adap.algo_data = &i2c->algo_data;
i2c->adap.dev.parent = &pdev->dev;
@@ -246,7 +246,7 @@
e_alloc:
release_mem_region(res->start, res_len(res));
e_print:
- printk(KERN_ERR "Registering PCA9564 FAILED! (%d)\n", ret);
+ printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret);
return ret;
}
@@ -290,7 +290,7 @@
}
MODULE_AUTHOR("Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>");
-MODULE_DESCRIPTION("I2C-PCA9564 platform driver");
+MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
MODULE_LICENSE("GPL");
module_init(i2c_pca_pf_init);
diff -ur linux-2.6.26.5/drivers/i2c/busses/Kconfig linux-2.6.26.5-new/drivers/i2c/busses/Kconfig
--- linux-2.6.26.5/drivers/i2c/busses/Kconfig 2008-09-08 14:40:20.000000000 -0300
+++ linux-2.6.26.5-new/drivers/i2c/busses/Kconfig 2008-09-19 10:33:35.000000000 -0300
@@ -630,7 +630,7 @@
will be called i2c-voodoo3.
config I2C_PCA_ISA
- tristate "PCA9564 on an ISA bus"
+ tristate "PCA9564/PCA9665 on an ISA bus"
depends on ISA
select I2C_ALGOPCA
default n
@@ -647,7 +647,7 @@
time). If unsure, say N.
config I2C_PCA_PLATFORM
- tristate "PCA9564 as platform device"
+ tristate "PCA9564/PCA9665 as platform device"
select I2C_ALGOPCA
default n
help
diff -ur linux-2.6.26.5/include/linux/i2c-algo-pca.h linux-2.6.26.5-new/include/linux/i2c-algo-pca.h
--- linux-2.6.26.5/include/linux/i2c-algo-pca.h 2008-09-08 14:40:20.000000000 -0300
+++ linux-2.6.26.5-new/include/linux/i2c-algo-pca.h 2008-09-19 11:13:21.000000000 -0300
@@ -1,7 +1,11 @@
#ifndef _LINUX_I2C_ALGO_PCA_H
#define _LINUX_I2C_ALGO_PCA_H
-/* Clock speeds for the bus */
+/* Chips known to the pca algo */
+#define I2C_PCA_CHIP_9564 0x00
+#define I2C_PCA_CHIP_9665 0x01
+
+/* Clock speeds for the bus for PCA9564*/
#define I2C_PCA_CON_330kHz 0x00
#define I2C_PCA_CON_288kHz 0x01
#define I2C_PCA_CON_217kHz 0x02
@@ -18,6 +22,26 @@
#define I2C_PCA_ADR 0x02 /* OWN ADR Read/Write */
#define I2C_PCA_CON 0x03 /* CONTROL Read/Write */
+/* PCA9665 registers */
+#define I2C_PCA_INDPTR 0x00 /* INDIRECT Pointer Write Only */
+#define I2C_PCA_IND 0x02 /* INDIRECT Read/Write */
+
+/* PCA9665 indirect registers */
+#define I2C_PCA_ICOUNT 0x00 /* Byte Count for buffered mode */
+#define I2C_PCA_IADR 0x01 /* OWN ADR */
+#define I2C_PCA_ISCLL 0x02 /* SCL LOW period */
+#define I2C_PCA_ISCLH 0x03 /* SCL HIGH period */
+#define I2C_PCA_ITO 0x04 /* TIMEOUT */
+#define I2C_PCA_IPRESET 0x05 /* Parallel bus reset */
+#define I2C_PCA_IMODE 0x06 /* I2C Bus mode */
+
+/* PCA9665 I2C bus mode */
+#define I2C_PCA_MODE_STD 0x00 /* Standard mode */
+#define I2C_PCA_MODE_FAST 0x01 /* Fast mode */
+#define I2C_PCA_MODE_FASTP 0x02 /* Fast Plus mode */
+#define I2C_PCA_MODE_TURBO 0x03 /* Turbo mode */
+
+
#define I2C_PCA_CON_AA 0x80 /* Assert Acknowledge */
#define I2C_PCA_CON_ENSIO 0x40 /* Enable */
#define I2C_PCA_CON_STA 0x20 /* Start */
@@ -31,8 +55,11 @@
int (*read_byte) (void *data, int reg);
int (*wait_for_completion) (void *data);
void (*reset_chip) (void *data);
- /* i2c_clock values are defined in linux/i2c-algo-pca.h */
+ /* For PCA9964, use one of the predefined frequencies:
+ * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000
+ * For PCA9665, use the frequency you want here. */
unsigned int i2c_clock;
+ unsigned int i2c_chip_type;
};
int i2c_pca_add_bus(struct i2c_adapter *);
[-- Attachment #3: Type: text/plain, Size: 157 bytes --]
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
next reply other threads:[~2008-09-19 14:22 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-19 14:22 Marco Aurelio da Costa [this message]
[not found] ` <48D3B5B7.1060402-nrw9SyMmU14AvxtiuMwx3w@public.gmane.org>
2008-09-19 14:55 ` PCA9665 support added to i2c-algo-pca and i2c-pca-isa.c Wolfram Sang
[not found] ` <20080919145500.GH4307-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2008-09-19 15:37 ` Marco Aurelio da Costa
[not found] ` <48D3C74E.1050801-nrw9SyMmU14AvxtiuMwx3w@public.gmane.org>
2008-09-20 7:21 ` Wolfram Sang
[not found] ` <20080920072131.GB12497-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2008-09-20 11:09 ` Marco Aurelio da Costa
[not found] ` <c76dcaf00809200409r7e0420c9rcb83a654d40e217a-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-09-20 12:10 ` Marco Aurelio da Costa
[not found] ` <c76dcaf00809200510k7e6b4648v630dc33bf6401cca-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-09-24 12:45 ` Marco Aurelio da Costa
[not found] ` <c76dcaf00809240545k4b7daf53ydbf374a88a5d686a-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-09-24 12:57 ` Wolfram Sang
2008-10-01 17:39 ` Wolfram Sang
[not found] ` <20081001173909.GG17953-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2008-10-02 23:27 ` Marco Aurelio da Costa
[not found] ` <c76dcaf00810021627y561e8dbdv5e85b1bc503d1f0b-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-10-14 13:08 ` Wolfram Sang
[not found] ` <c76dcaf00810140614i28e49f27xb9d4c503144606b0@mail.gmail.com>
[not found] ` <c76dcaf00810140614i28e49f27xb9d4c503144606b0-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2008-12-17 11:39 ` [i2c] " Wolfram Sang
[not found] ` <20081217113940.GE3382-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
2009-01-14 19:39 ` Wolfram Sang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48D3B5B7.1060402@gamic.com \
--to=costa-nrw9symmu14avxtiumwx3w@public.gmane.org \
--cc=i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.