Thread (21 messages) flat view 21 messages, 3 authors, 28d ago
COLD28d

[PATCH net-next v5 6/7] ptp: ocp: Add R4006 I2C peripheral topology

From: Ahmad Byagowi <hidden>
Date: 2026-08-14 23:11:31
Also in: linux-devicetree, linux-hardening, linux-i2c, linux-leds, lkml
Subsystem: networking drivers, opencompute ptp clock driver, ptp hardware clock support, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Vadim Fedorenko, Richard Cochran, Linus Torvalds

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 <redacted>
---
 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)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help