\documentclass[aspectratio=169,obeyspaces,spaces,hyphens,dvipsnames,handout]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}% http://ctan.org/pkg/lm
\usepackage{minted}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage[normalem]{ulem}

\mode<presentation>
\usetheme{Bootlin}

\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
  \hbox{}\nobreak\hfil(#1)
  \parfillskip=0pt \finalhyphendemerits=0 \endgraf}}

\newsavebox\mybox
\newenvironment{aquote}[1]
  {\savebox\mybox{#1}\begin{quotation}}
  {\signed{\usebox\mybox}\end{quotation}}

\title{Basics of I²C on Linux}
\authors{Luca Ceresoli}
\email{luca.ceresoli@bootlin.com}
\slidesurl{https://bootlin.com/pub/conferences/}
\institute{Bootlin}
\conference{Embedded Linux Conference Europe 2022}

\begin{document}

\addtocontents{toc}{\protect\setcounter{tocdepth}{-1}}
\section{Basics of I²C on Linux}
\addtocontents{toc}{\protect\setcounter{tocdepth}{2}}

\begin{frame}{Luca Ceresoli}
  \begin{itemize}
  \item Embedded Linux engineer at {\bf Bootlin}
    \begin{itemize}
    \item Embedded Linux experts
    \item Engineering services: Linux BSP development, kernel porting
      and drivers, Yocto/Buildroot integration, real-time, boot-time,
      security, multimedia
    \item Training services: Embedded Linux, Linux kernel drivers,
      Yocto, Buildroot, graphics stack, boot-time, real-time
    \end{itemize}
  \item Linux kernel and bootloader development, Buildroot and
    Yocto integration
  \item Open-source contributor
  \item Living in {\bf Bergamo}, Italy
  \item \code{luca.ceresoli@bootlin.com}
  \end{itemize}
  {\small \url{https://bootlin.com/company/staff/luca-ceresoli/}}
\end{frame}

\subsection{What is I²C}

\begin{frame}{What is I²C}
  \begin{center}
    \includegraphics[width=0.6\textwidth]{i2c_bus.pdf}
    {\tiny\break\url{https://docs.kernel.org/i2c/summary.html}}
  \end{center}
  \begin{itemize}
    \item A bus for Inter-Integrated-Circuit communication
    \item Design for hardware simplicity: 2 wires, many chips per bus, flexible
    \item Not discoverable, not plug-and-play
    \item Low speed: 100-400 kHz (with 1 MHz and 3.4 MHz extensions)
    \item Also known as: I2C, IIC, TWI, TWSI, \dots
    \item \url{https://en.wikipedia.org/wiki/I²C}
    \item \url{https://docs.kernel.org/i2c/}
  \end{itemize}
\end{frame}

\begin{frame}{Roles}
  \begin{center}
    \includegraphics[width=0.6\textwidth]{i2c_bus.pdf}
    {\tiny\break\url{https://docs.kernel.org/i2c/summary.html}}
  \end{center}
  \begin{columns}
    \column{0.5\textwidth}
    {\bf Adapter}
      \begin{itemize}
        \item Other names: Master, Controller, bus
        \item Initiates all transactions
        \item Usually one (multimaster possible)
        \item Has no address \break
      \end{itemize}
    \column{0.5\textwidth}
    {\bf Client}
      \begin{itemize}
         \item Other names: Slave, Device
        \item Responds to transactions
        \item Many per bus
        \item 7-bit address set in hardware \break
          (10-bit extension)
      \end{itemize}
  \end{columns}
\end{frame}

\begin{frame}{Two wires}
  \begin{center}
    \includegraphics[width=0.6\textwidth]{i2c_bus.pdf}
    {\tiny\break\url{https://docs.kernel.org/i2c/summary.html}}
  \end{center}
  \begin{itemize}
    \item Two wires
      \begin{itemize}
      \item SDA: data, bidirectional
      \item SCL: ``clock''
        \begin{itemize}
          \item Not really a clock
          \item SDA moved at SCL falling edge, SDA read at SCL rising edge
          \item Mostly driven by adapter, sometimes also by clients (clock stretching)
        \end{itemize}
      \end{itemize}
    \item Open collector
  \end{itemize}
\end{frame}

\begin{frame}{Communication protocol}
  \begin{center}
    \includegraphics[width=0.9\textwidth]{i2c-byte-transfer.pdf}
  \end{center}
  \begin{enumerate}
    \pause
    \item Start condition
    \pause
    \item Adapter sends: client address (7 bit) + direction bit (R/W)
    \pause
    \item Client sends ACK
    \pause
    \item Client sends one byte
    \pause
    \item Adapter sends ACK
    \pause
    \item Stop condition
  \end{enumerate}
\end{frame}

\begin{frame}{The SMBus protocol}
  \begin{itemize}
    \item Designed for chip communication on PC motherboards
      \item Mostly a subset of I²C
      \item Defines several commands
      \begin{itemize}
        \item Register write: S addr+W A reg A data P
        \item Register read: S addr+W A reg A RS addr+R A data NA P
      \end{itemize}
    \item Often I²C and SMBus clients can be mixed on the same bus
      \begin{itemize}
        \item Linux recommends using SMBus APIs for I²C chips when possible
      \end{itemize}
      \item \url{https://en.wikipedia.org/wiki/System_Management_Bus}
  \end{itemize}
\end{frame}

\subsection{I²C in the Linux Driver Model}

\begin{frame}{The I2C subsystem in the linux kernel}
  \begin{center}
    \includegraphics[height=0.8\textheight]{driver-model-calls.pdf}
  \end{center}
\end{frame}

\begin{frame}[fragile]{Sysfs view}

  I2C ``Devices'' includes both adapters and clients:

  \begin{block}{}
    \fontsize{8}{8}\selectfont
    \begin{minted}{shell}
# ls -l /sys/bus/i2c/devices/
lrwxrwxrwx ... 0-0039 -> ../../../devices/platform/soc/40012000.i2c/i2c-0/0-0039
lrwxrwxrwx ... 0-004a -> ../../../devices/platform/soc/40012000.i2c/i2c-0/0-004a
lrwxrwxrwx ... 1-0052 -> ../../../devices/platform/soc/40015000.i2c/i2c-1/1-0052
lrwxrwxrwx ... 2-0028 -> ../../../devices/platform/soc/5c002000.i2c/i2c-2/2-0028
lrwxrwxrwx ... 2-0033 -> ../../../devices/platform/soc/5c002000.i2c/i2c-2/2-0033
lrwxrwxrwx ... i2c-0 -> ../../../devices/platform/soc/40012000.i2c/i2c-0
lrwxrwxrwx ... i2c-1 -> ../../../devices/platform/soc/40015000.i2c/i2c-1
lrwxrwxrwx ... i2c-2 -> ../../../devices/platform/soc/5c002000.i2c/i2c-2
lrwxrwxrwx ... i2c-3 -> ../../../devices/platform/soc/40012000.i2c/i2c-0/i2c-3
    \end{minted}
  \end{block}
\end{frame}

\subsection{Device Tree}

\begin{frame}[fragile]{Device tree example}
  \begin{block}{\code{arch/arm/boot/dts/stm32mp15xx-dkx.dtsi}}
    \fontsize{8}{8}\selectfont
    \begin{minted}{dts}
&i2c4 {
    i2c-scl-rising-time-ns = <185>;
    i2c-scl-falling-time-ns = <20>;
    clock-frequency = <400000>;
    status = "okay";
    // ...

    stusb1600@28 {
        compatible = "st,stusb1600";
        reg = <0x28>;
        interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
        interrupt-parent = <&gpioi>;
        pinctrl-names = "default";
        pinctrl-0 = <&stusb1600_pins_a>;
        status = "okay";
        // ...
    };

    pmic: stpmic@33 {
        compatible = "st,stpmic1";
        reg = <0x33>;
        // ...
    }
}
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}{More properties}
  \begin{itemize}
    \item Adapter node
      \begin{itemize}
        \item {\tt compatible}
        \item {\tt \#address-cells = <1>} (1 address number per client chip)
        \item {\tt \#size-cells = <0>}    (no size  numbers per client chip)
        \item Optional: {\tt clock-frequency} (frequency of bus clock in Hz)
        \item Optional: {\tt i2c-scl-falling-time-ns}, {\tt i2c-sda-falling-time-ns}, \dots
        \item Optional: {\tt scl-gpios}, {\tt sda-gpios}: for GPIO bus recovery
        \item Optional: {\tt single-master} or {\tt multi-master}
        \item Adapter-specific properties
        \item \dots
        \item One subnode per client chip
          \begin{itemize}
            \item {\tt reg = <}{\em client address}{\tt >} (Look for ``Slave address'' on the datasheet)
            \item {\tt compatible}
            \item Client-specific properties
          \end{itemize}
      \end{itemize}
    \item See
      \href{https://www.kernel.org/doc/Documentation/devicetree/bindings/i2c/i2c.txt}
           {Documentation/devicetree/bindings/i2c/i2c.txt}
  \end{itemize}
\end{frame}

\subsection{Writing {\em client} device drivers}

\begin{frame}[fragile]{Client device driver: declare the driver}
  \begin{block}{\code{drivers/gpio/gpio-pca9570.c}}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static struct i2c_driver pca9570_driver = {
    .driver = {
        .name = "pca9570",
        .of_match_table = pca9570_of_match_table, // --> see later
    },
    .id_table = pca9570_id_table, // --> see later
    .probe_new = pca9570_probe, // --> see later
};
module_i2c_driver(pca9570_driver);
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Client device driver: i2c and device tree tables}
  \begin{block}{\code{drivers/gpio/gpio-pca9570.c}}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static const struct i2c_device_id pca9570_id_table[] = {
    { "pca9570", 4 },
    { "pca9571", 8 },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);

static const struct of_device_id pca9570_of_match_table[] = {
    { .compatible = "nxp,pca9570", .data = (void *)4 },
    { .compatible = "nxp,pca9571", .data = (void *)8 },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Client device driver: probe function}
  \begin{block}{\code{drivers/gpio/gpio-pca9570.c}}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static int pca9570_probe(struct i2c_client *client)
{
    struct pca9570 *gpio;

    gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
    if (!gpio)
        return -ENOMEM;

    gpio->chip.get = pca9570_get; // --> see later
    gpio->chip.set = pca9570_set; // --> see later
    // ...

    i2c_set_clientdata(client, gpio);

    return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
}
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Client device driver: recap}
  \begin{block}{\code{drivers/gpio/gpio-pca9570.c}}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static int pca9570_probe(struct i2c_client *client)
{
    // 1. allocate driver-specific struct
    // 2. fill it
    // 3. device-specific initializations
    // 4. i2c_set_clientdata(client, <driver-specific struct>)
    // 5. register to appropriate subsystem (GPIO, RTC, input, IIO, ...)
}

// 6. Describe i2c device in struct i2c table and device tree table
// 7. Describe driver in a struct i2c_driver
// 8. module_i2c_driver(): declare the driver
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{Client device driver: requesting I²C transactions}
  \begin{block}{\code{drivers/gpio/gpio-pca9570.c} (simplified)}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static void pca9570_set(struct gpio_chip *chip, unsigned offset, int value)
{
    struct pca9570 *gpio = gpiochip_get_data(chip);
    struct i2c_client *client = to_i2c_client(gpio->chip.parent);
    u8 buffer;

    buffer = /* chip-specific code */;

    i2c_smbus_write_byte(client, buffer);
}
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}{Requesting I²C transactions}
  \begin{itemize}
    \item Simple buffer transfer
      \begin{itemize}
        \item \code{i2c_smbus_write_byte()}: send one byte
        \item \code{i2c_smbus_read_byte()}:  receive one byte
        \item \code{i2c_master_send()}: send multiple bytes
        \item \code{i2c_master_recv()}: receive multiple bytes
      \end{itemize}
      \pause
    \item Register-like access
      \begin{itemize}
        \item \code{i2c_smbus_write_byte_data()}: write a register
        \item \code{i2c_smbus_read_byte_data()}:  read a register
        \item Plus variants transferring words or buffers
      \end{itemize}
      \pause
    \item And more, see:
      \begin{itemize}
        \item \url{https://docs.kernel.org/i2c/i2c-protocol.html}
        \item \url{https://docs.kernel.org/i2c/smbus-protocol.html}
      \end{itemize}
      \pause
    \item \dots or use \code{i2c_transfer()}, the ``swiss army knife of
      Linux I2C''
      \begin{itemize}
        \item Makes any number of transfers
        \item Does repeated start by default
        \item Various flags to tweak its behaviour
      \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile] {\code{i2c_transfer()}}
  \begin{block}{\code{sound/soc/codecs/adau1701.c} (simplified)}
    \fontsize{9}{9}\selectfont
    \begin{minted}{c}
static int adau1701_reg_read(void *context, unsigned int reg, unsigned int *value)
{
    uint8_t send_buf[2], recv_buf[3];
    struct i2c_msg msgs[2];

    msgs[0].addr = client->addr;
    msgs[0].len = sizeof(send_buf);
    msgs[0].buf = send_buf; // pre-filled
    msgs[0].flags = 0; // Write transaction by default

    msgs[1].addr = client->addr;
    msgs[1].len = size;
    msgs[1].buf = recv_buf;
    msgs[1].flags = I2C_M_RD; // Read transaction

    ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
    if (ret < 0)                       return ret;
    else if (ret != ARRAY_SIZE(msgs))  return -EIO;
}
    \end{minted}
  \end{block}
\end{frame}

\subsection{Userspace tools}

\begin{frame}{I2C from userspace}
  \begin{itemize}
    \item The first rule about I2C from userspace:
      \pause
    \item Do not use I2C from userspace
      \pause
      \item Use the RTC/ALSA/IIO device instead, I2C is just to get you there
  \end{itemize}
\end{frame}

\begin{frame}{i2c-tools}
  \begin{itemize}
    \item The \code{i2c-tools} package provides tools to access I²C on the
      command line
    \item Useful for debugging, testing, some simple prototyping
    \item Accesses the I²C bus via \code{/dev/i2c-0}, \code{/dev/i2c-1}\dots
    \item Assume devices have registers, SMBus-like
    \item \code{WARNING! This program can confuse your I2C bus, cause data loss and worse!}
    \item \url{https://i2c.wiki.kernel.org/index.php/I2C_Tools}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{\code{i2cdetect}}

  \begin{itemize}
    \item \code{i2cdetect}: detect devices on a bus
    \item No guarantee it works (I²C is not discoverable by the spec)
  \end{itemize}

  \begin{columns}
    \column{0.62\textwidth}

  \begin{block}{}
    \fontsize{9}{9}\selectfont
    \begin{minted}{shell}
# i2cdetect -l
i2c-0   i2c   STM32F7 I2C(0x40012000)    I2C adapter
i2c-1   i2c   STM32F7 I2C(0x40015000)    I2C adapter
i2c-2   i2c   STM32F7 I2C(0x5c002000)    I2C adapter
i2c-3   i2c   i2c-0-mux (chan_id 0)      I2C adapter
# i2cdetect -y 2
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- 28 -- -- -- -- -- -- --
30: -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
#
    \end{minted}
  \end{block}
  \column{0.38\textwidth}
  \code{--} No response
  \break
  \code{28} Response from address 28
  \break
  \code{UU} Address in use (by driver)
  \end{columns}
\end{frame}

\begin{frame}[fragile]{\code{i2cget} and \code{i2cset}}
  \begin{itemize}
    \item \code{i2cget}: read a register value
    \item \code{i2cset}: set a register value
    \item Can use various types of SMBus and I²C transactions
    \item Limited to 8-bit register address
  \end{itemize}

  \begin{block}{}
    \fontsize{9}{9}\selectfont
    \begin{minted}{shell}
# i2cget -y 2 0x28 0x1b
0x21
# i2cset -y 2 0x28 0x55
#
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{\code{i2cdump}}
  \begin{itemize}
  \item \code{i2cdump}: dump value of all registers
  \end{itemize}

  \begin{block}{}
    \fontsize{9}{9}\selectfont
    \begin{minted}{text}
# i2cdump -y 2 0x28
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 00 00 00 00 00 12 00 11 20 00 00 f3 00 00 00    ......?.? ..?...
10: 04 00 00 40 00 00 00 00 20 00 00 21 00 e0 00 00    ?..@.... ..!.?..
20: a0 32 00 00 00 ac 00 00 02 00 00 00 00 00 01 10    ?2...?..?.....??
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
70: a3 2c 91 01 08 2c d1 02 00 2c c1 03 00 f0 b0 04    ?,???,??.,??.???
80: 00 af 40 06 00 00 90 01 08 2c d1 02 00 2c c1 03    .?@?..???,??.,??
90: 00 00 00 00 00 00 40 00 00 00 00 00 00 00 00 00    ......@.........
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
#
    \end{minted}
  \end{block}
\end{frame}

\begin{frame}[fragile]{\code{i2ctransfer}}
  \begin{itemize}
    \item \code{i2ctransfer}: the ``swiss army knife of Linux I2C'', in
      userspace
    \item Example: reimplement the \code{i2cget -y 2 0x28 0x1b} command:
  \end{itemize}

  \begin{block}{}
    \fontsize{9}{9}\selectfont
    \begin{minted}{shell}
# i2ctransfer -y 2 w1@0x28 0x1b r1@0x28
0x21
#
    \end{minted}
  \end{block}

  \begin{itemize}
    \item \code{w1@0x28} Write transaction, 1 byte, client address 0x28
    \item \code{0x1b} Data to send in the write transaction
    \item \code{r1@0x28} Read transaction, 1 byte, client address 0x28
  \end{itemize}
\end{frame}

\subsection{Hardware tools}

\begin{frame}{Oscilloscope}
  \begin{itemize}
    \item Can show SCL and SDA with all the details
    \item Useful to check voltage levels, slopes, noise\dots
    \item Many models can visually decode I²C and other protocols
  \end{itemize}
\end{frame}

\begin{frame}{Oscilloscope --- NACK}
  \begin{center}
    \includegraphics[height=0.88\textheight]{oscilloscope-nack.png}
  \end{center}
\end{frame}

\begin{frame}{Oscilloscope --- Register read}
  \begin{center}
    \includegraphics[height=0.88\textheight]{oscilloscope-reg-read.png}
  \end{center}
\end{frame}

\begin{frame}{Logic analyzer}
  \begin{itemize}
    \item {\bf Sigrok} is suite of signal analysis software
      \begin{itemize}
        \item \url{https://sigrok.org}
      \end{itemize}
    \item {\bf Pulseview}: a logic analyzer and oscilloscope, based on Sigrok
      \begin{itemize}
        \item Visually decodes I²C and other protocols
        \item \url{https://sigrok.org/wiki/PulseView}
      \end{itemize}
    \item Open source, GPLv3+
    \item They work well with cheap acquisition devices
  \end{itemize}
  \begin{center}
    \includegraphics[height=0.4\textheight]{USB-logic-analyzer.jpg}
  \end{center}
\end{frame}

\begin{frame}{Pulseview --- NACK}
  \begin{center}
    \includegraphics[width=1\textwidth]{pulseview-nack.png}
  \end{center}
\end{frame}

\begin{frame}{Pulseview --- Register read}
  \begin{center}
    \includegraphics[width=1\textwidth]{pulseview-reg-read.png}
  \end{center}
\end{frame}

\subsection{Troubleshooting}

\begin{frame}{Troubleshooting tools}
  \begin{itemize}
    \item Return code from \code{i2c_*()} functions --- Never ignore errors!
    \pause
    \item Kernel logs
    \pause
    \item i2c-tools
    \pause
    \item Oscilloscope or logic analyzer
  \end{itemize}
\end{frame}

\begin{frame}{No ACK from client --- systematic}
  \begin{itemize}
    \item Problem: a client {\bf never} responds to transactions
      \begin{itemize}
        \item i2c-tools symptom: \code{Error: Read failed}
        \item Kernel internal APIs symptom: \code{-ENXIO}
      \end{itemize}
    \pause
    \item \code{i2cdetect}: a client (possibly yours) at any unexpected
      address?
      \begin{itemize}
        \item Check address pins on client chip: datasheet, schematics
      \end{itemize}
    \pause
    \item \code{i2cdetect}: no client at any unexpected address?
      \begin{itemize}
        \item Client not powered, held in reset, broken, unsoldered pin
      \end{itemize}
    \pause
    \item Oscilloscope: no activity on bus, SCL/SDA always high
      \begin{itemize}
        \item Pinmux (I²C adapter not reaching the pads)
        \item Device tree: device under wrong bus
      \end{itemize}
    \pause
    \item Oscilloscope: no activity on bus, SCL/SDA always low
      \begin{itemize}
        \item Missing pull-up resistors (external or internal)
      \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{No ACK from client --- sporadic}
  \begin{itemize}
    \item Problem: a client {\bf sporadically} does not respond to
      transactions
      \begin{itemize}
        \item i2c-tools symptom: \code{Error: Read failed}
        \item Kernel internal APIs symptom: \code{-ENXIO}
      \end{itemize}
    \pause
    \item Oscilloscope: SCL/SDA lines return to high level too slowly
      \begin{itemize}
        \item Weak pull-up
        \item Workaround: reduce \code{clock-frequency} in device tree
      \end{itemize}
    \pause
    \item Oscilloscope: noise on SCL/SDA lines
      \begin{itemize}
        \item Hardware must be fixed
      \end{itemize}
    \pause
    \item Oscilloscope: SCL/SDA delays incorrect
      \begin{itemize}
        \item Propagation delay in lines at high speed? Review PCB
        \item Tune \code{i2c-scl-internal-delay-ns}\dots
        \item Workaround: reduce \code{clock-frequency} in device tree
      \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}{No ACK from client after reset}
  \begin{itemize}
    \item Problem: a client {\bf sporadically} does not respond after
      unclean reset
      \begin{itemize}
        \item Symptom: driver fails to respond, fails to probe
      \end{itemize}
    \pause
    \item No clean shutdown $\rightarrow$ driver could not set client to
      idle state
      \begin{itemize}
        \item E.g. client left in the middle of a transaction, kernel
          starts a new one
      \end{itemize}
    \pause
    \item Reset all clients during boot
      \begin{itemize}
        \item In hardware, if possible
        \item In the bootloader otherwise
      \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]{Bus busy}
  \begin{itemize}
    \item Problem: SCL line held low
      \begin{itemize}
        \item Symptom: \code{bus busy} in kernel logs
      \end{itemize}
  \end{itemize}
  \begin{block}{}
    \fontsize{9}{9}\selectfont
    \begin{minted}{text}
stm32f7-i2c 40015000.i2c: bus busy
stm32f7-i2c 40015000.i2c: Trying to recover bus
    \end{minted}
  \end{block}
  \begin{itemize}
    \pause
    \item Systematic
      \begin{itemize}
        \item Short circuit / mounting problem
      \end{itemize}
    \pause
    \item Sporadic
      \begin{itemize}
        \item Chip gone crazy
          \begin{itemize}
            \item Bus recovery could fix it
          \end{itemize}
        \item Multimaster problem
      \end{itemize}
  \end{itemize}
\end{frame}

\questionslide

\appendix

\section{Extra slides}

\begin{frame}{Bit-level communication}
  \begin{center}
    \includegraphics[width=0.7\textwidth]{I2C_data_transfer.pdf}
    {\tiny\break\url{https://upload.wikimedia.org/wikipedia/commons/6/64/I2C_data_transfer.svg}}
  \end{center}
  \begin{itemize}
    \item SCL low = move SDA
    \item SCL high = sample SDA
    \item Exception: Start / Stop condition
  \end{itemize}
\end{frame}

\begin{frame}{The driver model}
  \begin{center}
    \includegraphics[height=0.8\textheight]{driver-model.pdf}
  \end{center}
\end{frame}

\begin{frame}{I²C muxes and switches}
  \begin{center}
    \includegraphics[height=0.7\textheight]{i2c-mux-switch.pdf}
  \end{center}
\end{frame}

\end{document}
