From 46a9aab7e90e899598f8c0c945f4ff020d9a001c Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Wed, 6 Mar 2024 00:09:25 +0300
Subject: [PATCH 1/6] mfd: khadas-mcu: add Edge2 registers

---
 drivers/mfd/khadas-mcu.c       |  8 ++++++--
 include/linux/mfd/khadas-mcu.h | 24 ++++++++++++++++++++++++
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c
index 61396d824f16..a1a63fb70aac 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,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_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", },
 };
 
diff --git a/include/linux/mfd/khadas-mcu.h b/include/linux/mfd/khadas-mcu.h
index a99ba2ed0e4e..63bc9bf76661 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,
 };
 
 /**
-- 
2.44.0


From c4e9f9c5fa33dea97005898d4f10ddd51814ae00 Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Wed, 6 Mar 2024 00:09:58 +0300
Subject: [PATCH 2/6] mfd: khadas-mcu: drop unused code

---
 drivers/mfd/khadas-mcu.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c
index a1a63fb70aac..805fb9eb4a2f 100644
--- a/drivers/mfd/khadas-mcu.c
+++ b/drivers/mfd/khadas-mcu.c
@@ -84,10 +84,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;
@@ -109,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_property_present(dev->of_node, "#cooling-cells"))
 		return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
 					    khadas_mcu_fan_cells,
-- 
2.44.0


From 8bbc226b1d4688b6a0489b1f925aa601e3df960c Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Wed, 6 Mar 2024 00:13:10 +0300
Subject: [PATCH 3/6] thermal: khadas_mcu_fan: add support for Khadas Edge 2

---
 drivers/thermal/khadas_mcu_fan.c | 77 ++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 4 deletions(-)

diff --git a/drivers/thermal/khadas_mcu_fan.c b/drivers/thermal/khadas_mcu_fan.c
index d35e5313bea4..e495e562c346 100644
--- a/drivers/thermal/khadas_mcu_fan.c
+++ b/drivers/thermal/khadas_mcu_fan.c
@@ -15,10 +15,16 @@
 #include <linux/thermal.h>
 
 #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_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, "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);
-- 
2.44.0


From b58c8f4916e4c8bdf106cf0b19326b51693173bf Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Wed, 6 Mar 2024 00:14:58 +0300
Subject: [PATCH 4/6] dt-bindings: mfd: khadas-mcu: add cooling-levels property

---
 Documentation/devicetree/bindings/mfd/khadas,mcu.yaml | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
index 084960fd5a1f..cf46b690010f 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
 
-- 
2.44.0


From f9944e2dc8d5ee03a8ac2769d90ee669e09490b3 Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Wed, 6 Mar 2024 00:17:58 +0300
Subject: [PATCH 5/6] arm64: dts: rockchip: Add MCU to Khadas Edge 2

---
 arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
index cf29563736ea..a292d1fd7eca 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
@@ -307,6 +307,13 @@ 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>;
+	};
 };
 
 &pinctrl {
-- 
2.44.0


From b48aaebb9b7f6c476671c87465475cdbe7b5833c Mon Sep 17 00:00:00 2001
From: Muhammed Efe Cetin <efectn@protonmail.com>
Date: Mon, 25 Mar 2024 22:41:26 +0300
Subject: [PATCH 6/6] arm64: dts: rockchip: Add automatic fan control to Khadas
 Edge 2

---
 .../dts/rockchip/rk3588s-khadas-edge2.dts     | 56 +++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
index a292d1fd7eca..803907ba4037 100644
--- a/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3588s-khadas-edge2.dts
@@ -316,6 +316,62 @@ khadas_mcu: system-controller@18 {
 	};
 };
 
+&package_thermal {
+	polling-delay = <1000>;
+
+	trips {
+		package_fan0: package-fan0 {
+			temperature = <45000>;
+			hysteresis = <5000>;
+			type = "active";
+		};
+
+		package_fan1: package-fan1 {
+			temperature = <55000>;
+			hysteresis = <5000>;
+			type = "active";
+		};
+
+		package_fan2: package-fan2 {
+			temperature = <60000>;
+			hysteresis = <5000>;
+			type = "active";
+		};
+
+		package_fan3: package-fan3 {
+			temperature = <70000>;
+			hysteresis = <5000>;
+			type = "active";
+		};
+	};
+
+	cooling-maps {
+		map0 {
+			trip = <&package_fan0>;
+			cooling-device = <&khadas_mcu 0 1>;
+			contribution = <1024>;
+		};
+
+		map1 {
+			trip = <&package_fan1>;
+			cooling-device = <&khadas_mcu 1 2>;
+			contribution = <1024>;
+		};
+
+		map2 {
+			trip = <&package_fan2>;
+			cooling-device = <&khadas_mcu 2 3>;
+			contribution = <1024>;
+		};
+
+		map3 {
+			trip = <&package_fan3>;
+			cooling-device = <&khadas_mcu 3 THERMAL_NO_LIMIT>;
+			contribution = <1024>;
+		};
+	};
+};
+
 &pinctrl {
 	vdd_sd {
 		vdd_sd_en: vdd-sd-en {
-- 
2.44.0

