RK3399 Kernel PWM风扇调试
2022-09-03 19:43:47
ThanksView
  • 访问次数: 222
  • 注册日期: 2019-03-19
  • 最后登录: 2024-04-22

一、原理图


当前风扇控制支持 gpio 与pwm控制

二、gpio控制

1、查找gpio号

    当前控制风扇通过控制GPIO高低电平来实现,
    FAN_CTL接GPIO4_C6
    查找gpio号
    进入系统,输入命令
    cat /sys/kernel/debug/gpio
            root@linaro-alip:/# cat /sys/kernel/debug/gpio
            GPIOs 0-31, platform/pinctrl, gpio0:
             gpio-4   (                    |bt_default_wake_host) in  lo    
             gpio-5   (                    |GPIO Key Power      ) in  hi    
             gpio-9   (                    |bt_default_reset    ) out hi    
             gpio-10  (                    |reset               ) out hi    
             gpio-11  (                    |spk-con-gpio        ) out lo    
            
            GPIOs 32-63, platform/pinctrl, gpio1:
             gpio-33  (                    |vcc_lcd             ) out hi    
             gpio-35  (                    |vcc_otg_vbus        ) out lo    
             gpio-46  (                    |vsel                ) out lo    
             gpio-49  (                    |vsel                ) out lo    
             gpio-55  (                    |enable              ) out lo    
            
            GPIOs 64-95, platform/pinctrl, gpio2:
             gpio-76  (                    |rockchip,pd-gpio    ) out hi    
             gpio-83  (                    |bt_default_rts      ) out lo    
             gpio-90  (                    |bt_default_wake     ) out hi    
             gpio-92  (                    |reset               ) out hi    
            
            GPIOs 96-127, platform/pinctrl, gpio3:
             gpio-111 (                    |mdio-reset          ) out hi    
            
            GPIOs 128-159, platform/pinctrl, gpio4:
             gpio-148 (                    |sysfs               ) in  hi    
             gpio-150 (                    |sysfs               ) out lo    
             gpio-153 (                    |vcc5v0_host         ) out hi  
    GPIO4_C6对应的gpio号是150
2、GPIO口操作

    导出GPIO口
        cd /sys/class/gpio
        echo 150 >export
    查看GPIO文件夹下会多出gpio150文件夹
         ls
        export   gpio150    gpiochip128  gpiochip64  unexport
        gpio148  gpiochip0  gpiochip32   gpiochip96
    进入文件夹gpio150
        cd gpio150
    打开文件权限并设置输入模式
        chmod 777 direction
        chmod 777 value
        echo out > direction
    修改GPIO口状态
        echo 1 > value / echo 0 > value


三、pwm控制

1、dts配置

    当前风扇控制引脚接pwm1,我们需配置风扇驱动和pwn1
fan0: pwm-fan {
        compatible = "pwm-fan";
        cooling-min-state = <0>;
        cooling-max-state = <3>;
        #cooling-cells = <2>;
        pwms = <&pwm1 0 10000000 0>;
        cooling-levels = <0 100 150 255>;
};
  
2、打开风扇驱动编译

    当前风扇驱动在 kernel/drivers/hwmon/pwm-fan.c中,打开编译宏配制  
        CONFIG_PWM_ROCKCHIP=y
        CONFIG_SENSORS_PWM_FAN=y
        CONFIG_HWMON=y


3、上层控制

    通过修改占空比达到控制风扇转动
        echo 100 > /sys/devices/platform/pwm-fan/hwmon/hwmon0/pwm1
   占空比的有效操作大致在0-255左右,数据值越大,转速越快

沙发
2022-09-03 19:47:28
ThanksView
  • 访问次数: 222
  • 注册日期: 2019-03-19
  • 最后登录: 2024-04-22

驱动注册

static int pwm_fan_probe(struct platform_device *pdev)

{
struct thermal_cooling_device *cdev;
struct pwm_fan_ctx *ctx;
#ifdef HWMON
struct device *hwmon;
#endif
int duty_cycle;
int ret;

ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;

mutex_init(&ctx->lock);
ctx->dev = &pdev->dev;

ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
if (IS_ERR(ctx->pwm)) {
dev_err(&pdev->dev, "Could not get PWM\n");
return PTR_ERR(ctx->pwm);
}
    ctx->pwm->state.polarity = ctx->pwm->args.polarity;
platform_set_drvdata(pdev, ctx);

/* Set duty cycle to maximum allowed */
duty_cycle = ctx->pwm->args.period - 1;
ctx->pwm_value = MAX_PWM;

ret = pwm_config(ctx->pwm, duty_cycle, ctx->pwm->args.period);
if (ret) {
dev_err(&pdev->dev, "Failed to configure PWM\n");
return ret;
}

/* Enbale PWM output */
ret = pwm_enable(ctx->pwm);
if (ret) {
dev_err(&pdev->dev, "Failed to enable PWM\n");
return ret;
}

#ifdef HWMON
hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwm-fan",
      ctx, pwm_fan_groups);
if (IS_ERR(hwmon)) {
dev_err(&pdev->dev, "Failed to register hwmon device\n");
pwm_disable(ctx->pwm);
return PTR_ERR(hwmon);
}
#endif
ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
if (ret)
return ret;

ctx->pwm_fan_state = ctx->pwm_fan_max_state;
if (IS_ENABLED(CONFIG_THERMAL)) {
cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
 "pwm-fan", ctx,
 &pwm_fan_cooling_ops);
if (IS_ERR(cdev)) {
dev_err(&pdev->dev,
"Failed to register pwm-fan as cooling device");
pwm_disable(ctx->pwm);
return PTR_ERR(cdev);
}
ctx->cdev = cdev;
thermal_cdev_update(cdev);
}

return 0;
}


驱动操作函数的实现

static const struct thermal_cooling_device_ops pwm_fan_cooling_ops = {
.get_max_state = pwm_fan_get_max_state,
.get_cur_state = pwm_fan_get_cur_state,
.set_cur_state = pwm_fan_set_cur_state,
.get_requested_power = pwm_fan_get_requested_power,
.state2power  = pwm_fan_state2power,
    .power2state  = pwm_fan_power2state,
    .monitor_fan = pwm_fan_monitor_fan,
};


static int pwm_fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct pwm_fan_ctx *ctx = cdev->devdata;

if (!ctx)
return -EINVAL;

*state = ctx->pwm_fan_max_state;

return 0;
}

static int pwm_fan_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct pwm_fan_ctx *ctx = cdev->devdata;

if (!ctx)
return -EINVAL;

*state = ctx->pwm_fan_state;

return 0;
}

static int
pwm_fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
{
struct pwm_fan_ctx *ctx = cdev->devdata;
int ret;

if (!ctx || (state > ctx->pwm_fan_max_state))
return -EINVAL;

if (state == ctx->pwm_fan_state)
return 0;

ret = __set_pwm(ctx, ctx->pwm_fan_cooling_levels[state]);
if (ret) {
dev_err(&cdev->device, "Cannot set pwm!\n");
return ret;
}

ctx->pwm_fan_state = state;

return ret;
}

static int pwm_fan_get_requested_power(struct thermal_cooling_device *cdev,
      struct thermal_zone_device *tz,
      u32 *power)
{
    return 0;
}


风扇温控运转机制


static int pwm_fan_state2power(struct thermal_cooling_device *cdev,
                      struct thermal_zone_device *tz,
                      unsigned long state,
                      u32 *power)
{
    return 0;
}

static int pwm_fan_power2state(struct thermal_cooling_device *cdev,
                     struct thermal_zone_device *tz,
                     u32 power, unsigned long *state)
{
    if(tz->temperature > 70000 && tz->temperature <= 80000)
    {
        *state = 1;
    }
    else if(tz->temperature > 80000 && tz->temperature <= 100000)
    {
        *state = 2;
    }
    else if(tz->temperature > 100000 && tz->temperature <= 114000)
    {
        *state = 3;
    }
    return 0;
}

static int pwm_fan_monitor_fan(int temperature,unsigned long *state)
{
    if(temperature < 50000)
    {
        *state = 0;
    }
    else if(temperature > 70000 && temperature <= 75000)
    {
        *state = 1;
    }
    else if(temperature > 75000 && temperature <= 100000)
    {
        *state = 2;
    }
    else if(temperature > 100000 && temperature <= 114000)
    {
        *state = 3;
    }
    return 0;
}

添加无条件监控操作函数

//kernel/include/linux/thermal.h
struct thermal_cooling_device_ops {
int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);
int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *);
int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
int (*get_requested_power)(struct thermal_cooling_device *,
  struct thermal_zone_device *, u32 *);
int (*state2power)(struct thermal_cooling_device *,
  struct thermal_zone_device *, unsigned long, u32 *);
int (*power2state)(struct thermal_cooling_device *,
  struct thermal_zone_device *, u32, unsigned long *);
//添加部分 开始
int (*monitor_fan) (int , unsigned long *);
//添加部分 结束
};


调用新增的监控操作函数

//kernel/drivers/thermal/thermal_core.c
void thermal_cdev_update(struct thermal_cooling_device *cdev)
{
struct thermal_instance *instance;
unsigned long target = 0;
unsigned long state = 99;//add by hogo@geroge for pwm hogo fan

/* cooling device is updated*/
if (cdev->updated)
return;

mutex_lock(&cdev->lock);
/* Make sure cdev enters the deepest cooling state */
list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
dev_dbg(&cdev->device, "zone%d->target=%lu\n",
instance->tz->id, instance->target);
if (instance->target == THERMAL_NO_TARGET)
continue;
if (instance->target > target)
target = instance->target;
//添加部分 开始
if(cdev->ops-> monitor_fan)
{
            cdev->ops-> monitor_fan(instance->tz->temperature,&state);
            target = state;
        }
        //添加部分 结束
}
mutex_unlock(&cdev->lock);
cdev->ops->set_cur_state(cdev, target);
cdev->updated = true;
trace_cdev_update(cdev, target);
dev_dbg(&cdev->device, "set to state %lu\n", target);
}



DTS设备树配置

fan0: pwm-fan {
        compatible = "pwm-fan";
        cooling-min-state = <0>;
        cooling-max-state = <3>;
        #cooling-cells = <2>;
        pwms = <&pwm0 0 10000000 0>;
        cooling-levels = <0 100 150 255>;
};


文章引用:

https://blog.csdn.net/qq_23327993/article/details/122297468

ThanksView 最后编辑, 2022-09-03 19:51:32
1/1

三维半岛官网: http://www.thanksview.com

进入首页