[PATCH net-next v5 6/7] ptp: ocp: Add R4006 I2C peripheral topology
From: Ahmad Byagowi
Date: Fri Aug 14 2026 - 19:15:00 EST
R4006 boards place sensors and an IS32FL3207 LED controller behind
a four-channel PCA9546 mux.
Describe the LM75B, SHT3x, and ICP10100 sensors and the five RGB LED
groups. The BNO08x at address 0x4a is omitted because it has no upstream
driver; the LM75B using the same address is on a different mux channel.
Read the board ID independently of the serial EEPROM and select this
profile from the R4006 prefix. Production IDs may append a board revision,
while unknown board IDs remain untouched.
Signed-off-by: Ahmad Byagowi <ahmadexp@xxxxxxxxx>
---
drivers/ptp/ptp_ocp.c | 97 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 444b26a5e2a9..5ae50ad83bda 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -578,6 +578,71 @@ static struct ptp_ocp_eeprom_map art_eeprom_map[] = {
{ }
};
+/*
+ * The BNO08x at 0x4a on channel 3 has no upstream Linux driver, so omit it.
+ * The LM75B at the same address is a separate device on mux channel 0.
+ */
+static const struct ptp_ocp_i2c_device ptp_ocp_r4006_sensors[] = {
+ { "temperature@48", "national,lm75b", "lm75b", 0, 0x48 },
+ { "temperature@49", "national,lm75b", "lm75b", 0, 0x49 },
+ { "temperature@4a", "national,lm75b", "lm75b", 0, 0x4a },
+ { "humidity@44", NULL, "sht3x", 1, 0x44 },
+ { "pressure@63", "invensense,icp10100", "icp10100", 2, 0x63 },
+};
+
+static const struct ptp_ocp_led ptp_ocp_r4006_leds[] = {
+ {
+ .node_name = "multi-led@c",
+ .function = LED_FUNCTION_STATUS,
+ .channel = { 13, 12, 14 },
+ },
+ {
+ .node_name = "multi-led@6",
+ .function = LED_FUNCTION_INDICATOR,
+ .function_enumerator = 1,
+ .has_function_enumerator = true,
+ .channel = { 7, 6, 8 },
+ },
+ {
+ .node_name = "multi-led@9",
+ .function = LED_FUNCTION_INDICATOR,
+ .function_enumerator = 2,
+ .has_function_enumerator = true,
+ .channel = { 10, 9, 11 },
+ },
+ {
+ .node_name = "multi-led@0",
+ .function = LED_FUNCTION_INDICATOR,
+ .function_enumerator = 3,
+ .has_function_enumerator = true,
+ .channel = { 1, 0, 2 },
+ },
+ {
+ .node_name = "multi-led@3",
+ .function = LED_FUNCTION_INDICATOR,
+ .function_enumerator = 4,
+ .has_function_enumerator = true,
+ .channel = { 4, 3, 5 },
+ },
+};
+
+static_assert(ARRAY_SIZE(ptp_ocp_r4006_sensors) <=
+ OCP_I2C_MAX_SENSOR_COUNT);
+static_assert(ARRAY_SIZE(ptp_ocp_r4006_leds) <= OCP_I2C_MAX_LED_COUNT);
+
+static const struct ptp_ocp_i2c_profile ptp_ocp_r4006_profile = {
+ .name = "r4006",
+ .sensors = ptp_ocp_r4006_sensors,
+ .sensor_count = ARRAY_SIZE(ptp_ocp_r4006_sensors),
+ .leds = ptp_ocp_r4006_leds,
+ .led_count = ARRAY_SIZE(ptp_ocp_r4006_leds),
+ .led_node_name = "led-controller@34",
+ .led_mux_channel = 1,
+ .led_address = 0x34,
+ .led_riset_ohms = 4700,
+ .led_max_microamp = 8150,
+};
+
#define bp_assign_entry(bp, res, val) ({ \
uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \
*(typeof(val) *)addr = val; \
@@ -2178,6 +2243,20 @@ ptp_ocp_i2c_supported(struct ptp_ocp *bp)
bp->pdev->device == PCI_DEVICE_ID_CELESTICA_TIMECARD);
}
+static const struct ptp_ocp_i2c_profile *
+ptp_ocp_i2c_select_profile(struct ptp_ocp *bp)
+{
+ /* Pairs with field publication in ptp_ocp_read_eeprom(). */
+ if (!smp_load_acquire(&bp->has_board_id))
+ return NULL;
+
+ /* Production R4006 board IDs may carry a revision suffix. */
+ if (!memcmp(bp->board_id, "R4006", 5))
+ return &ptp_ocp_r4006_profile;
+
+ return NULL;
+}
+
static int
ptp_ocp_i2c_init_nodes(struct ptp_ocp *bp)
{
@@ -2496,13 +2575,29 @@ ptp_ocp_i2c_populate_topology(struct ptp_ocp *bp,
if (!READ_ONCE(bp->i2c_root_present))
return 0;
- if (!ptp_ocp_i2c_supported(bp) || !bp->i2c_profile)
+ if (!ptp_ocp_i2c_supported(bp) || !bp->eeprom_map)
return 0;
adapter = ptp_ocp_i2c_root_adapter(i2c_ctrl);
if (!adapter)
return -EAGAIN;
+ /* Pairs with field publication in ptp_ocp_read_eeprom(). */
+ if (!smp_load_acquire(&bp->has_board_id)) {
+ ret = ptp_ocp_read_eeprom(bp, OCP_EEPROM_BOARD_ID);
+ if (ret)
+ goto out_put_adapter;
+ }
+ /* Pairs with field publication in ptp_ocp_read_eeprom(). */
+ if (!smp_load_acquire(&bp->has_board_id)) {
+ ret = -EAGAIN;
+ goto out_put_adapter;
+ }
+ if (!bp->i2c_profile)
+ bp->i2c_profile = ptp_ocp_i2c_select_profile(bp);
+ if (!bp->i2c_profile)
+ goto out_put_adapter;
+
ret = ptp_ocp_i2c_init_nodes(bp);
if (ret)
goto out_put_adapter;
--
2.50.1 (Apple Git-155)