Commit c6acad68 authored by Vadim Pasternak's avatar Vadim Pasternak Committed by Darren Hart (VMware)

platform/mellanox: mlxreg-hotplug: Modify to use a regmap interface

Restructure mlxreg header for unification of hotplug item definitions.

Unify hotplug items to allow any kind of item (power controller, fan
eeprom, psu eeprom, asic health) in common way.

Use a hardware independent regmap interface, enabling the support of
hotplug events over programmable devices attached to different bus
types, such as I2C, LPC, or SPI. Add a device node to the
mlxreg_core_data structure.
Signed-off-by: default avatarVadim Pasternak <vadimp@mellanox.com>
Acked-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
[dvhart: spelling corrections, refactor device node introduction]
Signed-off-by: default avatarDarren Hart (VMware) <dvhart@infradead.org>
parent 752849e6
...@@ -16,6 +16,7 @@ if MELLANOX_PLATFORM ...@@ -16,6 +16,7 @@ if MELLANOX_PLATFORM
config MLXREG_HOTPLUG config MLXREG_HOTPLUG
tristate "Mellanox platform hotplug driver support" tristate "Mellanox platform hotplug driver support"
depends on REGMAP
depends on HWMON depends on HWMON
depends on I2C depends on I2C
---help--- ---help---
......
This diff is collapsed.
...@@ -35,20 +35,22 @@ ...@@ -35,20 +35,22 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/platform_data/i2c-mux-reg.h> #include <linux/platform_data/i2c-mux-reg.h>
#include <linux/platform_data/mlxreg.h> #include <linux/platform_data/mlxreg.h>
#include <linux/regmap.h>
#define MLX_PLAT_DEVICE_NAME "mlxplat" #define MLX_PLAT_DEVICE_NAME "mlxplat"
/* LPC bus IO offsets */ /* LPC bus IO offsets */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58
#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 #define MLXPLAT_CPLD_LPC_REG_PWR_OFFSET 0x64
#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
...@@ -138,78 +140,194 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { ...@@ -138,78 +140,194 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
}; };
/* Platform hotplug devices */ /* Platform hotplug devices */
static struct mlxreg_hotplug_device mlxplat_mlxcpld_psu[] = { static struct i2c_board_info mlxplat_mlxcpld_psu[] = {
{ {
.brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, I2C_BOARD_INFO("24c02", 0x51),
.nr = 10,
}, },
{ {
.brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, I2C_BOARD_INFO("24c02", 0x50),
.nr = 10,
}, },
}; };
static struct mlxreg_hotplug_device mlxplat_mlxcpld_pwr[] = { static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
{ {
.brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, I2C_BOARD_INFO("dps460", 0x59),
.nr = 10,
}, },
{ {
.brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, I2C_BOARD_INFO("dps460", 0x58),
.nr = 10,
}, },
}; };
static struct mlxreg_hotplug_device mlxplat_mlxcpld_fan[] = { static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
{ {
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, I2C_BOARD_INFO("24c32", 0x50),
.nr = 11,
}, },
{ {
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, I2C_BOARD_INFO("24c32", 0x50),
.nr = 12,
}, },
{ {
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, I2C_BOARD_INFO("24c32", 0x50),
.nr = 13,
}, },
{ {
.brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, I2C_BOARD_INFO("24c32", 0x50),
.nr = 14,
}, },
}; };
/* Platform hotplug default data */ /* Platform hotplug default data */
static struct mlxreg_core_data mlxplat_mlxcpld_default_psu_items_data[] = {
{
.label = "psu1",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(0),
.hpdev.brdinfo = &mlxplat_mlxcpld_psu[0],
.hpdev.nr = 10,
},
{
.label = "psu2",
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = BIT(1),
.hpdev.brdinfo = &mlxplat_mlxcpld_psu[1],
.hpdev.nr = 10,
},
};
static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_items_data[] = {
{
.label = "pwr1",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(0),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[0],
.hpdev.nr = 10,
},
{
.label = "pwr2",
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = BIT(1),
.hpdev.brdinfo = &mlxplat_mlxcpld_pwr[1],
.hpdev.nr = 10,
},
};
static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
{
.label = "fan1",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = BIT(0),
.hpdev.brdinfo = &mlxplat_mlxcpld_fan[0],
.hpdev.nr = 11,
},
{
.label = "fan2",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = BIT(1),
.hpdev.brdinfo = &mlxplat_mlxcpld_fan[1],
.hpdev.nr = 12,
},
{
.label = "fan3",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = BIT(2),
.hpdev.brdinfo = &mlxplat_mlxcpld_fan[2],
.hpdev.nr = 13,
},
{
.label = "fan4",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = BIT(3),
.hpdev.brdinfo = &mlxplat_mlxcpld_fan[3],
.hpdev.nr = 14,
},
};
static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = {
{
.data = mlxplat_mlxcpld_default_psu_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
.mask = MLXPLAT_CPLD_PSU_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
.inversed = 1,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_pwr_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = MLXPLAT_CPLD_PWR_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
.inversed = 0,
.health = false,
},
{
.data = mlxplat_mlxcpld_default_fan_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
.mask = MLXPLAT_CPLD_FAN_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
.inversed = 1,
.health = false,
},
};
static static
struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_default_data = { struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = {
.top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, .items = mlxplat_mlxcpld_default_items,
.top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items),
.top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
.psu_mask = MLXPLAT_CPLD_PSU_MASK,
.psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu),
.psu = mlxplat_mlxcpld_psu,
.top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
.pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR,
.pwr_mask = MLXPLAT_CPLD_PWR_MASK,
.pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
.pwr = mlxplat_mlxcpld_pwr,
.top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF,
.fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR,
.fan_mask = MLXPLAT_CPLD_FAN_MASK,
.fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan),
.fan = mlxplat_mlxcpld_fan,
}; };
/* Platform hotplug MSN21xx system family data */ /* Platform hotplug MSN21xx system family data */
static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = {
{
.data = mlxplat_mlxcpld_default_pwr_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF,
.reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
.mask = MLXPLAT_CPLD_PWR_MASK,
.count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
.inversed = 0,
.health = false,
},
};
static static
struct mlxreg_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = {
.top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, .items = mlxplat_mlxcpld_msn21xx_items,
.top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_items),
.top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, .mask = MLXPLAT_CPLD_AGGR_MASK_DEF,
.pwr_mask = MLXPLAT_CPLD_PWR_MASK, };
.pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr),
struct mlxplat_mlxcpld_regmap_context {
void __iomem *base;
};
static struct mlxplat_mlxcpld_regmap_context mlxplat_mlxcpld_regmap_ctx;
static int
mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct mlxplat_mlxcpld_regmap_context *ctx = context;
*val = ioread8(ctx->base + reg);
return 0;
}
static int
mlxplat_mlxcpld_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct mlxplat_mlxcpld_regmap_context *ctx = context;
iowrite8(val, ctx->base + reg);
return 0;
}
static const struct regmap_config mlxplat_mlxcpld_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 255,
.reg_read = mlxplat_mlxcpld_reg_read,
.reg_write = mlxplat_mlxcpld_reg_write,
}; };
static struct resource mlxplat_mlxcpld_resources[] = { static struct resource mlxplat_mlxcpld_resources[] = {
...@@ -217,7 +335,7 @@ static struct resource mlxplat_mlxcpld_resources[] = { ...@@ -217,7 +335,7 @@ static struct resource mlxplat_mlxcpld_resources[] = {
}; };
static struct platform_device *mlxplat_dev; static struct platform_device *mlxplat_dev;
static struct mlxreg_hotplug_platform_data *mlxplat_hotplug; static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{ {
...@@ -328,6 +446,21 @@ static int __init mlxplat_init(void) ...@@ -328,6 +446,21 @@ static int __init mlxplat_init(void)
} }
} }
mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
mlxplat_lpc_resources[1].start, 1);
if (IS_ERR(mlxplat_mlxcpld_regmap_ctx.base)) {
err = PTR_ERR(mlxplat_mlxcpld_regmap_ctx.base);
goto fail_platform_mux_register;
}
mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
&mlxplat_mlxcpld_regmap_ctx,
&mlxplat_mlxcpld_regmap_config);
if (IS_ERR(mlxplat_hotplug->regmap)) {
err = PTR_ERR(mlxplat_hotplug->regmap);
goto fail_platform_mux_register;
}
priv->pdev_hotplug = platform_device_register_resndata( priv->pdev_hotplug = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-hotplug", &mlxplat_dev->dev, "mlxreg-hotplug",
PLATFORM_DEVID_NONE, PLATFORM_DEVID_NONE,
......
...@@ -34,8 +34,11 @@ ...@@ -34,8 +34,11 @@
#ifndef __LINUX_PLATFORM_DATA_MLXREG_H #ifndef __LINUX_PLATFORM_DATA_MLXREG_H
#define __LINUX_PLATFORM_DATA_MLXREG_H #define __LINUX_PLATFORM_DATA_MLXREG_H
#define MLXREG_CORE_LABEL_MAX_SIZE 32
/** /**
* struct mlxreg_hotplug_device - I2C device data: * struct mlxreg_hotplug_device - I2C device data:
*
* @adapter: I2C device adapter; * @adapter: I2C device adapter;
* @client: I2C device client; * @client: I2C device client;
* @brdinfo: device board information; * @brdinfo: device board information;
...@@ -47,52 +50,95 @@ ...@@ -47,52 +50,95 @@
struct mlxreg_hotplug_device { struct mlxreg_hotplug_device {
struct i2c_adapter *adapter; struct i2c_adapter *adapter;
struct i2c_client *client; struct i2c_client *client;
struct i2c_board_info brdinfo; struct i2c_board_info *brdinfo;
int nr; int nr;
}; };
/** /**
* struct mlxreg_hotplug_platform_data - device platform data: * struct mlxreg_core_data - attributes control data:
* @top_aggr_offset: offset of top aggregation interrupt register; *
* @top_aggr_mask: top aggregation interrupt common mask; * @label: attribute label;
* @top_aggr_psu_mask: top aggregation interrupt PSU mask; * @label: attribute register offset;
* @psu_reg_offset: offset of PSU interrupt register; * @reg: attribute register;
* @psu_mask: PSU interrupt mask; * @mask: attribute access mask;
* @psu_count: number of equipped replaceable PSUs; * @mode: access mode;
* @psu: pointer to PSU devices data array; * @bit: attribute effective bit;
* @top_aggr_pwr_mask: top aggregation interrupt power mask; * @np - pointer to node platform associated with attribute;
* @pwr_reg_offset: offset of power interrupt register * @hpdev - hotplug device data;
* @pwr_mask: power interrupt mask; * @health_cntr: dynamic device health indication counter;
* @pwr_count: number of power sources; * @attached: true if device has been attached after good health indication;
* @pwr: pointer to power devices data array; */
* @top_aggr_fan_mask: top aggregation interrupt FAN mask; struct mlxreg_core_data {
* @fan_reg_offset: offset of FAN interrupt register; char label[MLXREG_CORE_LABEL_MAX_SIZE];
* @fan_mask: FAN interrupt mask; u32 reg;
* @fan_count: number of equipped replaceable FANs; u32 mask;
* @fan: pointer to FAN devices data array; u32 bit;
umode_t mode;
struct device_node *np;
struct mlxreg_hotplug_device hpdev;
u8 health_cntr;
bool attached;
};
/**
* struct mlxreg_core_item - same type components controlled by the driver:
*
* @data: component data;
* @aggr_mask: group aggregation mask;
* @reg: group interrupt status register;
* @mask: group interrupt mask;
* @cache: last status value for elements fro the same group;
* @count: number of available elements in the group;
* @ind: element's index inside the group;
* @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
* @health: true if device has health indication, false in other case;
*/
struct mlxreg_core_item {
struct mlxreg_core_data *data;
u32 aggr_mask;
u32 reg;
u32 mask;
u32 cache;
u8 count;
u8 ind;
u8 inversed;
u8 health;
};
/**
* struct mlxreg_core_platform_data - platform data:
*
* @led_data: led private data;
* @regmap: register map of parent device;
* @counter: number of led instances;
*/
struct mlxreg_core_platform_data {
struct mlxreg_core_data *data;
void *regmap;
int counter;
};
/**
* struct mlxreg_core_hotplug_platform_data - hotplug platform data:
* *
* Structure represents board platform data, related to system hotplug events, * @items: same type components with the hotplug capability;
* like FAN, PSU, power cable insertion and removing. This data provides the * @irq: platform interrupt number;
* number of hot-pluggable devices and hardware description for event handling. * @regmap: register map of parent device;
* @counter: number of the components with the hotplug capability;
* @cell: location of top aggregation interrupt register;
* @mask: top aggregation interrupt common mask;
* @cell_low: location of low aggregation interrupt register;
* @mask_low: low aggregation interrupt common mask;
*/ */
struct mlxreg_hotplug_platform_data { struct mlxreg_core_hotplug_platform_data {
u16 top_aggr_offset; struct mlxreg_core_item *items;
u8 top_aggr_mask; int irq;
u8 top_aggr_psu_mask; void *regmap;
u16 psu_reg_offset; int counter;
u8 psu_mask; u32 cell;
u8 psu_count; u32 mask;
struct mlxreg_hotplug_device *psu; u32 cell_low;
u8 top_aggr_pwr_mask; u32 mask_low;
u16 pwr_reg_offset;
u8 pwr_mask;
u8 pwr_count;
struct mlxreg_hotplug_device *pwr;
u8 top_aggr_fan_mask;
u16 fan_reg_offset;
u8 fan_mask;
u8 fan_count;
struct mlxreg_hotplug_device *fan;
}; };
#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */ #endif /* __LINUX_PLATFORM_DATA_MLXREG_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment