Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/i2c ssdfb: fix i2c transfer error with some controllers
details: https://anonhg.NetBSD.org/src/rev/503a0778b2b2
branches: trunk
changeset: 846216:503a0778b2b2
user: tnn <tnn%NetBSD.org@localhost>
date: Tue Nov 05 19:59:35 2019 +0000
description:
ssdfb: fix i2c transfer error with some controllers
If the controller doesn't support the full 128 byte transfer size we need,
then split the write across multiple transactions.
diffstat:
sys/dev/i2c/ssdfb_i2c.c | 82 ++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 68 insertions(+), 14 deletions(-)
diffs (152 lines):
diff -r 529f81ac1a22 -r 503a0778b2b2 sys/dev/i2c/ssdfb_i2c.c
--- a/sys/dev/i2c/ssdfb_i2c.c Tue Nov 05 12:59:54 2019 +0000
+++ b/sys/dev/i2c/ssdfb_i2c.c Tue Nov 05 19:59:35 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ssdfb_i2c.c,v 1.4 2019/11/02 14:23:59 tnn Exp $ */
+/* $NetBSD: ssdfb_i2c.c,v 1.5 2019/11/05 19:59:35 tnn Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ssdfb_i2c.c,v 1.4 2019/11/02 14:23:59 tnn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ssdfb_i2c.c,v 1.5 2019/11/05 19:59:35 tnn Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -43,12 +43,16 @@
struct ssdfb_softc sc;
i2c_tag_t sc_i2c_tag;
i2c_addr_t sc_i2c_addr;
+ size_t sc_transfer_size;
};
static int ssdfb_i2c_match(device_t, cfdata_t, void *);
static void ssdfb_i2c_attach(device_t, device_t, void *);
static int ssdfb_i2c_detach(device_t, int);
+static int ssdfb_i2c_probe_transfer_size(struct ssdfb_i2c_softc *, bool);
+static int ssdfb_i2c_transfer(struct ssdfb_i2c_softc *, uint8_t, uint8_t *,
+ size_t, int);
static int ssdfb_i2c_cmd(void *, uint8_t *, size_t, bool);
static int ssdfb_i2c_transfer_rect(void *, uint8_t, uint8_t, uint8_t,
uint8_t, uint8_t *, size_t, bool);
@@ -132,6 +136,61 @@
}
static int
+ssdfb_i2c_probe_transfer_size(struct ssdfb_i2c_softc *sc, bool usepoll)
+{
+ int flags = usepoll ? I2C_F_POLL : 0;
+ uint8_t cb = SSDFB_I2C_CTRL_BYTE_DATA_MASK;
+ int error;
+ uint8_t buf[128];
+ size_t len;
+
+ error = iic_acquire_bus(sc->sc_i2c_tag, flags);
+ if (error)
+ return error;
+ len = sizeof(buf);
+ memset(buf, 0, len);
+ while (len > 0) {
+ error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_i2c_addr, &cb, sizeof(cb), buf, len, flags);
+ if (!error) {
+ break;
+ }
+ len >>= 1;
+ }
+ if (!error && len < 2) {
+ error = E2BIG;
+ } else {
+ sc->sc_transfer_size = len;
+ }
+ (void) iic_release_bus(sc->sc_i2c_tag, flags);
+
+ return error;
+}
+
+static int
+ssdfb_i2c_transfer(struct ssdfb_i2c_softc *sc, uint8_t cb, uint8_t *data,
+ size_t len, int flags)
+{
+ int error;
+ size_t xfer_size = sc->sc_transfer_size;
+
+ while (len >= xfer_size) {
+ error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_i2c_addr, &cb, sizeof(cb), data, xfer_size, flags);
+ if (error)
+ return error;
+ len -= xfer_size;
+ data += xfer_size;
+ }
+ if (len > 0) {
+ error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
+ sc->sc_i2c_addr, &cb, sizeof(cb), data, len, flags);
+ }
+
+ return error;
+}
+
+static int
ssdfb_i2c_cmd(void *cookie, uint8_t *cmd, size_t len, bool usepoll)
{
struct ssdfb_i2c_softc *sc = (struct ssdfb_i2c_softc *)cookie;
@@ -154,9 +213,6 @@
uint8_t frompage, uint8_t topage, uint8_t *p, size_t stride, bool usepoll)
{
struct ssdfb_i2c_softc *sc = (struct ssdfb_i2c_softc *)cookie;
- int flags = usepoll ? I2C_F_POLL : 0;
- uint8_t cb = SSDFB_I2C_CTRL_BYTE_DATA_MASK;
- uint8_t data[] = {0, 0, 0};
uint8_t cmd[2];
int error;
@@ -177,13 +233,12 @@
}
if (sc->sc.sc_transfer_rect != ssdfb_smbus_transfer_rect) {
- error = iic_acquire_bus(sc->sc_i2c_tag, flags);
+ error = ssdfb_i2c_probe_transfer_size(sc, usepoll);
if (error)
return error;
- error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
- sc->sc_i2c_addr, &cb, sizeof(cb), data, sizeof(data), flags);
- (void) iic_release_bus(sc->sc_i2c_tag, flags);
- if (error) {
+ aprint_verbose_dev(sc->sc.sc_dev, "%zd-byte transfers\n",
+ sc->sc_transfer_size);
+ if (sc->sc_transfer_size == 2) {
sc->sc.sc_transfer_rect = ssdfb_smbus_transfer_rect;
}
}
@@ -238,8 +293,7 @@
if (error)
goto out;
while (frompage <= topage) {
- error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
- sc->sc_i2c_addr, &cb, sizeof(cb), p, len, flags);
+ error = ssdfb_i2c_transfer(sc, cb, p, len, flags);
if (error)
goto out;
frompage++;
@@ -278,8 +332,7 @@
sc->sc_i2c_addr, &cc, sizeof(cc), cmds, sizeof(cmds), flags);
if (error)
goto out;
- error = iic_exec(sc->sc_i2c_tag, I2C_OP_WRITE_WITH_STOP,
- sc->sc_i2c_addr, &cb, sizeof(cb), p, len, flags);
+ error = ssdfb_i2c_transfer(sc, cb, p, len, flags);
if (error)
goto out;
frompage++;
@@ -364,5 +417,6 @@
}
out:
(void) iic_release_bus(sc->sc_i2c_tag, flags);
+
return error;
}
Home |
Main Index |
Thread Index |
Old Index