• Louis Chauvet's avatar
    spi: atmel: Fix clock issue when using devices with different polarities · fc70d643
    Louis Chauvet authored
    The current Atmel SPI controller driver (v2) behaves incorrectly when
    using two SPI devices with different clock polarities and GPIO CS.
    
    When switching from one device to another, the controller driver first
    enables the CS and then applies whatever configuration suits the targeted
    device (typically, the polarities). The side effect of such order is the
    apparition of a spurious clock edge after enabling the CS when the clock
    polarity needs to be inverted wrt. the previous configuration of the
    controller.
    
    This parasitic clock edge is problematic when the SPI device uses that edge
    for internal processing, which is perfectly legitimate given that its CS
    was asserted. Indeed, devices such as HVS8080 driven by driver gpio-sr in
    the kernel are shift registers and will process this first clock edge to
    perform a first register shift. In this case, the first bit gets lost and
    the whole data block that will later be read by the kernel is all shifted
    by one.
    
        Current behavior:
          The actual switching of the clock polarity only occurs after the CS
          when the controller sends the first message:
    
        CLK ------------\   /-\ /-\
                        |   | | | |    . . .
                        \---/ \-/ \
        CS  -----\
                 |
                 \------------------
    
                 ^      ^   ^
                 |      |   |
                 |      |   Actual clock of the message sent
                 |      |
                 |      Change of clock polarity, which occurs with the first
                 |      write to the bus. This edge occurs when the CS is
                 |      already asserted, and can be interpreted as
                 |      the first clock edge by the receiver.
                 |
                 GPIO CS toggle
    
    This issue is specific to this controller because while the SPI core
    performs the operations in the right order, the controller however does
    not. In practice, the controller only applies the clock configuration right
    before the first transmission.
    
    So this is not a problem when using the controller's dedicated CS, as the
    controller does things correctly, but it becomes a problem when you need to
    change the clock polarity and use an external GPIO for the CS.
    
    One possible approach to solve this problem is to send a dummy message
    before actually activating the CS, so that the controller applies the clock
    polarity beforehand.
    
    New behavior:
    
    CLK     ------\      /-\     /-\      /-\     /-\
                  |      | | ... | |      | | ... | |
                  \------/ \-   -/ \------/ \-   -/ \------
    
    CS      -\/-----------------------\
             ||                       |
             \/                       \---------------------
             ^    ^       ^           ^    ^
             |    |       |           |    |
             |    |       |           |    Expected clock cycles when
             |    |       |           |    sending the message
             |    |       |           |
             |    |       |           Actual GPIO CS activation, occurs inside
             |    |       |           the driver
             |    |       |
             |    |       Dummy message, to trigger clock polarity
             |    |       reconfiguration. This message is not received and
             |    |       processed by the device because CS is low.
             |    |
             |    Change of clock polarity, forced by the dummy message. This
             |    time, the edge is not detected by the receiver.
             |
             This small spike in CS activation is due to the fact that the
             spi-core activates the CS gpio before calling the driver's
             set_cs callback, which deactivates this gpio again until the
             clock polarity is correct.
    
    To avoid having to systematically send a dummy packet, the driver keeps
    track of the clock's current polarity. In this way, it only sends the dummy
    packet when necessary, ensuring that the clock will have the correct
    polarity when the CS is toggled.
    
    There could be two hardware problems with this patch:
    1- Maybe the small CS activation peak can confuse SPI devices
    2- If on a design, a single wire is used to select two devices depending
    on its state, the dummy message may disturb them.
    
    Fixes: 5ee36c98 ("spi: atmel_spi update chipselect handling")
    Cc:  <stable@vger.kernel.org>
    Signed-off-by: default avatarLouis Chauvet <louis.chauvet@bootlin.com>
    Link: https://msgid.link/r/20231204154903.11607-1-louis.chauvet@bootlin.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
    fc70d643
spi-atmel.c 45.8 KB