Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Khadas MCU Controlled FAN driver
0004  *
0005  * Copyright (C) 2020 BayLibre SAS
0006  * Author(s): Neil Armstrong <narmstrong@baylibre.com>
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/mfd/khadas-mcu.h>
0013 #include <linux/regmap.h>
0014 #include <linux/sysfs.h>
0015 #include <linux/thermal.h>
0016 
0017 #define MAX_LEVEL 3
0018 
0019 struct khadas_mcu_fan_ctx {
0020     struct khadas_mcu *mcu;
0021     unsigned int level;
0022     struct thermal_cooling_device *cdev;
0023 };
0024 
0025 static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
0026                     unsigned int level)
0027 {
0028     int ret;
0029 
0030     ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
0031                level);
0032     if (ret)
0033         return ret;
0034 
0035     ctx->level = level;
0036 
0037     return 0;
0038 }
0039 
0040 static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
0041                     unsigned long *state)
0042 {
0043     *state = MAX_LEVEL;
0044 
0045     return 0;
0046 }
0047 
0048 static int khadas_mcu_fan_get_cur_state(struct thermal_cooling_device *cdev,
0049                     unsigned long *state)
0050 {
0051     struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
0052 
0053     *state = ctx->level;
0054 
0055     return 0;
0056 }
0057 
0058 static int
0059 khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
0060                  unsigned long state)
0061 {
0062     struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
0063 
0064     if (state > MAX_LEVEL)
0065         return -EINVAL;
0066 
0067     if (state == ctx->level)
0068         return 0;
0069 
0070     return khadas_mcu_fan_set_level(ctx, state);
0071 }
0072 
0073 static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = {
0074     .get_max_state = khadas_mcu_fan_get_max_state,
0075     .get_cur_state = khadas_mcu_fan_get_cur_state,
0076     .set_cur_state = khadas_mcu_fan_set_cur_state,
0077 };
0078 
0079 static int khadas_mcu_fan_probe(struct platform_device *pdev)
0080 {
0081     struct khadas_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
0082     struct thermal_cooling_device *cdev;
0083     struct device *dev = &pdev->dev;
0084     struct khadas_mcu_fan_ctx *ctx;
0085     int ret;
0086 
0087     ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
0088     if (!ctx)
0089         return -ENOMEM;
0090     ctx->mcu = mcu;
0091     platform_set_drvdata(pdev, ctx);
0092 
0093     cdev = devm_thermal_of_cooling_device_register(dev->parent,
0094             dev->parent->of_node, "khadas-mcu-fan", ctx,
0095             &khadas_mcu_fan_cooling_ops);
0096     if (IS_ERR(cdev)) {
0097         ret = PTR_ERR(cdev);
0098         dev_err(dev, "Failed to register khadas-mcu-fan as cooling device: %d\n",
0099             ret);
0100         return ret;
0101     }
0102     ctx->cdev = cdev;
0103 
0104     return 0;
0105 }
0106 
0107 static void khadas_mcu_fan_shutdown(struct platform_device *pdev)
0108 {
0109     struct khadas_mcu_fan_ctx *ctx = platform_get_drvdata(pdev);
0110 
0111     khadas_mcu_fan_set_level(ctx, 0);
0112 }
0113 
0114 #ifdef CONFIG_PM_SLEEP
0115 static int khadas_mcu_fan_suspend(struct device *dev)
0116 {
0117     struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
0118     unsigned int level_save = ctx->level;
0119     int ret;
0120 
0121     ret = khadas_mcu_fan_set_level(ctx, 0);
0122     if (ret)
0123         return ret;
0124 
0125     ctx->level = level_save;
0126 
0127     return 0;
0128 }
0129 
0130 static int khadas_mcu_fan_resume(struct device *dev)
0131 {
0132     struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
0133 
0134     return khadas_mcu_fan_set_level(ctx, ctx->level);
0135 }
0136 #endif
0137 
0138 static SIMPLE_DEV_PM_OPS(khadas_mcu_fan_pm, khadas_mcu_fan_suspend,
0139              khadas_mcu_fan_resume);
0140 
0141 static const struct platform_device_id khadas_mcu_fan_id_table[] = {
0142     { .name = "khadas-mcu-fan-ctrl", },
0143     {},
0144 };
0145 MODULE_DEVICE_TABLE(platform, khadas_mcu_fan_id_table);
0146 
0147 static struct platform_driver khadas_mcu_fan_driver = {
0148     .probe      = khadas_mcu_fan_probe,
0149     .shutdown   = khadas_mcu_fan_shutdown,
0150     .driver = {
0151         .name       = "khadas-mcu-fan-ctrl",
0152         .pm     = &khadas_mcu_fan_pm,
0153     },
0154     .id_table   = khadas_mcu_fan_id_table,
0155 };
0156 
0157 module_platform_driver(khadas_mcu_fan_driver);
0158 
0159 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
0160 MODULE_DESCRIPTION("Khadas MCU FAN driver");
0161 MODULE_LICENSE("GPL");