From e06cc12b569bfa1d06d9f0c4ea0459b52869f1e1 Mon Sep 17 00:00:00 2001 From: Muhammed Efe Cetin Date: Sun, 17 Mar 2024 14:30:35 +0300 Subject: [PATCH] mfd: backport khadas mcu driver changes from armbian rockchip-rk3588-edge kernel --- .../devicetree/bindings/mfd/khadas,mcu.yaml | 7 +- drivers/mfd/khadas-mcu.c | 22 ++---- drivers/thermal/khadas_mcu_fan.c | 77 ++++++++++++++++++- include/linux/mfd/khadas-mcu.h | 24 ++++++ 4 files changed, 110 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml index 084960fd5a1fd..cf46b690010f2 100644 --- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml +++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml @@ -11,7 +11,7 @@ maintainers: description: | Khadas embeds a microcontroller on their VIM and Edge boards adding some - system feature as PWM Fan control (for VIM2 rev14 or VIM3), User memory + system feature as PWM Fan control (for VIM2 rev14, VIM3, Edge2), User memory storage, IR/Key resume control, system power LED control and more. properties: @@ -22,6 +22,11 @@ properties: "#cooling-cells": # Only needed for boards having FAN control feature const: 2 + cooling-levels: + description: Max speed of PWM fan. This property is necessary for Khadas Edge 2. + items: + maximum: 100 + reg: maxItems: 1 diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c index f3d418810693c..ff606e65285f1 100644 --- a/drivers/mfd/khadas-mcu.c +++ b/drivers/mfd/khadas-mcu.c @@ -26,6 +26,10 @@ static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg) case KHADAS_MCU_CHECK_USER_PASSWD_REG: case KHADAS_MCU_WOL_INIT_START_REG: case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG: + case KHADAS_MCU_LED_ON_RAM_REG: + case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG_V2: + case KHADAS_MCU_WDT_EN_REG: + case KHADAS_MCU_SYS_RST_REG: return true; default: return false; @@ -69,23 +73,18 @@ static const struct regmap_config khadas_mcu_regmap_config = { .reg_bits = 8, .reg_stride = 1, .val_bits = 8, - .max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG, + .max_register = KHADAS_MCU_SYS_RST_REG, .volatile_reg = khadas_mcu_reg_volatile, .writeable_reg = khadas_mcu_reg_writeable, .cache_type = REGCACHE_RBTREE, }; static struct mfd_cell khadas_mcu_fan_cells[] = { - /* VIM1/2 Rev13+ and VIM3 only */ + /* VIM1/2 Rev13+, VIM3 and Edge2 only */ { .name = "khadas-mcu-fan-ctrl", }, }; -static struct mfd_cell khadas_mcu_cells[] = { - { .name = "khadas-mcu-user-mem", }, -}; - -static int khadas_mcu_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int khadas_mcu_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; struct khadas_mcu *ddata; @@ -106,13 +105,6 @@ static int khadas_mcu_probe(struct i2c_client *client, return ret; } - 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 (of_find_property(dev->of_node, "#cooling-cells", NULL)) return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, khadas_mcu_fan_cells, diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c index d35e5313bea41..a020ef3c86c7d 100644 --- a/drivers/thermal/khadas_mcu_fan.c +++ b/drivers/thermal/khadas_mcu_fan.c @@ -15,10 +15,16 @@ #include #define MAX_LEVEL 3 +#define MAX_SPEED 0x64 struct khadas_mcu_fan_ctx { struct khadas_mcu *mcu; unsigned int level; + + unsigned int fan_max_level; + unsigned int fan_register; + unsigned int *fan_cooling_levels; + struct thermal_cooling_device *cdev; }; @@ -26,9 +32,21 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx, unsigned int level) { int ret; + unsigned int write_level = level; + + if (level > ctx->fan_max_level) + return -EINVAL; + + if (ctx->fan_cooling_levels != NULL) { + write_level = ctx->fan_cooling_levels[level]; + + if (write_level > MAX_SPEED) + return -EINVAL; + } + + ret = regmap_write(ctx->mcu->regmap, ctx->fan_register, + write_level); - ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG, - level); if (ret) return ret; @@ -40,7 +58,9 @@ static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx, static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { - *state = MAX_LEVEL; + struct khadas_mcu_fan_ctx *ctx = cdev->devdata; + + *state = ctx->fan_max_level; return 0; } @@ -61,7 +81,7 @@ khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev, { struct khadas_mcu_fan_ctx *ctx = cdev->devdata; - if (state > MAX_LEVEL) + if (state > ctx->fan_max_level) return -EINVAL; if (state == ctx->level) @@ -76,6 +96,48 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +// Khadas Edge 2 sets fan level by passing fan speed(0-100). So we need different logic here like pwm-fan cooling-levels. +// This is optional and just necessary for Edge 2. +static int khadas_mcu_fan_get_cooling_data_edge2(struct khadas_mcu_fan_ctx *ctx, struct device *dev) { + struct device_node *np = ctx->mcu->dev->of_node; + int num, i, ret; + + if (!of_find_property(np, "cooling-levels", NULL)) + return 0; + + ret = of_property_count_u32_elems(np, "cooling-levels"); + if (ret <= 0) { + dev_err(dev, "Wrong data!\n"); + return ret ? : -EINVAL; + } + + num = ret; + ctx->fan_cooling_levels = devm_kcalloc(dev, num, sizeof(u32), + GFP_KERNEL); + if (!ctx->fan_cooling_levels) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "cooling-levels", + ctx->fan_cooling_levels, num); + if (ret) { + dev_err(dev, "Property 'cooling-levels' cannot be read!\n"); + return ret; + } + + for (i = 0; i < num; i++) { + if (ctx->fan_cooling_levels[i] > MAX_SPEED) { + dev_err(dev, "PWM fan state[%d]:%d > %d\n", i, + ctx->fan_cooling_levels[i], MAX_SPEED); + return -EINVAL; + } + } + + ctx->fan_max_level = num - 1; + ctx->fan_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG_V2; + + return 0; +} + static int khadas_mcu_fan_probe(struct platform_device *pdev) { struct khadas_mcu *mcu = dev_get_drvdata(pdev->dev.parent); @@ -90,6 +152,13 @@ static int khadas_mcu_fan_probe(struct platform_device *pdev) ctx->mcu = mcu; platform_set_drvdata(pdev, ctx); + ctx->fan_max_level = MAX_LEVEL; + ctx->fan_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG; + + ret = khadas_mcu_fan_get_cooling_data_edge2(ctx, dev); + if (ret) + return ret; + cdev = devm_thermal_of_cooling_device_register(dev->parent, dev->parent->of_node, "khadas-mcu-fan", ctx, &khadas_mcu_fan_cooling_ops); diff --git a/include/linux/mfd/khadas-mcu.h b/include/linux/mfd/khadas-mcu.h index a99ba2ed0e4e0..63bc9bf76661d 100644 --- a/include/linux/mfd/khadas-mcu.h +++ b/include/linux/mfd/khadas-mcu.h @@ -35,26 +35,45 @@ #define KHADAS_MCU_FACTORY_TEST_REG 0x16 /* R */ #define KHADAS_MCU_BOOT_MODE_REG 0x20 /* RW */ #define KHADAS_MCU_BOOT_EN_WOL_REG 0x21 /* RW */ +#define KHADAS_MCU_BOOT_EN_DCIN_REG_V2 0x21 /* RW */ #define KHADAS_MCU_BOOT_EN_RTC_REG 0x22 /* RW */ #define KHADAS_MCU_BOOT_EN_EXP_REG 0x23 /* RW */ +#define KHADAS_MCU_LED_MODE_ON_REG_V2 0x23 /* RW */ +#define KHADAS_MCU_LED_MODE_OFF_REG_V2 0x24 /* RW */ #define KHADAS_MCU_BOOT_EN_IR_REG 0x24 /* RW */ #define KHADAS_MCU_BOOT_EN_DCIN_REG 0x25 /* RW */ +#define KHADAS_MCU_RGB_ON_R_REG 0x25 /* RW */ +#define KHADAS_MCU_RGB_ON_G_REG 0x26 /* RW */ #define KHADAS_MCU_BOOT_EN_KEY_REG 0x26 /* RW */ +#define KHADAS_MCU_RGB_ON_B_REG 0x27 /* RW */ #define KHADAS_MCU_KEY_MODE_REG 0x27 /* RW */ +#define KHADAS_MCU_RGB_OFF_R_REG 0x28 /* RW */ #define KHADAS_MCU_LED_MODE_ON_REG 0x28 /* RW */ +#define KHADAS_MCU_RGB_OFF_G_REG 0x29 /* RW */ #define KHADAS_MCU_LED_MODE_OFF_REG 0x29 /* RW */ +#define KHADAS_MCU_RGB_OFF_B_REG 0x2a /* RW */ #define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c /* RW */ #define KHADAS_MCU_MAC_SWITCH_REG 0x2d /* RW */ +#define KHADAS_MCU_REST_CONF_REG 0x2e /* RW */ #define KHADAS_MCU_MCU_SLEEP_MODE_REG 0x2e /* RW */ +#define KHADAS_MCU_BOOT_EN_IR_REG_V2 0x2f /* RW */ #define KHADAS_MCU_IR_CODE1_0_REG 0x2f /* RW */ #define KHADAS_MCU_IR_CODE1_1_REG 0x30 /* RW */ +#define KHADAS_MCU_IR1_CUST1_REG 0x30 /* RW */ #define KHADAS_MCU_IR_CODE1_2_REG 0x31 /* RW */ +#define KHADAS_MCU_IR1_CUST2_REG 0x31 /* RW */ #define KHADAS_MCU_IR_CODE1_3_REG 0x32 /* RW */ +#define KHADAS_MCU_IR1_ORDER1_REG 0x32 /* RW */ #define KHADAS_MCU_USB_PCIE_SWITCH_REG 0x33 /* RW */ +#define KHADAS_MCU_IR1_ORDER2_REG 0x33 /* RW */ +#define KHADAS_MCU_IR2_CUST1_REG 0x34 /* RW */ #define KHADAS_MCU_IR_CODE2_0_REG 0x34 /* RW */ #define KHADAS_MCU_IR_CODE2_1_REG 0x35 /* RW */ +#define KHADAS_MCU_IR2_CUST2_REG 0x35 /* RW */ #define KHADAS_MCU_IR_CODE2_2_REG 0x36 /* RW */ +#define KHADAS_MCU_IR2_ORDER1_REG 0x36 /* RW */ #define KHADAS_MCU_IR_CODE2_3_REG 0x37 /* RW */ +#define KHADAS_MCU_IR2_ORDER2_REG 0x36 /* RW */ #define KHADAS_MCU_PASSWD_USER_0_REG 0x40 /* RW */ #define KHADAS_MCU_PASSWD_USER_1_REG 0x41 /* RW */ #define KHADAS_MCU_PASSWD_USER_2_REG 0x42 /* RW */ @@ -69,6 +88,10 @@ #define KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG 0x86 /* RO */ #define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */ #define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */ +#define KHADAS_MCU_LED_ON_RAM_REG 0x89 /* WO */ +#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG_V2 0x8A /* WO */ +#define KHADAS_MCU_WDT_EN_REG 0x8B /* WO */ +#define KHADAS_MCU_SYS_RST_REG 0x91 /* WO */ enum { KHADAS_BOARD_VIM1 = 0x1, @@ -76,6 +99,7 @@ enum { KHADAS_BOARD_VIM3, KHADAS_BOARD_EDGE = 0x11, KHADAS_BOARD_EDGE_V, + KHADAS_BOARD_EDGE2, }; /**