mfd: khadas-mcu: Add support for VIM4 MCU variant

Refactor probe() to use per-variant values
instead of hardcoded globals.

Add dedicated regmap configuration for the VIM4 MCU,
with its own volatile/writeable registers.

Add a new compatible string "khadas,vim4-mcu".

Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
Link: https://patch.msgid.link/20260917-add-mcu-fan-khadas-vim4-v12-3-497cd543a148@aliel.fr
Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
Ronald Claveau 2026-09-17 09:59:02 +02:00 committed by Lee Jones
parent f9f61c21b9
commit c94c97f8c9

View File

@ -84,38 +84,107 @@ static const struct mfd_cell khadas_mcu_cells[] = {
MFD_CELL_NAME("khadas-mcu-user-mem"),
};
static bool khadas_mcu_vim4_reg_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
case KHADAS_MCU_PWR_OFF_CMD_REG:
case KHADAS_MCU_VIM4_REST_CONF_REG:
case KHADAS_MCU_WOL_INIT_START_REG:
case KHADAS_MCU_VIM4_LED_ON_RAM_REG:
case KHADAS_MCU_VIM4_FAN_CTRL_REG:
case KHADAS_MCU_VIM4_WDT_EN_REG:
case KHADAS_MCU_VIM4_SYS_RST_REG:
return true;
default:
return false;
}
}
static bool khadas_mcu_vim4_reg_writeable(struct device *dev, unsigned int reg)
{
switch (reg) {
case KHADAS_MCU_VERSION_0_REG:
case KHADAS_MCU_VERSION_1_REG:
case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
return false;
default:
return true;
}
}
static const struct regmap_config khadas_mcu_vim4_regmap_config = {
.reg_bits = 8,
.reg_stride = 1,
.val_bits = 8,
.max_register = KHADAS_MCU_VIM4_SYS_RST_REG,
.volatile_reg = khadas_mcu_vim4_reg_volatile,
.writeable_reg = khadas_mcu_vim4_reg_writeable,
.cache_type = REGCACHE_MAPLE,
};
static const struct mfd_cell khadas_mcu_vim4_fan_cells[] = {
MFD_CELL_NAME("khadas-mcu-vim4-fan"),
};
static int khadas_mcu_probe(struct i2c_client *client)
{
const struct mfd_cell *cells, *fan_cells;
const struct regmap_config *regmap_cfg;
struct device *dev = &client->dev;
int ncells, nfan_cells, ret;
struct khadas_mcu *ddata;
int ret;
const void *mcu_variant;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
mcu_variant = i2c_get_match_data(client);
if (!mcu_variant)
return -ENODEV;
switch ((uintptr_t)mcu_variant) {
case KHADAS_MCU_GENERIC:
regmap_cfg = &khadas_mcu_regmap_config;
cells = khadas_mcu_cells;
ncells = ARRAY_SIZE(khadas_mcu_cells);
fan_cells = khadas_mcu_fan_cells;
nfan_cells = ARRAY_SIZE(khadas_mcu_fan_cells);
break;
case KHADAS_MCU_VIM4:
regmap_cfg = &khadas_mcu_vim4_regmap_config;
cells = NULL;
ncells = 0;
fan_cells = khadas_mcu_vim4_fan_cells;
nfan_cells = ARRAY_SIZE(khadas_mcu_vim4_fan_cells);
break;
default:
return -ENODEV;
}
i2c_set_clientdata(client, ddata);
ddata->dev = dev;
ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
ddata->regmap = devm_regmap_init_i2c(client, regmap_cfg);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
return dev_err_probe(dev, ret, "Failed to allocate register map\n");
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
khadas_mcu_cells,
ARRAY_SIZE(khadas_mcu_cells),
NULL, 0, NULL);
if (ret)
return ret;
if (cells && ncells) {
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
cells,
ncells,
NULL, 0, NULL);
if (ret)
return ret;
}
if (of_property_present(dev->of_node, "#cooling-cells"))
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
khadas_mcu_fan_cells,
ARRAY_SIZE(khadas_mcu_fan_cells),
fan_cells,
nfan_cells,
NULL, 0, NULL);
return 0;
@ -123,7 +192,8 @@ static int khadas_mcu_probe(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id khadas_mcu_of_match[] = {
{ .compatible = "khadas,mcu", },
{ .compatible = "khadas,mcu", .data = (void *)KHADAS_MCU_GENERIC },
{ .compatible = "khadas,vim4-mcu", .data = (void *)KHADAS_MCU_VIM4 },
{},
};
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);