This patch adds:
- Support of Mellanox LED driver leds-mlxreg activation from mlx-platform.
  This LED driver uses the same regmap infrastructure as others Mellanox
  platform drivers.
- LED specific registers description.
- Per system type LED description, which is passed to LED driver.
- Static inline functions for adding and removing platform drivers sharing
  the same regmap infrastructure.
  Motivation of adding them as a static inline to the header file is to
  allow reusing of them by not only x86 architecture specific platform
  driver.

Signed-off-by: Vadim Pasternak <[email protected]>
---
 drivers/platform/x86/mlx-platform.c  | 290 +++++++++++++++++++++++++++++++++++
 include/linux/platform_data/mlxreg.h |  63 ++++++++
 2 files changed, 353 insertions(+)

diff --git a/drivers/platform/x86/mlx-platform.c 
b/drivers/platform/x86/mlx-platform.c
index 912f844..efb605a 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -47,6 +47,11 @@
 /* LPC bus IO offsets */
 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR         0x2000
 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR         0x2500
+#define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET       0x20
+#define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET       0x21
+#define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET       0x22
+#define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET       0x23
+#define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET       0x24
 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET       0x3a
 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET  0x3b
 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET     0x40
@@ -84,6 +89,8 @@
 #define MLXPLAT_CPLD_PWR_MASK          GENMASK(1, 0)
 #define MLXPLAT_CPLD_FAN_MASK          GENMASK(3, 0)
 #define MLXPLAT_CPLD_FAN_NG_MASK       GENMASK(5, 0)
+#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK        GENMASK(7, 4)
+#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK        GENMASK(3, 0)
 
 /* Default I2C parent bus number */
 #define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR       1
@@ -114,11 +121,13 @@
  * @pdev_i2c - i2c controller platform device
  * @pdev_mux - array of mux platform devices
  * @pdev_hotplug - hotplug platform devices
+ * @platform_items - platform devices container
  */
 struct mlxplat_priv {
        struct platform_device *pdev_i2c;
        struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
        struct platform_device *pdev_hotplug;
+       struct mlxreg_core_platform_drivers *platform_items;
 };
 
 /* Regions for LPC I2C controller and LPC base register space */
@@ -592,9 +601,251 @@ struct mlxreg_core_hotplug_platform_data 
mlxplat_mlxcpld_default_ng_data = {
        .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
 };
 
+/* Platform led default data */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "psu:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_led_data = {
+               .data = mlxplat_mlxcpld_default_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data),
+};
+
+/* Platform led MSN21xx system family data */
+static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "fan:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu1:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "psu2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu2:red",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "uid:blue",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = {
+               .data = mlxplat_mlxcpld_msn21xx_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data),
+};
+
+/* Platform led for default data for 200GbE systems */
+static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = {
+       {
+               .label = "status:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "status:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+       },
+       {
+               .label = "psu:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "psu:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan1:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan2:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan3:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan4:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan5:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan5:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+       },
+       {
+               .label = "fan6:green",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+       {
+               .label = "fan6:orange",
+               .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+               .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+       },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = {
+               .data = mlxplat_mlxcpld_default_ng_led_data,
+               .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data),
+};
+
+/* Core platform devices */
+static struct mlxreg_core_platform_driver
+                       mlxplat_mlxcpld_default_core_platform_drivers[] = {
+       {
+               .name = "leds-mlxreg",
+               .mlxreg_core_pdata = &mlxplat_default_led_data,
+       },
+};
+
+static struct mlxreg_core_platform_driver
+                       mlxplat_mlxcpld_msn21xx_core_platform_drivers[] = {
+       {
+               .name = "leds-mlxreg",
+               .mlxreg_core_pdata = &mlxplat_msn21xx_led_data,
+       },
+};
+
+static struct mlxreg_core_platform_driver
+                       mlxplat_mlxcpld_default_ng_core_platform_drivers[] = {
+       {
+               .name = "leds-mlxreg",
+               .mlxreg_core_pdata = &mlxplat_default_ng_led_data,
+       },
+};
+
 static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET:
@@ -611,6 +862,11 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device 
*dev, unsigned int reg)
 static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
@@ -632,6 +888,11 @@ static bool mlxplat_mlxcpld_readable_reg(struct device 
*dev, unsigned int reg)
 static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
+       case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET:
+       case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
        case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
@@ -692,6 +953,7 @@ static struct resource mlxplat_mlxcpld_resources[] = {
 
 static struct platform_device *mlxplat_dev;
 static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
+static struct mlxreg_core_platform_drivers mlxplat_platform_devs;
 
 static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
 {
@@ -705,6 +967,10 @@ static int __init mlxplat_dmi_default_matched(const struct 
dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_platform_devs.pdrv =
+                       mlxplat_mlxcpld_default_core_platform_drivers;
+       mlxplat_platform_devs.pdrvs_num =
+               ARRAY_SIZE(mlxplat_mlxcpld_default_core_platform_drivers);
 
        return 1;
 };
@@ -721,6 +987,10 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct 
dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_platform_devs.pdrv =
+                       mlxplat_mlxcpld_msn21xx_core_platform_drivers;
+       mlxplat_platform_devs.pdrvs_num =
+               ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_core_platform_drivers);
 
        return 1;
 };
@@ -737,6 +1007,10 @@ static int __init mlxplat_dmi_msn274x_matched(const 
struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_platform_devs.pdrv =
+                       mlxplat_mlxcpld_default_core_platform_drivers;
+       mlxplat_platform_devs.pdrvs_num =
+               ARRAY_SIZE(mlxplat_mlxcpld_default_core_platform_drivers);
 
        return 1;
 };
@@ -753,6 +1027,10 @@ static int __init mlxplat_dmi_msn201x_matched(const 
struct dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_platform_devs.pdrv =
+                       mlxplat_mlxcpld_msn21xx_core_platform_drivers;
+       mlxplat_platform_devs.pdrvs_num =
+               ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_core_platform_drivers);
 
        return 1;
 };
@@ -769,6 +1047,10 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct 
dmi_system_id *dmi)
        mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
        mlxplat_hotplug->deferred_nr =
                mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+       mlxplat_platform_devs.pdrv =
+                       mlxplat_mlxcpld_default_ng_core_platform_drivers;
+       mlxplat_platform_devs.pdrvs_num =
+               ARRAY_SIZE(mlxplat_mlxcpld_default_ng_core_platform_drivers);
 
        return 1;
 };
@@ -990,6 +1272,13 @@ static int __init mlxplat_init(void)
                goto fail_platform_mux_register;
        }
 
+       /* Add platform drivers. */
+       err = mlxreg_core_add_platform_drivers(&mlxplat_dev->dev,
+                                              &mlxplat_platform_devs,
+                                              mlxplat_hotplug->regmap);
+       if (err)
+               goto fail_platform_hotplug_register;
+
        /* Sync registers with hardware. */
        regcache_mark_dirty(mlxplat_hotplug->regmap);
        err = regcache_sync(mlxplat_hotplug->regmap);
@@ -1016,6 +1305,7 @@ static void __exit mlxplat_exit(void)
        struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
        int i;
 
+       mlxreg_core_remove_platform_drivers(&mlxplat_platform_devs);
        platform_device_unregister(priv->pdev_hotplug);
 
        for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
diff --git a/include/linux/platform_data/mlxreg.h 
b/include/linux/platform_data/mlxreg.h
index 19f5cb61..efc30a7 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -144,4 +144,67 @@ struct mlxreg_core_hotplug_platform_data {
        int shift_nr;
 };
 
+/* mlxreg_core_platform_driver - platform driver specification
+ * @name - platform driver name;
+ * @regmap - register map shared between all the drivers;
+ * @pdev - platform device;
+ * @mlxreg_core_pdata - platform driver data;
+ */
+struct mlxreg_core_platform_driver {
+       const char *name;
+       void *regmap;
+       struct platform_device *pdev;
+       struct mlxreg_core_platform_data *mlxreg_core_pdata;
+};
+
+/* mlxreg_core_platform_drivers - platform drivers container
+ * @pdrv - platform driver container;
+ * @pdrvs_num - number of core platform drivers;
+ */
+struct mlxreg_core_platform_drivers {
+       struct mlxreg_core_platform_driver *pdrv;
+       int pdrvs_num;
+};
+
+static inline int
+mlxreg_core_add_platform_drivers(struct device *dev,
+               struct mlxreg_core_platform_drivers *pdrvs, void *regmap)
+{
+       struct mlxreg_core_platform_driver *item;
+       int i, err;
+
+       for (i = 0; i < pdrvs->pdrvs_num; i++, item++) {
+               item = pdrvs->pdrv + i;
+               item->regmap = regmap;
+               item->pdev = platform_device_register_resndata(dev, item->name,
+                                       PLATFORM_DEVID_NONE, NULL, 0,
+                                       item->mlxreg_core_pdata,
+                                       sizeof(*item->mlxreg_core_pdata));
+               if (IS_ERR(item->pdev)) {
+                       err = PTR_ERR(item->pdev);
+                       goto fail;
+               }
+       }
+
+       return 0;
+
+fail:
+       while (--i >= 0)
+               platform_device_unregister(--item->pdev);
+
+       return err;
+}
+
+static inline void
+mlxreg_core_remove_platform_drivers(struct mlxreg_core_platform_drivers *pdrvs)
+{
+       struct mlxreg_core_platform_driver *item;
+       int i;
+
+       for (i = pdrvs->pdrvs_num - 1; i >= 0 ; i--) {
+               item = pdrvs->pdrv + i;
+               platform_device_unregister(item->pdev);
+       }
+}
+
 #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
-- 
2.1.4

Reply via email to