Commit 8b7a486f authored by Alessandro Rubini's avatar Alessandro Rubini

kernel/spec-i2c: bugfix: add delays in bitbanging i2c

This is a long-standing bug, and completely my fault.  Since our i2c
is simply a bitbanging gpio-based interface, I need to add some delays
into the operations.  Without this, accessing eeprom worked with most
mezzanines but not with all of them. The measured speed was more than 1MHz.

The devices are rated at 400kHz, so delay 1.25 usecs at each output
operation (thus, writing is three such delay for each bit).  Addin the
unpredictable software delays I see slightly more than than 200kHz
in my test system.

The driver now takes 2.5s to read the whole eeprom, but there's ample
space to make it better by fixing the FIXME in spec-i2c.c .
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 210ba8b0
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fmc.h> #include <linux/fmc.h>
#include "spec.h" #include "spec.h"
#include "hw/wrc_syscon_regs.h" #include "hw/wrc_syscon_regs.h"
...@@ -45,6 +46,7 @@ static void set_sda(struct fmc_device *fmc, int val) ...@@ -45,6 +46,7 @@ static void set_sda(struct fmc_device *fmc, int val)
fmc_writel(fmc, SYSC_GPSR_FMC_SDA, SYSC_REG_GPSR); fmc_writel(fmc, SYSC_GPSR_FMC_SDA, SYSC_REG_GPSR);
else else
fmc_writel(fmc, SYSC_GPCR_FMC_SDA, SYSC_REG_GPCR); fmc_writel(fmc, SYSC_GPCR_FMC_SDA, SYSC_REG_GPCR);
ndelay(1250); /* 400kHz -> 2.5us/loop */
} }
static void set_scl(struct fmc_device *fmc, int val) static void set_scl(struct fmc_device *fmc, int val)
...@@ -53,6 +55,7 @@ static void set_scl(struct fmc_device *fmc, int val) ...@@ -53,6 +55,7 @@ static void set_scl(struct fmc_device *fmc, int val)
fmc_writel(fmc, SYSC_GPSR_FMC_SCL, SYSC_REG_GPSR); fmc_writel(fmc, SYSC_GPSR_FMC_SCL, SYSC_REG_GPSR);
else else
fmc_writel(fmc, SYSC_GPCR_FMC_SCL, SYSC_REG_GPCR); fmc_writel(fmc, SYSC_GPCR_FMC_SCL, SYSC_REG_GPCR);
ndelay(1250); /* 400kHz -> 2.5us/loop */
} }
static int get_sda(struct fmc_device *fmc) static int get_sda(struct fmc_device *fmc)
......
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