Skip to content

Commit

Permalink
mfd: backport khadas mcu driver changes from armbian rockchip-rk3588-…
Browse files Browse the repository at this point in the history
…edge kernel
  • Loading branch information
efectn authored and amazingfate committed Apr 12, 2024
1 parent a527f72 commit e06cc12
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 20 deletions.
7 changes: 6 additions & 1 deletion Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand Down
22 changes: 7 additions & 15 deletions drivers/mfd/khadas-mcu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down
77 changes: 73 additions & 4 deletions drivers/thermal/khadas_mcu_fan.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,38 @@
#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;
};

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;

Expand All @@ -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;
}
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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);
Expand Down
24 changes: 24 additions & 0 deletions include/linux/mfd/khadas-mcu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -69,13 +88,18 @@
#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,
KHADAS_BOARD_VIM2,
KHADAS_BOARD_VIM3,
KHADAS_BOARD_EDGE = 0x11,
KHADAS_BOARD_EDGE_V,
KHADAS_BOARD_EDGE2,
};

/**
Expand Down

0 comments on commit e06cc12

Please sign in to comment.