Add Khadas MCU and fan control support for Khadas Edge 2
Subsystems (5)
cover Add Khadas MCU and fan control support for Khadas Edge 2
From: Muhammed Efe Cetin <[email protected]>
This patch series adds support for the Khadas MCU and fan control for Khadas Edge 2 board.
The first patch updates devicetree bindings for new cooling-levels property.
The second mfd patch removes unused nvmem code.
The third patch adds the Khadas Edge 2 registers to the mfd driver.
The fourth patch adds support for Khadas Edge 2's new fan control registers to MCU thermal driver and the last one adds the Khadas Edge 2 device tree node for the MCU and fan control. And the final patch adds the Khadas Edge 2 device tree node for the MCU and fan control.
Muhammed Efe Cetin (5):
dt-bindings: mfd: khadas-mcu: add cooling-levels property
mfd: khadas-mcu: drop unused nvmem code
mfd: khadas-mcu: add Khadas Edge 2 registers
thermal: khadas_mcu_fan: add support for Khadas Edge 2
arm64: dts: rockchip: add Khadas MCU and fan control nodes
.../devicetree/bindings/mfd/khadas,mcu.yaml | 9 ++- .../dts/rockchip/rk3588s-khadas-edge2.dts | 59 ++++++++++++++ drivers/mfd/khadas-mcu.c | 19 ++--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++- include/linux/mfd/khadas-mcu.h | 25 ++++++ 5 files changed, 170 insertions(+), 18 deletions(-)
Signature · 1 line
2.49.0
PATCH 1/5 dt-bindings: mfd: khadas-mcu: add cooling-levels property
From: Muhammed Efe Cetin <[email protected]>
Add fan controlling step property which is used by Khadas Edge 2.
--- Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml +8 -1
@@ -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,13 @@ properties: "#cooling-cells": # Only needed for boards having FAN control feature const: 2 + cooling-levels: + description: + Max speed of PWM fan, from 0 to 100. This property is necessary for Khadas Edge 2. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + maximum: 100 + reg: maxItems: 1
Signature · 1 line
2.49.0
[email protected]
maintainerRe: [PATCH 1/5] dt-bindings: mfd: khadas-mcu: add cooling-levels property
Quoted 23 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Add fan controlling step property which is used by Khadas Edge 2.
Signed-off-by Muhammed Efe Cetin <[email protected]>--- Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)Documentation/devicetree/bindings/mfd/khadas,mcu.yaml +1
-1@@ -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:
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml properties: · line 30
Quoted 9 lines
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml +6
-0@@ -22,6 +22,13 @@ properties: "#cooling-cells": # Only needed for boards having FAN control feature const: 2 + cooling-levels: + description: + Max speed of PWM fan, from 0 to 100. This property is necessary for Khadas Edge 2. + $ref: /schemas/types.yaml#/definitions/uint32-array + items: + maximum: 100
The cooling level can be detected dynamically by reading the MCU register, so just set the max_level to 100 when edge2 is detected, and drop this property.
Neil
Quoted 4 lines
Documentation/devicetree/bindings/mfd/khadas,mcu.yaml +1
-0+ reg: maxItems: 1
PATCH 2/5 mfd: khadas-mcu: drop unused nvmem code
In reply to [email protected]From: Muhammed Efe Cetin <[email protected]>
Drop "khadas-mcu-user-mem" code since it is not used anywhere.
--- drivers/mfd/khadas-mcu.c | 11 ----------- 1 file changed, 11 deletions(-)
drivers/mfd/khadas-mcu.c +0 -11
@@ -80,10 +80,6 @@ static struct mfd_cell khadas_mcu_fan_cells[] = { { .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) {struct device *dev = &client->dev;
@@ -105,13 +101,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_property_present (dev->of_node,"#cooling-cells" )) return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, khadas_mcu_fan_cells,
Signature · 1 line
2.49.0
Re: [PATCH 2/5] mfd: khadas-mcu: drop unused nvmem code
Quoted 28 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Drop "khadas-mcu-user-mem" code since it is not used anywhere.
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/mfd/khadas-mcu.c | 11 ----------- 1 file changed, 11 deletions(-)drivers/mfd/khadas-mcu.c +0
-4@@ -80,10 +80,6 @@ static struct mfd_cell khadas_mcu_fan_cells[] = { { .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) {struct device *dev = &client->dev;@@ -105,13 +101,6 @@ static int khadas_mcu_probe(struct i2c_client *client)return ret; }
drivers/mfd/khadas-mcu.c static int khadas_mcu_probe(struct i2c_client *client) · line 106
Quoted 10 lines
drivers/mfd/khadas-mcu.c +0
-7- 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_property_present (dev->of_node,"#cooling-cells" )) return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, khadas_mcu_fan_cells,
PATCH 3/5 mfd: khadas-mcu: add Khadas Edge 2 registers
In reply to [email protected]From: Muhammed Efe Cetin <[email protected]>
Add Khadas Edge 2 MCU registers to khadas-mcu.h and adjust some properties. Also, i've added some registers with V2 suffix,
as same addresses were already exist for previous boards.
--- drivers/mfd/khadas-mcu.c | 8 ++++++-- include/linux/mfd/khadas-mcu.h | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-)
drivers/mfd/khadas-mcu.c +6 -2
@@ -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,14 +73,14 @@ 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_MAPLE, };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" , }, };
include/linux/mfd/khadas-mcu.h +25 -0
@@ -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_REST_CONF_REG 0x2c/* WO */ #define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c/* RW */ #define KHADAS_MCU_MAC_SWITCH_REG 0x2d/* 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,11 @@#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 +100,7 @@ enum {KHADAS_BOARD_VIM3 ,KHADAS_BOARD_EDGE =0x11 ,KHADAS_BOARD_EDGE_V , + KHADAS_BOARD_EDGE2, };/**
Signature · 1 line
2.49.0
Re: [PATCH 3/5] mfd: khadas-mcu: add Khadas Edge 2 registers
Quoted 107 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Add Khadas Edge 2 MCU registers to
khadas-mcu.hand adjust some properties. Also, i've added some registers with V2 suffix,
as same addresses were already exist for previous boards.Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/mfd/khadas-mcu.c | 8 ++++++-- include/linux/mfd/khadas-mcu.h | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-)drivers/mfd/khadas-mcu.c +6
-2@@ -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,14 +73,14 @@ 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_MAPLE, };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" , }, };include/linux/mfd/khadas-mcu.h +24
-0@@ -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_REST_CONF_REG 0x2c/* WO */ #define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c/* RW */ #define KHADAS_MCU_MAC_SWITCH_REG 0x2d/* 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,11 @@#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 ,
include/linux/mfd/khadas-mcu.h enum { · line 106
Quoted 7 lines
include/linux/mfd/khadas-mcu.h +1
-0@@ -76,6 +100,7 @@ enum {KHADAS_BOARD_VIM3 ,KHADAS_BOARD_EDGE =0x11 ,KHADAS_BOARD_EDGE_V , + KHADAS_BOARD_EDGE2, };/**
PATCH 4/5 thermal: khadas_mcu_fan: add support for Khadas Edge 2
In reply to [email protected]From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the 0x8A register,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.
--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)
drivers/thermal/khadas_mcu_fan.c +72 -4
@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
Signature · 1 line
2.49.0
[email protected]
maintainerRe: [PATCH 4/5] thermal: khadas_mcu_fan: add support for Khadas Edge 2
Quoted 7 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the
0x8Aregister,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.
Thanks for the explanation, but would would you like to change that ? The MCU can accept any value between 0 and 99, so why change the levels from DT ?
Neil
Quoted 133 lines
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)drivers/thermal/khadas_mcu_fan.c +72
-4@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
Re: [PATCH 4/5] thermal: khadas_mcu_fan: add support for Khadas Edge 2
Quoted 9 lines · On 6/26/25 17:11, [email protected] wrote:
Quoted 7 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the
0x8Aregister,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.
Quoted 4 lines
Thanks for the explanation, but would would you like to change that ? The MCU can accept any value between 0 and 99, so why change the levels from DT ?
Neil
Thanks for the review. Therefore, you say just add values between 0-100 to cooling-device instead of remapping them using cooling-levels property?
What would be the best practise of detecting whether the board is Khadas Edge 2? Adding new bool property, reading model propety from devicetree etc.
Best regards.
Quoted 125 lines
Quoted 124 lines
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)drivers/thermal/khadas_mcu_fan.c +6
-0@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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;drivers/thermal/khadas_mcu_fan.c +64
-2+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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
[email protected]
maintainerRe: [PATCH 4/5] thermal: khadas_mcu_fan: add support for Khadas Edge 2
Quoted 10 lines · On 26/06/2025 16:36, [email protected] wrote:
Quoted 9 lines · On 6/26/25 17:11, [email protected] wrote:
Quoted 7 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the
0x8Aregister,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.
Quoted 8 lines
Quoted 4 lines
Thanks for the explanation, but would would you like to change that ? The MCU can accept any value between 0 and 99, so why change the levels from DT ?
Neil
Thanks for the review. Therefore, you say just add values between 0-100 to cooling-device instead of remapping them using cooling-levels property?
What would be the best practise of detecting whether the board is Khadas Edge 2? Adding new bool property, reading model propety from devicetree etc.
The register DEVICE_NO should be set at 0x12 for Edge V, 0x11 for Edge 1. I don't have the number for Edge 2, perhaps you can read it ?
Neil
Quoted 129 lines
Best regards.
Quoted 125 lines
Quoted 124 lines
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)drivers/thermal/khadas_mcu_fan.c +6
-0@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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;drivers/thermal/khadas_mcu_fan.c +64
-2+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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
Re: [PATCH 4/5] thermal: khadas_mcu_fan: add support for Khadas Edge 2
Quoted 16 lines · On 6/26/25 17:46, [email protected] wrote:
Quoted 15 lines · On 26/06/2025 16:36, [email protected] wrote:
Quoted 13 lines · On 6/26/25 17:11, [email protected] wrote:
Quoted 7 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the
0x8Aregister,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.Thanks for the explanation, but would would you like to change that ? The MCU can accept any value between 0 and 99, so why change the levels from DT ?
Neil
Quoted 7 lines
Quoted 3 lines
Thanks for the review. Therefore, you say just add values between 0-100 to cooling-device instead of remapping them using cooling-levels property?
What would be the best practise of detecting whether the board is Khadas Edge 2? Adding new bool property, reading model propety from devicetree etc.
The register
DEVICE_NOshould be set at0x12for Edge V,0x11for Edge 1. I don't have the number for Edge 2, perhaps you can read it ?Neil
The DEVICE_NO register is not available for Khadas Edge 2. Here are the registers [0].
[0] https://dl.khadas.com/products/edge2/tools/mcu/edge2-mcu-register-description-en-v1.0-230520.pdf
Quoted 131 lines
Quoted 130 lines
Best regards.
Quoted 125 lines
Quoted 124 lines
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)drivers/thermal/khadas_mcu_fan.c +6
-0@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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;drivers/thermal/khadas_mcu_fan.c +64
-2+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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
[email protected]
maintainerRe: [PATCH 4/5] thermal: khadas_mcu_fan: add support for Khadas Edge 2
Quoted 21 lines · Muhammed Efe Cetin
Quoted 20 lines · On 6/26/25 17:46, [email protected] wrote:
Quoted 18 lines · On 26/06/2025 16:36, [email protected] wrote:
Quoted 9 lines · On 6/26/25 17:11, [email protected] wrote:
Quoted 7 lines · On 26/06/2025 16:04, [email protected] wrote:
From: Muhammed Efe Cetin <[email protected]>
Fan control on the Khadas Edge 2 is controlled with the
0x8Aregister,
using percentage values from 0 to 100, whereas there are only 3 constant steps in previous Khadas boards. Therefore, i added a new cooling-levels property, similar to the one used in the pwm-fan driver. The original behavior can still be used when the cooling-levels property is not specified, ensuring that the new functionality does not break old boards.Quoted 4 lines
Thanks for the explanation, but would would you like to change that ? The MCU can accept any value between 0 and 99, so why change the levels from DT ?
Neil
Thanks for the review. Therefore, you say just add values between 0-100 to cooling-device instead of remapping them using cooling-levels property?
What would be the best practise of detecting whether the board is Khadas Edge 2? Adding new bool property, reading model propety from devicetree etc.
Quoted 7 lines
Quoted 3 lines
The register
DEVICE_NOshould be set at0x12for Edge V,0x11for Edge 1. I don't have the number for Edge 2, perhaps you can read it ?Neil
The
DEVICE_NOregister is not available for Khadas Edge 2. Here are the registers [0].[0] https://dl.khadas.com/products/edge2/tools/mcu/edge2-mcu-register-description-en-v1.0-230520.pdf
OK so it's basically completely different.
In this case introduce a separate compatible since we can't detect it dynamically, and just add the registers with EDGE2 prefix.
But keep the khadas-mcu-fan-ctrl, it will work if you pass the device type detected via the new compatible.
Neil
Quoted 133 lines
Quoted 132 lines
Quoted 131 lines
Best regards.
Quoted 125 lines
Quoted 124 lines
Signed-off-by Muhammed Efe Cetin <[email protected]>--- drivers/thermal/khadas_mcu_fan.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-)drivers/thermal/khadas_mcu_fan.c +6
-0@@ -15,10 +15,16 @@#include <linux/thermal.h> #define MAX_LEVEL 3 +#define MAX_SPEED 0x64struct 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;drivers/thermal/khadas_mcu_fan.c +64
-2+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,47 @@ static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = { .set_cur_state = khadas_mcu_fan_set_cur_state, }; +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_property_present (np,"cooling-levels" )) +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,"MCU 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 +151,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);
PATCH 5/5 arm64: dts: rockchip: add Khadas MCU and fan control nodes
In reply to [email protected]From: Muhammed Efe Cetin <[email protected]>
Add Khadas MCU fan control to Khadas Edge 2 with 4 fan control levels.
--- .../dts/rockchip/rk3588s-khadas-edge2.dts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+)
arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts +59 -0
@@ -271,12 +271,71 @@ hym8563: rtc@51 { clock-output-names = "hym8563"; wakeup-source; }; + + khadas_mcu: system-controller@18 { + compatible = "khadas,mcu"; + reg = <0x18>; + cooling-levels = <0 50 72 100>; + #cooling-cells = <2>; + }; }; &i2s5_8ch { status = "okay"; }; +&package_thermal { + polling-delay = <2000>; + + trips { + package_fan0: package-fan0 { + temperature = <50000>; + hysteresis = <5000>; + type = "active"; + }; + + package_fan1: package-fan1 { + temperature = <60000>; + hysteresis = <5000>; + type = "active"; + }; + + package_fan2: package-fan2 { + temperature = <65000>; + hysteresis = <5000>; + type = "active"; + }; + + package_fan3: package-fan3 { + temperature = <75000>; + hysteresis = <5000>; + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&package_fan0>; + cooling-device = <&khadas_mcu THERMAL_NO_LIMIT 1>; + }; + + map1 { + trip = <&package_fan1>; + cooling-device = <&khadas_mcu 1 2>; + }; + + map2 { + trip = <&package_fan2>; + cooling-device = <&khadas_mcu 2 3>; + }; + + map3 { + trip = <&package_fan3>; + cooling-device = <&khadas_mcu 3 THERMAL_NO_LIMIT>; + }; + }; +}; + &pd_gpu { domain-supply = <&vdd_gpu_s0>; };
Signature · 1 line
2.49.0