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 <[email protected]>
---
 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)


Reply via email to