diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index c1e1c4f254ce..ea9e7f4479ca 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -96,6 +96,8 @@ struct mlxreg_hotplug_priv_data { static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, struct mlxreg_core_data *data) { + struct mlxreg_core_hotplug_platform_data *pdata; + /* * Return if adapter number is negative. It could be in case hotplug * event is not associated with hotplug device. @@ -103,10 +105,12 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, if (data->hpdev.nr < 0) return 0; - data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr); + pdata = dev_get_platdata(&priv->pdev->dev); + data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + + pdata->shift_nr); if (!data->hpdev.adapter) { dev_err(priv->dev, "Failed to get adapter for bus %d\n", - data->hpdev.nr); + data->hpdev.nr + pdata->shift_nr); return -EFAULT; } @@ -114,8 +118,8 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, data->hpdev.brdinfo); if (!data->hpdev.client) { dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", - data->hpdev.brdinfo->type, data->hpdev.nr, - data->hpdev.brdinfo->addr); + data->hpdev.brdinfo->type, data->hpdev.nr + + pdata->shift_nr, data->hpdev.brdinfo->addr); i2c_put_adapter(data->hpdev.adapter); data->hpdev.adapter = NULL; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1868aab0282a..b528e44ad8ae 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1175,6 +1175,7 @@ config INTEL_TELEMETRY config MLX_PLATFORM tristate "Mellanox Technologies platform support" + depends on I2C && REGMAP ---help--- This option enables system support for the Mellanox Technologies platform. The Mellanox systems provide data center networking diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 67f3c6d36988..7a0bd24c1ae2 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -85,6 +85,12 @@ #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) +/* Default I2C parent bus number */ +#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1 + +/* Maximum number of possible physical buses equipped on system */ +#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16 + /* Number of channels in group */ #define MLXPLAT_CPLD_GRP_CHNL_NUM 8 @@ -843,10 +849,48 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table); +static int mlxplat_mlxcpld_verify_bus_topology(int *nr) +{ + struct i2c_adapter *search_adap; + int shift, i; + + /* Scan adapters from expected id to verify it is free. */ + *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; + for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i < + MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) { + search_adap = i2c_get_adapter(i); + if (search_adap) { + i2c_put_adapter(search_adap); + continue; + } + + /* Return if expected parent adapter is free. */ + if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR) + return 0; + break; + } + + /* Return with error if free id for adapter is not found. */ + if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) + return -ENODEV; + + /* Shift adapter ids, since expected parent adapter is not free. */ + *nr = i; + for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { + shift = *nr - mlxplat_mux_data[i].parent; + mlxplat_mux_data[i].parent = *nr; + mlxplat_mux_data[i].base_nr += shift; + if (shift > 0) + mlxplat_hotplug->shift_nr = shift; + } + + return 0; +} + static int __init mlxplat_init(void) { struct mlxplat_priv *priv; - int i, err; + int i, nr, err; if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; @@ -866,7 +910,12 @@ static int __init mlxplat_init(void) } platform_set_drvdata(mlxplat_dev, priv); - priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, + err = mlxplat_mlxcpld_verify_bus_topology(&nr); + if (nr < 0) + goto fail_alloc; + + nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr; + priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr, NULL, 0); if (IS_ERR(priv->pdev_i2c)) { err = PTR_ERR(priv->pdev_i2c); diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h index 262910967476..2744cff1b297 100644 --- a/include/linux/platform_data/mlxreg.h +++ b/include/linux/platform_data/mlxreg.h @@ -130,6 +130,7 @@ struct mlxreg_core_platform_data { * @cell_low: location of low aggregation interrupt register; * @mask_low: low aggregation interrupt common mask; * @deferred_nr: I2C adapter number must be exist prior probing execution; + * @shift_nr: I2C adapter numbers must be incremented by this value; */ struct mlxreg_core_hotplug_platform_data { struct mlxreg_core_item *items; @@ -141,6 +142,7 @@ struct mlxreg_core_hotplug_platform_data { u32 cell_low; u32 mask_low; int deferred_nr; + int shift_nr; }; #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */