[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