summaryrefslogtreecommitdiff
path: root/drivers/i2c/algos
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/algos')
-rw-r--r--drivers/i2c/algos/Kconfig1
-rw-r--r--drivers/i2c/algos/Makefile1
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c168
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c70
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c129
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.h11
6 files changed, 159 insertions, 221 deletions
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index f1cfe7e5508b..aea523529ef6 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# I2C algorithm drivers configuration
#
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 215303f60d61..9b319a30d2ea 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the i2c algorithms
#
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 1147bddb8b2c..6544d27e4419 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -1,21 +1,12 @@
-/* -------------------------------------------------------------------------
- * i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
- * -------------------------------------------------------------------------
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * i2c-algo-bit.c: i2c driver algorithms for bit-shift adapters
+ *
* Copyright (C) 1995-2000 Simon G. Vogl
-
- 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.
- * ------------------------------------------------------------------------- */
-
-/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
- <kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de> */
+ *
+ * With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
+ * <kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de>
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -110,8 +101,8 @@ static int sclhi(struct i2c_algo_bit_data *adap)
}
#ifdef DEBUG
if (jiffies != start && i2c_debug >= 3)
- pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
- "high\n", jiffies - start);
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go high\n",
+ jiffies - start);
#endif
done:
@@ -171,8 +162,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
setsda(adap, sb);
udelay((adap->udelay + 1) / 2);
if (sclhi(adap) < 0) { /* timed out */
- bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
- "timeout at bit #%d\n", (int)c, i);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_outb: 0x%02x, timeout at bit #%d\n",
+ (int)c, i);
return -ETIMEDOUT;
}
/* FIXME do arbitration here:
@@ -185,15 +177,16 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
}
sdahi(adap);
if (sclhi(adap) < 0) { /* timeout */
- bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
- "timeout at ack\n", (int)c);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_outb: 0x%02x, timeout at ack\n", (int)c);
return -ETIMEDOUT;
}
/* read ack: SDA should be pulled down by slave, or it may
* NAK (usually to report problems with the data we wrote).
+ * Always report ACK if SDA is write-only.
*/
- ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ ack = !adap->getsda || !getsda(adap); /* ack: sda is pulled low -> success */
bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
ack ? "A" : "NA");
@@ -215,8 +208,9 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
sdahi(adap);
for (i = 0; i < 8; i++) {
if (sclhi(adap) < 0) { /* timeout */
- bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
- "#%d\n", 7 - i);
+ bit_dbg(1, &i2c_adap->dev,
+ "i2c_inb: timeout at bit #%d\n",
+ 7 - i);
return -ETIMEDOUT;
}
indata *= 2;
@@ -245,67 +239,55 @@ static int test_bus(struct i2c_adapter *i2c_adap)
return -ENODEV;
}
+ if (adap->getsda == NULL)
+ pr_info("%s: SDA is write-only, testing not possible\n", name);
if (adap->getscl == NULL)
- pr_info("%s: Testing SDA only, SCL is not readable\n", name);
+ pr_info("%s: SCL is write-only, testing not possible\n", name);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
+ sda = adap->getsda ? getsda(adap) : 1;
+ scl = adap->getscl ? getscl(adap) : 1;
if (!scl || !sda) {
- printk(KERN_WARNING
- "%s: bus seems to be busy (scl=%d, sda=%d)\n",
- name, scl, sda);
+ pr_warn("%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda);
goto bailout;
}
sdalo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (sda) {
- printk(KERN_WARNING "%s: SDA stuck high!\n", name);
+ if (adap->getsda && getsda(adap)) {
+ pr_warn("%s: SDA stuck high!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING "%s: SCL unexpected low "
- "while pulling SDA low!\n", name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA low!\n", name);
goto bailout;
}
sdahi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!sda) {
- printk(KERN_WARNING "%s: SDA stuck low!\n", name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA stuck low!\n", name);
goto bailout;
}
- if (!scl) {
- printk(KERN_WARNING "%s: SCL unexpected low "
- "while pulling SDA high!\n", name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL unexpected low while pulling SDA high!\n", name);
goto bailout;
}
scllo(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 0 : getscl(adap);
- if (scl) {
- printk(KERN_WARNING "%s: SCL stuck high!\n", name);
+ if (adap->getscl && getscl(adap)) {
+ pr_warn("%s: SCL stuck high!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING "%s: SDA unexpected low "
- "while pulling SCL low!\n", name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL low!\n", name);
goto bailout;
}
sclhi(adap);
- sda = getsda(adap);
- scl = (adap->getscl == NULL) ? 1 : getscl(adap);
- if (!scl) {
- printk(KERN_WARNING "%s: SCL stuck low!\n", name);
+ if (adap->getscl && !getscl(adap)) {
+ pr_warn("%s: SCL stuck low!\n", name);
goto bailout;
}
- if (!sda) {
- printk(KERN_WARNING "%s: SDA unexpected low "
- "while pulling SCL high!\n", name);
+ if (adap->getsda && !getsda(adap)) {
+ pr_warn("%s: SDA unexpected low while pulling SCL high!\n", name);
goto bailout;
}
@@ -352,8 +334,8 @@ static int try_address(struct i2c_adapter *i2c_adap,
i2c_start(adap);
}
if (i && ret)
- bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
- "0x%02x: %s\n", i + 1,
+ bit_dbg(1, &i2c_adap->dev,
+ "Used %d tries to %s client at 0x%02x: %s\n", i + 1,
addr & 1 ? "read from" : "write to", addr >> 1,
ret == 1 ? "success" : "failed, timeout?");
return ret;
@@ -423,6 +405,10 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
unsigned char *temp = msg->buf;
int count = msg->len;
const unsigned flags = msg->flags;
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ if (!adap->getsda)
+ return -EOPNOTSUPP;
while (count > 0) {
inval = i2c_inb(i2c_adap);
@@ -442,8 +428,9 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
if (!(flags & I2C_M_NO_RD_ACK))
acknak(i2c_adap, 0);
- dev_err(&i2c_adap->dev, "readbytes: invalid "
- "block length (%d)\n", inval);
+ dev_err(&i2c_adap->dev,
+ "readbytes: invalid block length (%d)\n",
+ inval);
return -EPROTO;
}
/* The original count value accounts for the extra
@@ -506,8 +493,8 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
return -ENXIO;
}
if (flags & I2C_M_RD) {
- bit_dbg(3, &i2c_adap->dev, "emitting repeated "
- "start condition\n");
+ bit_dbg(3, &i2c_adap->dev,
+ "emitting repeated start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
@@ -519,9 +506,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
}
}
} else { /* normal 7bit address */
- addr = msg->addr << 1;
- if (flags & I2C_M_RD)
- addr |= 1;
+ addr = i2c_8bit_addr_from_msg(msg);
if (flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
ret = try_address(i2c_adap, addr, retries);
@@ -566,8 +551,8 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
- bit_dbg(1, &i2c_adap->dev, "NAK from "
- "device addr 0x%02x msg #%d\n",
+ bit_dbg(1, &i2c_adap->dev,
+ "NAK from device addr 0x%02x msg #%d\n",
msgs[i].addr, i);
goto bailout;
}
@@ -607,11 +592,26 @@ bailout:
return ret;
}
+/*
+ * We print a warning when we are not flagged to support atomic transfers but
+ * will try anyhow. That's what the I2C core would do as well. Sadly, we can't
+ * modify the algorithm struct at probe time because this struct is exported
+ * 'const'.
+ */
+static int bit_xfer_atomic(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+ if (!adap->can_do_atomic)
+ dev_warn(&i2c_adap->dev, "not flagged for atomic transfers\n");
+
+ return bit_xfer(i2c_adap, msgs, num);
+}
+
static u32 bit_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL |
- I2C_FUNC_SMBUS_READ_BLOCK_DATA |
- I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ return I2C_FUNC_I2C | I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_EMUL_ALL |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
}
@@ -619,8 +619,9 @@ static u32 bit_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */
const struct i2c_algorithm i2c_bit_algo = {
- .master_xfer = bit_xfer,
- .functionality = bit_func,
+ .xfer = bit_xfer,
+ .xfer_atomic = bit_xfer_atomic,
+ .functionality = bit_func,
};
EXPORT_SYMBOL(i2c_bit_algo);
@@ -649,15 +650,24 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap,
if (bit_adap->getscl == NULL)
adap->quirks = &i2c_bit_quirk_no_clk_stretch;
+ /*
+ * We tried forcing SCL/SDA to an initial state here. But that caused a
+ * regression, sadly. Check Bugzilla #200045 for details.
+ */
+
ret = add_adapter(adap);
if (ret < 0)
return ret;
- /* Complain if SCL can't be read */
- if (bit_adap->getscl == NULL) {
+ if (bit_adap->getsda == NULL)
+ dev_warn(&adap->dev, "Not I2C compliant: can't read SDA\n");
+
+ if (bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n");
+
+ if (bit_adap->getsda == NULL || bit_adap->getscl == NULL)
dev_warn(&adap->dev, "Bus may be unreliable\n");
- }
+
return 0;
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index e370804ec8bc..ee86df4cff4b 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i2c-algo-pca.c i2c driver algorithms for PCA9564 adapters
* Copyright (C) 2004 Arcom Control Systems
* Copyright (C) 2008 Pengutronix
- *
- * 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.
*/
#include <linux/kernel.h>
@@ -39,7 +30,7 @@ static int i2c_debug;
#define pca_clock(adap) adap->i2c_clock
#define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)
#define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)
-#define pca_wait(adap) adap->wait_for_completion(adap->data)
+#define pca_wait(adap) adap->wait_for_completion_cb(adap->data)
static void pca_reset(struct i2c_algo_pca_data *adap)
{
@@ -50,8 +41,22 @@ static void pca_reset(struct i2c_algo_pca_data *adap)
pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET);
pca_outw(adap, I2C_PCA_IND, 0xA5);
pca_outw(adap, I2C_PCA_IND, 0x5A);
+
+ /*
+ * After a reset we need to re-apply any configuration
+ * (calculated in pca_init) to get the bus in a working state.
+ */
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IMODE);
+ pca_outw(adap, I2C_PCA_IND, adap->bus_settings.mode);
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLL);
+ pca_outw(adap, I2C_PCA_IND, adap->bus_settings.tlow);
+ pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_ISCLH);
+ pca_outw(adap, I2C_PCA_IND, adap->bus_settings.thi);
+
+ pca_set_con(adap, I2C_PCA_CON_ENSIO);
} else {
adap->reset_chip(adap->data);
+ pca_set_con(adap, I2C_PCA_CON_ENSIO | adap->bus_settings.clock_freq);
}
}
@@ -112,11 +117,8 @@ static int pca_address(struct i2c_algo_pca_data *adap,
struct i2c_msg *msg)
{
int sta = pca_get_con(adap);
- int addr;
+ int addr = i2c_8bit_addr_from_msg(msg);
- addr = ((0x7f & msg->addr) << 1);
- if (msg->flags & I2C_M_RD)
- addr |= 1;
DEB2("=== SLAVE ADDRESS %#04x+%c=%#04x\n",
msg->addr, msg->flags & I2C_M_RD ? 'R' : 'W', addr);
@@ -326,7 +328,8 @@ static int pca_xfer(struct i2c_adapter *i2c_adap,
DEB2("BUS ERROR - SDA Stuck low\n");
pca_reset(adap);
goto out;
- case 0x90: /* Bus error - SCL stuck low */
+ case 0x78: /* Bus error - SCL stuck low (PCA9665) */
+ case 0x90: /* Bus error - SCL stuck low (PCA9564) */
DEB2("BUS ERROR - SCL Stuck low\n");
pca_reset(adap);
goto out;
@@ -358,8 +361,8 @@ static u32 pca_func(struct i2c_adapter *adap)
}
static const struct i2c_algorithm pca_algo = {
- .master_xfer = pca_xfer,
- .functionality = pca_func,
+ .xfer = pca_xfer,
+ .functionality = pca_func,
};
static unsigned int pca_probe_chip(struct i2c_adapter *adap)
@@ -434,13 +437,14 @@ static int pca_init(struct i2c_adapter *adap)
" Use the nominal frequency.\n", adap->name);
}
- pca_reset(pca_data);
-
clock = pca_clock(pca_data);
printk(KERN_INFO "%s: Clock frequency is %dkHz\n",
adap->name, freqs[clock]);
- pca_set_con(pca_data, I2C_PCA_CON_ENSIO | clock);
+ /* Store settings as these will be needed when the PCA chip is reset */
+ pca_data->bus_settings.clock_freq = clock;
+
+ pca_reset(pca_data);
} else {
int clock;
int mode;
@@ -471,17 +475,17 @@ static int pca_init(struct i2c_adapter *adap)
/* To avoid integer overflow, use clock/100 for calculations */
clock = pca_clock(pca_data) / 100;
- if (pca_data->i2c_clock > 1000000) {
+ if (pca_data->i2c_clock > I2C_MAX_FAST_MODE_PLUS_FREQ) {
mode = I2C_PCA_MODE_TURBO;
min_tlow = 14;
min_thi = 5;
raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
- } else if (pca_data->i2c_clock > 400000) {
+ } else if (pca_data->i2c_clock > I2C_MAX_FAST_MODE_FREQ) {
mode = I2C_PCA_MODE_FASTP;
min_tlow = 17;
min_thi = 9;
raise_fall_time = 22; /* Raise 11e-8s, Fall 11e-8s */
- } else if (pca_data->i2c_clock > 100000) {
+ } else if (pca_data->i2c_clock > I2C_MAX_STANDARD_MODE_FREQ) {
mode = I2C_PCA_MODE_FAST;
min_tlow = 44;
min_thi = 20;
@@ -507,19 +511,15 @@ static int pca_init(struct i2c_adapter *adap)
thi = tlow * min_thi / min_tlow;
}
+ /* Store settings as these will be needed when the PCA chip is reset */
+ pca_data->bus_settings.mode = mode;
+ pca_data->bus_settings.tlow = tlow;
+ pca_data->bus_settings.thi = thi;
+
pca_reset(pca_data);
printk(KERN_INFO
"%s: Clock frequency is %dHz\n", adap->name, clock * 100);
-
- 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, thi);
-
- pca_set_con(pca_data, I2C_PCA_CON_ENSIO);
}
udelay(500); /* 500 us for oscillator to stabilise */
@@ -553,8 +553,8 @@ int i2c_pca_add_numbered_bus(struct i2c_adapter *adap)
}
EXPORT_SYMBOL(i2c_pca_add_numbered_bus);
-MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>, "
- "Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
+MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
MODULE_DESCRIPTION("I2C-Bus PCA9564/PCA9665 algorithm");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 270d84bfc2c6..a87ecea7f510 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -1,19 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters
*
* Copyright (C) 1995-1997 Simon G. Vogl
* 1998-2000 Hans Berglund
*
- * 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.
- *
* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
* Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
* <mbailey@littlefeet-inc.com>
@@ -28,20 +19,12 @@
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pcf.h>
+#include <linux/string_choices.h>
#include "i2c-algo-pcf.h"
-#define DEB2(x) if (i2c_debug >= 2) x
-#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
-#define DEBPROTO(x) if (i2c_debug >= 9) x;
- /* debug the protocol by showing transferred bits */
#define DEF_TIMEOUT 16
-/*
- * module parameters:
- */
-static int i2c_debug;
-
/* setting states on the bus with the right timing: */
#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
@@ -55,27 +38,21 @@ static int i2c_debug;
static void i2c_start(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk(KERN_DEBUG "S "));
set_pcf(adap, 1, I2C_PCF_START);
}
static void i2c_repstart(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk(" Sr "));
set_pcf(adap, 1, I2C_PCF_REPSTART);
}
static void i2c_stop(struct i2c_algo_pcf_data *adap)
{
- DEBPROTO(printk("P\n"));
set_pcf(adap, 1, I2C_PCF_STOP);
}
static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
{
- DEB2(printk(KERN_INFO
- "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
- *status));
/*
* Cleanup from LAB -- reset and enable ESO.
* This resets the PCF8584; since we've lost the bus, no
@@ -96,9 +73,6 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
if (adap->lab_mdelay)
mdelay(adap->lab_mdelay);
- DEB2(printk(KERN_INFO
- "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
- get_pcf(adap, 1)));
}
static int wait_for_bb(struct i2c_algo_pcf_data *adap)
@@ -155,56 +129,48 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
*
* vdovikin: added detect code for PCF8584
*/
-static int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
+static int pcf_init_8584(struct i2c_algo_pcf_data *adap)
{
unsigned char temp;
- DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
- get_pcf(adap, 1)));
-
/* S1=0x80: S0 selected, serial interface off */
set_pcf(adap, 1, I2C_PCF_PIN);
/*
* check to see S1 now used as R/W ctrl -
* PCF8584 does that when ESO is zero
*/
- if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if ((temp & 0x7f) != 0)
return -ENXIO; /* definitely not PCF8584 */
- }
/* load own address in S0, effective address is (own << 1) */
i2c_outb(adap, get_own(adap));
/* check it's really written */
- if ((temp = i2c_inb(adap)) != get_own(adap)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
+ temp = i2c_inb(adap);
+ if (temp != get_own(adap))
return -ENXIO;
- }
/* S1=0xA0, next byte in S2 */
set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
/* check to see S2 now selected */
- if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if ((temp & 0x7f) != I2C_PCF_ES1)
return -ENXIO;
- }
/* load clock register S2 */
i2c_outb(adap, get_clock(adap));
/* check it's really written, the only 5 lowest bits does matter */
- if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
+ temp = i2c_inb(adap);
+ if ((temp & 0x1f) != get_clock(adap))
return -ENXIO;
- }
/* Enable serial interface, idle, S0 selected */
set_pcf(adap, 1, I2C_PCF_IDLE);
/* check to see PCF is really idled and we can access status register */
- if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
+ temp = get_pcf(adap, 1);
+ if (temp != (I2C_PCF_PIN | I2C_PCF_BB))
return -ENXIO;
- }
printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
@@ -217,9 +183,7 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
int wrcount, status, timeout;
- for (wrcount=0; wrcount<count; ++wrcount) {
- DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
- buf[wrcount] & 0xff));
+ for (wrcount = 0; wrcount < count; ++wrcount) {
i2c_outb(adap, buf[wrcount]);
timeout = wait_for_pin(adap, &status);
if (timeout) {
@@ -254,7 +218,8 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
/* increment number of bytes to read by one -- read dummy byte */
for (i = 0; i <= count; i++) {
- if ((wfp = wait_for_pin(adap, &status))) {
+ wfp = wait_for_pin(adap, &status);
+ if (wfp) {
if (wfp == -EINTR)
return -EINTR; /* arbitration lost */
@@ -288,20 +253,14 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
}
-static int pcf_doAddress(struct i2c_algo_pcf_data *adap,
+static void pcf_send_address(struct i2c_algo_pcf_data *adap,
struct i2c_msg *msg)
{
- unsigned short flags = msg->flags;
- unsigned char addr;
+ unsigned char addr = i2c_8bit_addr_from_msg(msg);
- addr = msg->addr << 1;
- if (flags & I2C_M_RD)
- addr |= 1;
- if (flags & I2C_M_REV_DIR_ADDR)
+ if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
i2c_outb(adap, addr);
-
- return 0;
}
static int pcf_xfer(struct i2c_adapter *i2c_adap,
@@ -311,7 +270,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
struct i2c_msg *pmsg;
int i;
- int ret=0, timeout, status;
+ int timeout, status;
if (adap->xfer_begin)
adap->xfer_begin(adap->data);
@@ -319,20 +278,15 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
/* Check for bus busy */
timeout = wait_for_bb(adap);
if (timeout) {
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
- "Timeout waiting for BB in pcf_xfer\n");)
i = -EIO;
goto out;
}
- for (i = 0;ret >= 0 && i < num; i++) {
- pmsg = &msgs[i];
-
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
- pmsg->flags & I2C_M_RD ? "read" : "write",
- pmsg->len, pmsg->addr, i + 1, num);)
+ for (i = 0; i < num; i++) {
+ int ret;
- ret = pcf_doAddress(adap, pmsg);
+ pmsg = &msgs[i];
+ pcf_send_address(adap, pmsg);
/* Send START */
if (i == 0)
@@ -347,8 +301,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
goto out;
}
i2c_stop(adap);
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
- "for PIN(1) in pcf_xfer\n");)
i = -EREMOTEIO;
goto out;
}
@@ -356,35 +308,21 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap,
/* Check LRB (last rcvd bit - slave ack) */
if (status & I2C_PCF_LRB) {
i2c_stop(adap);
- DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
i = -EREMOTEIO;
goto out;
}
- DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
- i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
if (pmsg->flags & I2C_M_RD) {
ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
(i + 1 == num));
-
- if (ret != pmsg->len) {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
- "only read %d bytes.\n",ret));
- } else {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
- }
} else {
ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
(i + 1 == num));
-
- if (ret != pmsg->len) {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
- "only wrote %d bytes.\n",ret));
- } else {
- DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
- }
}
+
+ if (ret < 0)
+ goto out;
}
out:
@@ -401,8 +339,8 @@ static u32 pcf_func(struct i2c_adapter *adap)
/* exported algorithm data: */
static const struct i2c_algorithm pcf_algo = {
- .master_xfer = pcf_xfer,
- .functionality = pcf_func,
+ .xfer = pcf_xfer,
+ .functionality = pcf_func,
};
/*
@@ -413,12 +351,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
int rval;
- DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
-
/* register new adapter to i2c module... */
adap->algo = &pcf_algo;
- if ((rval = pcf_init_8584(pcf_adap)))
+ rval = pcf_init_8584(pcf_adap);
+ if (rval)
return rval;
rval = i2c_add_adapter(adap);
@@ -430,7 +367,3 @@ EXPORT_SYMBOL(i2c_pcf_add_bus);
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
MODULE_LICENSE("GPL");
-
-module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-pcf.h b/drivers/i2c/algos/i2c-algo-pcf.h
index 262ee801975b..2448ab192ce5 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.h
+++ b/drivers/i2c/algos/i2c-algo-pcf.h
@@ -1,18 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/* -------------------------------------------------------------------- */
/* i2c-pcf8584.h: PCF 8584 global defines */
/* -------------------------------------------------------------------- */
/* Copyright (C) 1996 Simon G. Vogl
1999 Hans Berglund
- 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. */
+ */
/* -------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl> */