Hi Peter, Thanks for taking a look and for the heads-up on the defconfig!
To answer your question: I am testing this exclusively on a Raspberry Pi 4 Model B (BCM2711), as it is the only hardware generation I currently have on hand. The specific I2C device I am using for testing is a UPS HAT <https://www.waveshare.com/wiki/UPS_HAT> equipped with an INA219 power monitor/current sensor. I use it to query battery voltage and current. The new I2C driver handles the read/write transactions with the INA219 sensor flawlessly. Here is a quick log of the testing procedure from the U-Boot shell: => i2c dev 1 => i2c probe 0x42 # Prepare calibration and config data in RAM => mw.b 0x01000000 0x39 1; mw.b 0x01000001 0x9f 1 => mw.b 0x01000002 0x10 1; mw.b 0x01000003 0x00 1 # Write configurations to INA219 => i2c write 0x01000000 0x42 0.1 2 -s => i2c write 0x01000002 0x42 5.1 2 -s # Read current register (0x04) => i2c read 0x42 4.1 2 0x01000000 Regarding `rpi_arm64_defconfig`: Understood. Would you like me to send a v4 to enable CONFIG_SYS_I2C_BCM2835 in `rpi_arm64_defconfig` (and potentially others), or should I wait for you to finish your testing across other Pi generations so I can incorporate all feedback into v4 at once? Looking forward to your test results. Best regards, Giau Nguyen -------------------------------------------------------- Phone: (+84) 387 915 996 <+84%20387%20915%20996> On Sat, Oct 31, 2026 at 4:32 PM Peter Robinson <[email protected]> wrote: > Hi Giau, > > > Mainline U-Boot currently lacks an I2C controller driver for the > > Broadcom BCM2711 SoC (Raspberry Pi 4). > > May I ask what i2c devices you're using to test this on U-Boot and on > which generation of device? > > > This commit adds a new DM-compliant I2C driver for Broadcom > > BCM2835/BCM2711 SoCs based on the Linux kernel's i2c-bcm2835.c. > > (based on Linux commit 32a0a94aa09e ("i2c: Switch back to struct > platform_driver::remove()")). > > > > The driver dynamically queries the actual VPU core clock rate from > > the VideoCore firmware via mailbox property messages to calculate > > the CDIV clock divider, ensuring accurate I2C timing and baud rates > > on BCM2711. > > > > Enable CONFIG_SYS_I2C_BCM2835 in rpi_4_defconfig. > > Typically the main config used is rpi_arm64_defconfig which covers all > 64bit capable generations (3/4/5/Zero2). > > I'll test/review in the next few days for a RP > > > Reviewed-by: Heiko Schocher <[email protected]> > > Signed-off-by: Giau Nguyen <[email protected]> > > --- > > v3: > > - Added the Linux commit ID to the commit message. > > - Fixed alphabetical sorting of CONFIG_SYS_I2C_BCM2835 in > drivers/i2c/Makefile. > > - Added Reviewed-by tag from Heiko. > > > > v2: > > - Clarified commit message: U-Boot mainline currently lacks BCM2711 I2C > driver. > > - Fixed line endings and code formatting per checkpatch.pl. > > - Converted register offsets to 'struct bcm2835_i2c_regs' abstraction. > > - Removed 'bcm2835_i2c_readl/writel' wrappers in favor of standard > readl/writel. > > - Moved mailbox clock querying to bcm2835_get_clock_rate() in > mach-bcm283x. > > - Enabled CONFIG_SYS_I2C_BCM2835 in rpi_4_defconfig. > > - Sorted drivers/i2c/Kconfig and Makefile alphabetically. > > - Removed 'Assisted by AI' tag. > > > > MAINTAINERS | 1 + > > arch/arm/mach-bcm283x/include/mach/msg.h | 9 + > > arch/arm/mach-bcm283x/msg.c | 22 ++ > > configs/rpi_4_defconfig | 4 + > > drivers/i2c/Kconfig | 10 + > > drivers/i2c/Makefile | 1 + > > drivers/i2c/i2c-bcm2835.c | 370 +++++++++++++++++++++++ > > 7 files changed, 417 insertions(+) > > create mode 100644 drivers/i2c/i2c-bcm2835.c > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index 8c6c0c2a4bc..3260024a736 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -215,6 +215,7 @@ F: arch/arm/dts/bcm283* > > F: arch/arm/mach-bcm283x/ > > F: board/raspberrypi/ > > F: drivers/gpio/bcm2835_gpio.c > > +F: drivers/i2c/i2c-bcm2835.c > > F: drivers/mmc/bcm2835_sdhci.c > > F: drivers/mmc/bcm2835_sdhost.c > > F: drivers/serial/serial_bcm283x_mu.c > > diff --git a/arch/arm/mach-bcm283x/include/mach/msg.h > b/arch/arm/mach-bcm283x/include/mach/msg.h > > index e54da86e353..d6adec07ae2 100644 > > --- a/arch/arm/mach-bcm283x/include/mach/msg.h > > +++ b/arch/arm/mach-bcm283x/include/mach/msg.h > > @@ -22,6 +22,15 @@ int bcm2835_power_on_module(u32 module); > > */ > > int bcm2835_get_mmc_clock(u32 clock_id); > > > > +/** > > + * bcm2835_get_clock_rate() - get the current rate of a clock > > + * > > + * @clock_id: ID of clock to get frequency for > (BCM2835_MBOX_CLOCK_ID_...) > > + * @rate: Returns the clock rate in Hz > > + * Return: 0 if OK, -EIO or -EINVAL on error > > + */ > > +int bcm2835_get_clock_rate(u32 clock_id, ulong *rate); > > + > > /** > > * bcm2835_set_sdhost_clock() - determine if firmware controls sdhost > cdiv > > * > > diff --git a/arch/arm/mach-bcm283x/msg.c b/arch/arm/mach-bcm283x/msg.c > > index 4993c0bdb81..74f847c5e54 100644 > > --- a/arch/arm/mach-bcm283x/msg.c > > +++ b/arch/arm/mach-bcm283x/msg.c > > @@ -115,6 +115,28 @@ int bcm2835_get_mmc_clock(u32 clock_id) > > return clock_rate; > > } > > > > +int bcm2835_get_clock_rate(u32 clock_id, ulong *rate) > > +{ > > + ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1); > > + int ret; > > + > > + BCM2835_MBOX_INIT_HDR(msg_clk); > > + BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); > > + msg_clk->get_clock_rate.body.req.clock_id = clock_id; > > + > > + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, > &msg_clk->hdr); > > + if (ret) { > > + printf("bcm2835: Could not query clock rate for %u\n", > clock_id); > > + return -EIO; > > + } > > + > > + *rate = msg_clk->get_clock_rate.body.resp.rate_hz; > > + if (!*rate) > > + return -EINVAL; > > + > > + return 0; > > +} > > + > > int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2) > > { > > ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_sdhost_clock, > msg_sdhost_clk, 1); > > diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig > > index f5fb322aa8f..2ddaf003558 100644 > > --- a/configs/rpi_4_defconfig > > +++ b/configs/rpi_4_defconfig > > @@ -22,6 +22,7 @@ CONFIG_MISC_INIT_R=y > > CONFIG_SYS_PROMPT="U-Boot> " > > CONFIG_CMD_DFU=y > > CONFIG_CMD_GPIO=y > > +CONFIG_CMD_I2C=y > > CONFIG_CMD_MMC=y > > CONFIG_CMD_PCI=y > > CONFIG_CMD_USB=y > > @@ -34,6 +35,9 @@ CONFIG_DM_DMA=y > > CONFIG_DFU_MMC=y > > CONFIG_SYS_DFU_DATA_BUF_SIZE=0x100000 > > CONFIG_SYS_DFU_MAX_FILE_SIZE=0x200000 > > +CONFIG_I2C=y > > +CONFIG_DM_I2C=y > > +CONFIG_SYS_I2C_BCM2835=y > > CONFIG_BCM2835_GPIO=y > > CONFIG_MMC_SDHCI=y > > CONFIG_MMC_SDHCI_SDMA=y > > diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > > index 52067fa7c1f..1b26906e403 100644 > > --- a/drivers/i2c/Kconfig > > +++ b/drivers/i2c/Kconfig > > @@ -164,6 +164,16 @@ config SYS_I2C_AT91 > > i2c-gpio driver unless your system can cope with this > limitation. > > Binding info: doc/device-tree-bindings/i2c/i2c-at91.txt > > > > +config SYS_I2C_BCM2835 > > + bool "BCM2835 I2C controller" > > + depends on DM_I2C > > + help > > + Enable support for the Broadcom BCM2835/BCM2711 I2C controller. > > + This driver provides standard I2C support for Raspberry Pi > > + devices, including the newer Raspberry Pi 4. It dynamically > > + calculates the clock divider based on the VPU core clock > > + queried via the firmware mailbox. > > + > > config SYS_I2C_IPROC > > bool "Broadcom I2C driver" > > depends on DM_I2C > > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > > index bebd728e7da..aac6ce4b6e0 100644 > > --- a/drivers/i2c/Makefile > > +++ b/drivers/i2c/Makefile > > @@ -14,6 +14,7 @@ obj-$(CONFIG_$(XPL_)SYS_I2C_LEGACY) += i2c_core.o > > obj-$(CONFIG_SYS_I2C_ASPEED) += ast_i2c.o > > obj-$(CONFIG_SYS_I2C_AST2600) += ast2600_i2c.o > > obj-$(CONFIG_SYS_I2C_AT91) += at91_i2c.o > > +obj-$(CONFIG_SYS_I2C_BCM2835) += i2c-bcm2835.o > > obj-$(CONFIG_SYS_I2C_CADENCE) += i2c-cdns.o > > obj-$(CONFIG_SYS_I2C_CA) += i2c-cortina.o > > obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o > > diff --git a/drivers/i2c/i2c-bcm2835.c b/drivers/i2c/i2c-bcm2835.c > > new file mode 100644 > > index 00000000000..e6abb076bdb > > --- /dev/null > > +++ b/drivers/i2c/i2c-bcm2835.c > > @@ -0,0 +1,370 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * BCM2835 I2C controller driver > > + * (C) Copyright 2026 > > + * > > + * Author: Giau Nguyen <[email protected]> > > + * Based on Linux driver: drivers/i2c/busses/i2c-bcm2835.c > > + */ > > + > > +#include <log.h> > > +#include <asm/io.h> > > +#include <asm/arch/mbox.h> > > +#include <asm/arch/msg.h> > > +#include <dm.h> > > +#include <dm/device_compat.h> > > +#include <i2c.h> > > +#include <time.h> > > +#include <linux/bitops.h> > > +#include <linux/delay.h> > > +#include <linux/err.h> > > +#include <linux/kernel.h> > > +#include <linux/types.h> > > + > > +#define BCM2835_I2C_C_READ BIT(0) > > +#define BCM2835_I2C_C_CLEAR BIT(4) /* bits 4 and 5 both clear */ > > +#define BCM2835_I2C_C_ST BIT(7) > > +#define BCM2835_I2C_C_INTD BIT(8) > > +#define BCM2835_I2C_C_INTT BIT(9) > > +#define BCM2835_I2C_C_INTR BIT(10) > > +#define BCM2835_I2C_C_I2CEN BIT(15) > > + > > +#define BCM2835_I2C_S_TA BIT(0) > > +#define BCM2835_I2C_S_DONE BIT(1) > > +#define BCM2835_I2C_S_TXW BIT(2) > > +#define BCM2835_I2C_S_RXR BIT(3) > > +#define BCM2835_I2C_S_TXD BIT(4) > > +#define BCM2835_I2C_S_RXD BIT(5) > > +#define BCM2835_I2C_S_TXE BIT(6) > > +#define BCM2835_I2C_S_RXF BIT(7) > > +#define BCM2835_I2C_S_ERR BIT(8) > > +#define BCM2835_I2C_S_CLKT BIT(9) > > +#define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error > reporting */ > > + > > +#define BCM2835_I2C_FEDL_SHIFT 16 > > +#define BCM2835_I2C_REDL_SHIFT 0 > > + > > +#define BCM2835_I2C_CDIV_MIN 0x0002 > > +#define BCM2835_I2C_CDIV_MAX 0xFFFE > > + > > +#define BCM2835_I2C_CLKT_TOUT_MS 35 > > +#define BCM2835_I2C_XFER_TIMEOUT_MS 1000 > > + > > +struct bcm2835_i2c_regs { > > + u32 c; > > + u32 s; > > + u32 dlen; > > + u32 a; > > + u32 fifo; > > + u32 div; > > + u32 del; > > + u32 clkt; > > +}; > > + > > +struct bcm2835_i2c_priv { > > + struct bcm2835_i2c_regs __iomem *regs; > > + ulong input_rate; > > + size_t msg_buf_remaining; > > + u8 *msg_buf; > > + struct i2c_msg *curr_msg; > > + int msg_err; > > + int num_msgs; > > +}; > > + > > +static void bcm2835_fill_txfifo(struct bcm2835_i2c_priv *i2c_dev) > > +{ > > + struct bcm2835_i2c_regs __iomem *regs = i2c_dev->regs; > > + > > + while (i2c_dev->msg_buf_remaining) { > > + if (!(readl(®s->s) & BCM2835_I2C_S_TXD)) > > + break; > > + > > + writel(*i2c_dev->msg_buf, ®s->fifo); > > + i2c_dev->msg_buf++; > > + i2c_dev->msg_buf_remaining--; > > + } > > +} > > + > > +static void bcm2835_drain_rxfifo(struct bcm2835_i2c_priv *i2c_dev) > > +{ > > + struct bcm2835_i2c_regs __iomem *regs = i2c_dev->regs; > > + > > + while (i2c_dev->msg_buf_remaining) { > > + if (!(readl(®s->s) & BCM2835_I2C_S_RXD)) > > + break; > > + > > + *i2c_dev->msg_buf = readl(®s->fifo); > > + i2c_dev->msg_buf++; > > + i2c_dev->msg_buf_remaining--; > > + } > > +} > > + > > +static int bcm2835_i2c_calc_divider(unsigned long rate, > > + unsigned long parent_rate) > > +{ > > + int divider = DIV_ROUND_UP(parent_rate, rate); > > + > > + /* > > + * Per the datasheet, the register is always interpreted as an > even > > + * number, by rounding down. In other words, the LSB is ignored. > So, > > + * if the LSB is set, increment the divider to avoid any issue. > > + */ > > + if (divider & 1) > > + divider++; > > + > > + if (divider < BCM2835_I2C_CDIV_MIN || > > + divider > BCM2835_I2C_CDIV_MAX) > > + return -EINVAL; > > + > > + return divider; > > +} > > + > > +static int bcm2835_i2c_set_rate(struct udevice *bus, unsigned int rate) > > +{ > > + struct bcm2835_i2c_priv *i2c_dev = dev_get_priv(bus); > > + struct bcm2835_i2c_regs __iomem *regs = i2c_dev->regs; > > + ulong parent_rate = i2c_dev->input_rate; > > + u32 redl, fedl; > > + u32 clk_tout; > > + int divider; > > + > > + if (!rate || !parent_rate) > > + return -EINVAL; > > + > > + divider = bcm2835_i2c_calc_divider(rate, parent_rate); > > + if (divider < 0) > > + return divider; > > + > > + writel(divider, ®s->div); > > + > > + /* > > + * Number of core clocks to wait after falling edge before > > + * outputting the next data bit. Note that both FEDL and REDL > > + * can't be greater than CDIV/2. > > + */ > > + fedl = max_t(u32, divider / 16, 1); > > + > > + /* > > + * Number of core clocks to wait after rising edge before > > + * sampling the next incoming data bit. > > + */ > > + redl = max_t(u32, divider / 4, 1); > > + > > + writel((fedl << BCM2835_I2C_FEDL_SHIFT) | > > + (redl << BCM2835_I2C_REDL_SHIFT), ®s->del); > > + > > + /* > > + * Set the clock stretch timeout. > > + */ > > + if (rate > 0xffff * 1000 / BCM2835_I2C_CLKT_TOUT_MS) > > + clk_tout = 0xffff; > > + else > > + clk_tout = BCM2835_I2C_CLKT_TOUT_MS * rate / 1000; > > + > > + writel(clk_tout, ®s->clkt); > > + > > + return 0; > > +} > > + > > +static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_priv *i2c_dev) > > +{ > > + struct bcm2835_i2c_regs __iomem *regs = i2c_dev->regs; > > + u32 c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN; > > + struct i2c_msg *msg = i2c_dev->curr_msg; > > + bool last_msg = (i2c_dev->num_msgs == 1); > > + > > + if (!i2c_dev->num_msgs) > > + return; > > + > > + i2c_dev->num_msgs--; > > + i2c_dev->msg_buf = msg->buf; > > + i2c_dev->msg_buf_remaining = msg->len; > > + > > + if (msg->flags & I2C_M_RD) > > + c |= BCM2835_I2C_C_READ; > > + else > > + c |= BCM2835_I2C_C_INTT; > > + > > + if (last_msg) > > + c |= BCM2835_I2C_C_INTD; > > + > > + writel(msg->addr, ®s->a); > > + writel(msg->len, ®s->dlen); > > + writel(c, ®s->c); > > +} > > + > > +static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_priv > *i2c_dev) > > +{ > > + i2c_dev->curr_msg = NULL; > > + i2c_dev->num_msgs = 0; > > + i2c_dev->msg_buf = NULL; > > + i2c_dev->msg_buf_remaining = 0; > > +} > > + > > +static int bcm2835_i2c_xfer(struct udevice *dev, struct i2c_msg *msgs, > int count) > > +{ > > + struct bcm2835_i2c_priv *i2c_dev = dev_get_priv(dev); > > + struct bcm2835_i2c_regs __iomem *regs = i2c_dev->regs; > > + bool ignore_nak = false; > > + bool done = false; > > + ulong start; > > + int i; > > + u32 val, err; > > + int ret = 0; > > + > > + if (!msgs || count <= 0) > > + return -EINVAL; > > + > > + for (i = 0; i < count; i++) { > > + if (msgs[i].flags & I2C_M_TEN) > > + return -EOPNOTSUPP; > > + if (msgs[i].flags & I2C_M_RD) { > > + if (i < count - 1) { > > + dev_err(dev, "read message must be > last\n"); > > + return -EOPNOTSUPP; > > + } > > + } > > + if (msgs[i].len > 0xffff) > > + return -EINVAL; > > + if (msgs[i].flags & I2C_M_IGNORE_NAK) > > + ignore_nak = true; > > + } > > + > > + /* Clear stale status and FIFO state before starting a new > transaction. */ > > + writel(BCM2835_I2C_C_CLEAR, ®s->c); > > + writel(BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR | > BCM2835_I2C_S_DONE, > > + ®s->s); > > + > > + i2c_dev->curr_msg = msgs; > > + i2c_dev->num_msgs = count; > > + i2c_dev->msg_err = 0; > > + > > + bcm2835_i2c_start_transfer(i2c_dev); > > + start = get_timer(0); > > + while (get_timer(start) < BCM2835_I2C_XFER_TIMEOUT_MS) { > > + val = readl(®s->s); > > + > > + err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); > > + if (err && !(val & BCM2835_I2C_S_TA)) > > + i2c_dev->msg_err = err; > > + > > + if (val & BCM2835_I2C_S_DONE) { > > + if (!i2c_dev->curr_msg) { > > + dev_err(dev, "unexpected completion > status\n"); > > + } else if (i2c_dev->curr_msg->flags & I2C_M_RD) { > > + bcm2835_drain_rxfifo(i2c_dev); > > + val = readl(®s->s); > > + } > > + > > + if ((val & BCM2835_I2C_S_RXD) || > > + i2c_dev->msg_buf_remaining) > > + i2c_dev->msg_err = BCM2835_I2C_S_LEN; > > + done = true; > > + break; > > + } > > + > > + if (val & BCM2835_I2C_S_TXW) { > > + if (!i2c_dev->msg_buf_remaining) { > > + i2c_dev->msg_err = val | > BCM2835_I2C_S_LEN; > > + break; > > + } > > + > > + bcm2835_fill_txfifo(i2c_dev); > > + > > + if (i2c_dev->num_msgs > 0 && > !i2c_dev->msg_buf_remaining) { > > + i2c_dev->curr_msg++; > > + bcm2835_i2c_start_transfer(i2c_dev); > > + } > > + } > > + > > + if (val & BCM2835_I2C_S_RXR) { > > + if (!i2c_dev->msg_buf_remaining) { > > + i2c_dev->msg_err = val | > BCM2835_I2C_S_LEN; > > + break; > > + } > > + > > + bcm2835_drain_rxfifo(i2c_dev); > > + } > > + udelay(1); > > + } > > + > > + if (!done) { > > + val = readl(®s->s); > > + dev_err(dev, "transfer timeout: status=%08x > remaining=%zu\n", > > + val, i2c_dev->msg_buf_remaining); > > + ret = -ETIMEDOUT; > > + } > > + > > + /* Always abort/reset the controller and clear W1C status bits. > */ > > + writel(BCM2835_I2C_C_CLEAR, ®s->c); > > + writel(BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR | > BCM2835_I2C_S_DONE, > > + ®s->s); > > + > > + bcm2835_i2c_finish_transfer(i2c_dev); > > + if (ret) > > + return ret; > > + > > + if (ignore_nak) > > + i2c_dev->msg_err &= ~BCM2835_I2C_S_ERR; > > + > > + if (!i2c_dev->msg_err) > > + return 0; > > + > > + if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) > > + return -EREMOTEIO; > > + > > + return -EIO; > > +} > > + > > +static const struct dm_i2c_ops bcm2835_i2c_ops = { > > + .xfer = bcm2835_i2c_xfer, > > + .set_bus_speed = bcm2835_i2c_set_rate, > > +}; > > + > > +static const struct udevice_id bcm2835_i2c_ids[] = { > > + {.compatible = "brcm,bcm2711-i2c"}, > > + {.compatible = "brcm,bcm2835-i2c"}, > > + {} > > +}; > > + > > +static int bcm2835_i2c_probe(struct udevice *bus) > > +{ > > + struct bcm2835_i2c_priv *priv = dev_get_priv(bus); > > + struct bcm2835_i2c_regs __iomem *regs; > > + unsigned int bus_clk_rate; > > + int ret; > > + > > + priv->regs = dev_read_addr_ptr(bus); > > + if (!priv->regs) { > > + printf("bcm2835_i2c: cannot get base address\n"); > > + return -EINVAL; > > + } > > + > > + regs = priv->regs; > > + > > + ret = bcm2835_get_clock_rate(BCM2835_MBOX_CLOCK_ID_CORE, > &priv->input_rate); > > + if (ret) > > + return ret; > > + > > + bus_clk_rate = dev_read_u32_default(bus, "clock-frequency", > > + I2C_SPEED_STANDARD_RATE); > > + ret = bcm2835_i2c_set_rate(bus, bus_clk_rate); > > + if (ret) > > + return ret; > > + > > + /* clear FIFO + status */ > > + writel(BCM2835_I2C_C_CLEAR, ®s->c); > > + writel(BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR | > BCM2835_I2C_S_DONE, > > + ®s->s); > > + > > + return 0; > > +} > > + > > +U_BOOT_DRIVER(bcm2835_i2c) = { > > + .name = "bcm2835_i2c", > > + .id = UCLASS_I2C, > > + .of_match = bcm2835_i2c_ids, > > + .probe = bcm2835_i2c_probe, > > + .priv_auto = sizeof(struct bcm2835_i2c_priv), > > + .ops = &bcm2835_i2c_ops, > > +}; > > -- > > 2.34.1 > > >
