Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use i2c-bcm2835 as default #1716

Merged
merged 13 commits into from
Nov 13, 2016

Conversation

notro
Copy link
Contributor

@notro notro commented Nov 11, 2016

I have submitted some patches upstream (now in linux-next) which tries to bring i2c-bcm2835 up to speed so we can start to use it. And the only way to know if it really can replace i2c-bcm2708 is to make it default, since "no one" will try it otherwise.

I have added a debug patch that hopefully can be of aid in tracking down the cause if some device stops working.

There's one thing missing here and that's a fallback to i2c-bcm2708. Initially I planned to make a i2c-bcm2708-overlay.dts, but we have i2c{0,1}-bcm2708-overlay.dts, so I'm not sure what to do.

Writing messages larger than the FIFO size results in a hang, rendering
the machine unusable. This is because the RXD status flag is set on the
first interrupt which results in bcm2835_drain_rxfifo() stealing bytes
from the buffer. The controller continues to trigger interrupts waiting
for the missing bytes, but bcm2835_fill_txfifo() has none to give.
In this situation wait_for_completion_timeout() apparently is unable to
stop the madness.

The BCM2835 ARM Peripherals datasheet has this to say about the flags:
  TXD: is set when the FIFO has space for at least one byte of data.
  RXD: is set when the FIFO contains at least one byte of data.
  TXW: is set during a write transfer and the FIFO is less than full.
  RXR: is set during a read transfer and the FIFO is or more full.

Implementing the logic from the downstream i2c-bcm2708 driver solved
the hang problem.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
If an unexpected TXW or RXR interrupt occurs (msg_buf_remaining == 0),
the driver has no way to fill/drain the FIFO to stop the interrupts.
In this case the controller has to be disabled and the transfer
completed to avoid hang.

(CLKT | ERR) and DONE interrupts are completed in their own paths, and
the controller is disabled in the transfer function after completion.
Unite the code paths and do disabling inside the interrupt routine.

Clear interrupt status bits in the united completion path instead of
trying to do it on every interrupt which isn't necessary.
Only CLKT, ERR and DONE can be cleared that way.

Add the status value to the error value in case of TXW/RXR errors to
distinguish them from the other S_LEN error.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Writing to an AT24C32 generates on average 2x i2c transfer errors per
32-byte page write. Which amounts to a lot for a 4k write. This is due
to the fact that the chip doesn't respond during it's internal write
cycle when the at24 driver tries and retries the next write.
Only a handful drivers use dev_err() on transfer error, so switch to
dev_dbg() instead.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
The controller can't support this flag, so remove it.

Documentation/i2c/i2c-protocol states that all of the message is sent:

I2C_M_IGNORE_NAK:
    Normally message is interrupted immediately if there is [NA] from the
    client. Setting this flag treats any [NA] as [A], and all of
    message is sent.

From the BCM2835 ARM Peripherals datasheet:

    The ERR field is set when the slave fails to acknowledge either
    its address or a data byte written to it.

So when the controller doesn't receive an ack, it sets ERR and raises
an interrupt. In other words, the whole message is not sent.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Documentation/i2c/i2c-protocol states that Combined transactions should
separate messages with a Start bit and end the whole transaction with a
Stop bit. This patch adds support for issuing only a Start between
messages instead of a Stop followed by a Start.

This implementation differs from downstream i2c-bcm2708 in 2 respects:
- it uses an interrupt to detect that the transfer is active instead
  of using polling. There is no interrupt for Transfer Active, but by
  not prefilling the FIFO it's possible to use the TXW interrupt.
- when resetting/disabling the controller between transfers it writes
  CLEAR to the control register instead of just zero.
  Using just zero gave many errors. This might be the reason why
  downstream had to disable this feature and make it available with a
  module parameter.

I have run thousands of transfers to a DS1307 (rtc), MMA8451 (accel)
and AT24C32 (eeprom) in parallel without problems.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Acked-by: Eric Anholt <eric@anholt.net>
Use i2c_adapter->timeout for the completion timeout value. The core
default is 1 second.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Support a dynamic clock by reading the frequency and setting the
divisor in the transfer function instead of during probe.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Martin Sperl <kernel@martin.sperl.org>
This adds a debug module parameter to aid in debugging transfer issues
by printing info to the kernel log. When enabled, status values are
collected in the interrupt routine and msg info in
bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid
affecting timing. Having printk in the isr can mask issues.

debug values (additive):
1: Print info on error
2: Print info on all transfers
3: Print messages before transfer is started

The value can be changed at runtime:
/sys/module/i2c_bcm2835/parameters/debug

Example output, debug=3:
[  747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
[  747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
[  747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1]
[  747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE  [i2c1]
[  747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1]
[  747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD  [i2c1]
[  747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD  [i2c1]
[  747.117870] isr: remain=8, status=0x32 : DONE TXD RXD  [i2c1]

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
i2c-bcm2835 has gotten an overhaul so we can now use as default.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
@pelwell
Copy link
Contributor

pelwell commented Nov 11, 2016

For the overlay, use target = <&i2c_arm>;, and call it i2c-bcm2708. The other overlays, which allow different pins to be used, will be misnamed, but that isn't a big problem.

@notro
Copy link
Contributor Author

notro commented Nov 11, 2016

Added i2c-bcm2708 fallback overlay

Copy link
Contributor

@pelwell pelwell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two nitpicks.

@@ -520,6 +520,12 @@ Params: ds1307 Select the DS1307 device
source


Name: i2c-bcm2708
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As with the Makefile, this item needs to move before i2c-gpio.

@@ -41,6 +41,7 @@ dtbo-$(RPI_DT_OVERLAYS) += i2c-gpio.dtbo
dtbo-$(RPI_DT_OVERLAYS) += i2c-mux.dtbo
dtbo-$(RPI_DT_OVERLAYS) += i2c-pwm-pca9685a.dtbo
dtbo-$(RPI_DT_OVERLAYS) += i2c-rtc.dtbo
dtbo-$(RPI_DT_OVERLAYS) += i2c-bcm2708.dtbo
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, notro, my script complains this entry should come before i2c-gpio.

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
@notro
Copy link
Contributor Author

notro commented Nov 11, 2016

Fixed

@pelwell
Copy link
Contributor

pelwell commented Nov 12, 2016

My alphabet looks a bit different - I've pushed some changes to be squashed.

@notro
Copy link
Contributor Author

notro commented Nov 12, 2016

Sorry, the hyphen messed up my head. Can you squash this when pulling/merging?

@pelwell
Copy link
Contributor

pelwell commented Nov 12, 2016

If I go through github we can only merge as-is or squash down to one. Since most of these are upstream patches, it's easier if we keep them separate. If we are in agreement to apply your patches, we can always squash and apply them manually.

@popcornmix
Copy link
Collaborator

@pelwell okay to merge this?
There is a rebase to 4.8.7 coming so I can squash the commits then.

@pelwell
Copy link
Contributor

pelwell commented Nov 13, 2016

I've not had chance to test the new code, but my tests would be limited anyway and I trust @notro. Yes, no objections.

@popcornmix popcornmix merged commit 235e57a into raspberrypi:rpi-4.8.y Nov 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants