While we have a local variable "buf_len" for dev->tx_buf_len, we don't
have such local variable for dev->tx_buf pointer. While "buf_len" is
restored at first then updated when we start processing a new i2c_msg
(determined by STATUS_WRITE_IN_PROGRESS flag), ->tx_buf is different.
Such inconsistency makes the code slightly hard to follow.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
We have some steps at the top of i2c_dw_xfer_msg() to set up a slave
address and enable DW I2C core. And it's executed only when we don't
have STATUS_WRITE_IN_PROGRESS.
But we need to make sure that STATUS_WRITE_IN_PROGRESS only indicates
that we have a pending i2c_msg to process. In other words, even if
STATUS_WRITE_IN_PROGRESS is not set, that doesn't mean we're at initial
state in the I2C transaction.
Since i2c_dw_xfer_msg() will be invoked again and again during a
transaction, those init steps have a possibility to be re-processed
needlessly. For example, this issue easily takes place when processing
a combined transaction with a certain condition (the number of tx bytes
in the first i2c_msg, equals to the Tx FIFO depth).
Consequently we should not use STATUS_WRITE_IN_PROGRESS to determine
where we're at in an I2C transaction. It would be better to separate
those initialization steps from i2c_dw_xfer_msg().
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Enable RX_FULL interrupt mask by default, and hook it in the interrupt
handler. If requested amount of rx data (defined by IC_RX_TL) is not
available, we don't have to process i2c_dw_read().
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
As a hardware feature, DW I2C core generates a STOP condition whenever
the Tx FIFO becomes empty (strictly speaking, whenever the last byte in
the Tx FIFO is sent out), even if we have more bytes to be written.
In other words, we must never make "Tx FIFO underrun" happen during
a transaction, except for the last byte. For the safety's sake, we'd
make TX_EMPTY interrupt get triggered every time one byte is processed.
The Rx FIFO threshold needs to be set as well.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
Symptom:
--------
When we're going to send/receive the longer size of data than the Tx
FIFO length, the I2C transaction will be divided into several separated
transactions, limited by the Tx FIFO length.
Details:
--------
As a hardware feature, DW I2C core generates a STOP condition whenever
the Tx FIFO becomes empty (strictly speaking, whenever the last byte in
the Tx FIFO is sent out), even if we have more bytes to be written.
Then, once a new transmit data is written to the Tx FIFO, DW I2C core
will initiate a new transaction, which leads to another START condition.
This explains how the transaction in question goes, and implies that
current tasklet-based dw_i2c_pump_msg() strategy couldn't meet the
timing constraint required for avoiding Tx FIFO underrun.
To avoid this scenario, we must keep providing new transmit data within
a given time period. In case of Fast-mode + 32-byte Tx FIFO, for
instance, it takes about 22.5[us] to process single byte, and 720[us] in
total.
This patch removes the existing tasklet-based "pump" system, and move
its jobs into the interrupt handler.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
In case a work-in-progress i2c_msg has more bytes to be written, we
need to set STATUS_WRITE_IN_PROGRESS and exit from the msg_write_idx-
searching loop. Otherwise, we will overtake the current msg_write_idx
without waiting for its transmission to be processed.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
* Calculate with accurate conditional expressions from DW manuals.
* Round ic_clk by adding 0.5 as it's important at high ic_clk rate.
* Take into account "tHD;STA" issue for _HCNT calculation.
* Take into account "tf" for _LCNT calculation.
* Add "cond" and "offset" fot further correction requirements.
For _HCNT calculation, there's one issue needs to be carefully
considered; DesignWare I2C core doesn't seem to have solid strategy
to meet the tHD;STA timing spec. If you configure _HCNT based on the
tHIGH timing spec, it easily results in violation of the tHD;STA spec.
After many trials, we came to the conclusion that the tHD;STA period
is proportional to (_HCNT + 3). For the safety's sake, this should be
selected by default.
As for _LCNT calculation, DW I2C core has one characteristic behavior;
he starts counting the SCL CNTs for the LOW period of the SCL clock
(tLOW) as soon as it pulls the SCL line. At that time, he doesn't take
into account the fall time of SCL signal (tf), IOW, he starts counting
CNTs without confirming the SCL input voltage has dropped to below VIL.
This characteristics becomes a problem on some platforms where tf is
considerably long, and results in violation of the tLOW timing spec.
To make the driver configurable as much as possible for various cases,
we'd have separated arguments "tf" and "offset", and for safety default
values should be 0.3 us and 0, respectively.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
We couldn't know the original intent for this variable, but at this
point it's useless.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
We don't have to use "struct i2c_adapter" pointer here.
Let's use a local "struct dw_i2c_dev" pointer, instead.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
We don't have to use "struct i2c_adapter" pointer here.
Let's use a local "struct dw_i2c_dev" pointer, instead.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
We're strongly discouraged from using the IC_CLR_INTR register because
it clears all software-clearable interrupts asserted at the moment.
stat = readl(IC_INTR_STAT);
:
: <=== Interrupts asserted during this period will be lost
:
readl(IC_CLR_INTR);
Instead, use the separately-prepared IC_CLR_* registers.
At the same time, this patch adds all remaining interrupt definitions
available in the DesignWare I2C hardware.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
This driver looks originally meant for armel machines where readw()/
writew() works perfectly fine with this hardware. But that doens't
work for big-endian systems.
This patch converts all 8/16-bit-aware usages to 32-bit variants.
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi@necel.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>
The i2c Linux driver for the DesignWare i2c block of Synopsys, which is meant
for AMBA Peripheral Bus. This i2c block is used on SoC chips like the ARM9
based PVG610.
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Ben Dooks <ben-linux@fluff.org>