[PATCH 4/8] ARM: dts: bcm6846: Add I2C bus block

Linus Walleij linus.walleij at linaro.org
Tue Sep 2 02:26:37 PDT 2025


On Mon, Sep 1, 2025 at 5:49 PM Florian Fainelli
<florian.fainelli at broadcom.com> wrote:
> On 9/1/2025 5:50 AM, Linus Walleij wrote:


> > +             i2c0: i2c at 2100 {
> > +                     compatible = "brcm,brcmstb-i2c";
>
> Historically the BCA SoCs have byte-sized FIFOs rather than word-sized
> FIFOs which is why the compatible string "brcm,brcmper-i2c" was defined.
> I assume this was changed at some point and this works correctly with
> the "brcm,brcmstb-i2c" compatible string.
>
> Was there any I2C peripheral you could interface with?

Good question!

I have an SFP on I2C and it doesn't connect with either mode of the
I2C, I think because I need pin control for BCA working first :(

I look into the i2c_bcm63xxx.c driver by Prataba Reddy, which
is what at least BCM6846 is using. The register access looks like this:

/* Read the value from given bcm63000 register */
static inline int reg_read(uint32* offset)
{
    int ret;
    ret = *offset;
    BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "reg_read: offset = %lx, val is %x\n",
                  (long int)offset, ret);
    return ret;
}

/* Write the given value to given bcm63000 register */
static inline void reg_write(uint32* offset, int val)
{
    BCM_LOG_DEBUG(BCM_LOG_ID_I2C, "reg_write: offset = %lx; val = %x\n",
                  (long int)offset, val);
    *offset = val;
}

And those are used like this for the FIFO (read):

        /* Read the data */
        if (fifo_len == 8)
        {
            for (j = 0; j < xfer_cnt; j++)
                buf[i*fifo_len + j] =
                    (u8)reg_read((uint32 *)&i2c_dev->reg_base->DataOut0 + j);
        }
        else
        {
            int num_dwords = (xfer_cnt)/4;
            int left_over = (xfer_cnt)%4;
            int temp_data=0;
            for (j = 0; j < num_dwords; j++)
            {
#ifdef __LITTLE_ENDIAN
                *((int *)&buf[i*fifo_len + j*4]) =
                    reg_read((uint32 *)&i2c_dev->reg_base->DataOut0 + j);
#else
                *((int *)&buf[i*fifo_len + j*4]) =
                    swab32(reg_read((uint32
*)&i2c_dev->reg_base->DataOut0 + j));
#endif
            }
            if(left_over)
            {
#ifdef __LITTLE_ENDIAN
                temp_data =
                    reg_read((uint32 *)&i2c_dev->reg_base->DataOut0 + j);
#else
                temp_data =
                    swab32(reg_read((uint32
*)&i2c_dev->reg_base->DataOut0 + j));
#endif
                memcpy((char*)&buf[i*fifo_len + j*4],
(char*)&temp_data, left_over);

            }

        }

And for write:

        /* Write the data */
        if (fifo_len == 8)
        {
            for (j = 0; j < xfer_cnt; j++)
                reg_write((uint32 *)&i2c_dev->reg_base->DataIn0 + j,
buf[i * fifo_len + j]);
        }
        else
        {
            int num_dwords = (xfer_cnt + 3)/4;
            for (j = 0; j < num_dwords; j++)
            {
#ifdef __LITTLE_ENDIAN
                reg_write((uint32 *)&i2c_dev->reg_base->DataIn0 + j,
                          *((int *)&buf[i * fifo_len + j*4]));
#else
                reg_write((uint32 *)&i2c_dev->reg_base->DataIn0 + j,
                          swab32(*((int *)&buf[i * fifo_len + j*4])));
#endif
            }
        }


To me this looks like 32bit access and one byte in the LSB of each
32bit word. But the FIFO data_regsz code in i2c-brcmstb.c is a bit
terse here, which one should I be using?

I guess brcm,brcmper-i2c?

Unfortunately Documentation/devicetree/bindings/i2c/brcm,brcmstb-i2c.yaml
isn't very helpful with this, I can patch it after we conclude this.

Yours,
Linus Walleij



More information about the linux-arm-kernel mailing list