Skip to content

Commit

Permalink
thermal: Add thermal driver for Sunplus
Browse files Browse the repository at this point in the history
Add thermal driver for Sunplus.

Signed-off-by: Li-hao Kuo <lhjeff911@gmail.com>
  • Loading branch information
Li-hao Kuo authored and intel-lab-lkp committed Jul 12, 2022
1 parent 62f46fc commit 328f3fe
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
6 changes: 6 additions & 0 deletions MAINTAINERS
Expand Up @@ -18944,6 +18944,12 @@ S: Maintained
F: Documentation/devicetree/bindings/spi/spi-sunplus-sp7021.yaml
F: drivers/spi/spi-sunplus-sp7021.c

SUNPLUS THERMAL DRIVER
M: Li-hao Kuo <lhjeff911@gmail.com>
L: linux-pm@vger.kernel.org
S: Maintained
F: drivers/thermal/sunplus_thermal.c

SUNPLUS UART DRIVER
M: Hammer Hsieh <hammerh0314@gmail.com>
S: Maintained
Expand Down
10 changes: 10 additions & 0 deletions drivers/thermal/Kconfig
Expand Up @@ -504,4 +504,14 @@ config KHADAS_MCU_FAN_THERMAL
If you say yes here you get support for the FAN controlled
by the Microcontroller found on the Khadas VIM boards.

config SUNPLUS_THERMAL
tristate "Sunplus thermal drivers"
depends on SOC_SP7021 || COMPILE_TEST
help
This enable the Sunplus SP7021 thermal driver, which supports the primitive
temperature sensor embedded in Sunplus SP7021 SoC.

If you have a Sunplus SP7021 platform say Y here and enable this option
to have support for thermal management.

endif
1 change: 1 addition & 0 deletions drivers/thermal/Makefile
Expand Up @@ -61,3 +61,4 @@ obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
obj-$(CONFIG_SUNPLUS_THERMAL) += sunplus_thermal.o
139 changes: 139 additions & 0 deletions drivers/thermal/sunplus_thermal.c
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) Sunplus Inc.
* Author: Li-hao Kuo <lhjeff911@gmail.com>
*/

#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/thermal.h>

#define ENABLE_THERMAL BIT(31)
#define SP_THERMAL_MASK GENMASK(10, 0)

#define TEMP_RATE 608
#define TEMP_BASE 3500
#define TEMP_OTP_BASE 1518

#define SP_THERMAL_CTL0_REG 0x0000
#define SP_THERMAL_STS0_REG 0x0030

/* common data structures */
struct sp_thermal_data {
struct thermal_zone_device *pcb_tz;
void __iomem *regs;
int *otp_temp0;
};

static int sunplus_get_otp_temp_coef(struct sp_thermal_data *sp_data, struct device *dev)
{
struct nvmem_cell *cell;
ssize_t otp_l;

cell = nvmem_cell_get(dev, "calib");
if (IS_ERR(cell))
return PTR_ERR(cell);

sp_data->otp_temp0 = nvmem_cell_read(cell, &otp_l);
nvmem_cell_put(cell);

if (*sp_data->otp_temp0 == 0)
*sp_data->otp_temp0 = TEMP_OTP_BASE;

return 0;
}

/*
* There is a thermal sensor instance for Sunplus Soc
* T_CODE is the ADC of the thermal sensor
* T_CODE : 11 digits in total
* When remanufacturing, the 35 degree T_CODE will be read and stored in nvcell.
* otp_temp0 is the 35 degree T_CODE obtained from nvcell
* The function will get 35 degree T_CODE for thermal calibration.
* TEMP_RATE is the Sunplus thermal temperature slope.
*/

static int sp_thermal_get_sensor_temp(void *data, int *temp)
{
struct sp_thermal_data *sp_data = data;
int t_code;

t_code = readl(sp_data->regs + SP_THERMAL_STS0_REG);
t_code = FIELD_GET(SP_THERMAL_MASK, t_code);
*temp = ((*sp_data->otp_temp0 - t_code) * 10000 / TEMP_RATE) + TEMP_BASE;
*temp *= 10;
return 0;
}

static const struct thermal_zone_of_device_ops sp_of_thermal_ops = {
.get_temp = sp_thermal_get_sensor_temp,
};

static int sunplus_thermal_probe(struct platform_device *pdev)
{
struct sp_thermal_data *sp_data;
int ret;

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

sp_data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(sp_data->regs)) {
dev_err(&pdev->dev, "resource get fail\n");
return PTR_ERR(sp_data->regs);
}

writel(ENABLE_THERMAL, sp_data->regs + SP_THERMAL_CTL0_REG);

platform_set_drvdata(pdev, sp_data);
ret = sunplus_get_otp_temp_coef(sp_data, &pdev->dev);
if (ret)
return ret;

sp_data->pcb_tz = devm_thermal_zone_of_sensor_register(&pdev->dev,
0,
sp_data, &sp_of_thermal_ops);

if (IS_ERR(sp_data->pcb_tz)) {
ret = PTR_ERR(sp_data->pcb_tz);
dev_err(dev, "Failed to register tsensor: %d\n", ret);
return ret;
}

return ret;
}

static int sunplus_thermal_remove(struct platform_device *pdev)
{
struct sp_thermal_data *sp_data = platform_get_drvdata(pdev);

thermal_zone_of_sensor_unregister(&pdev->dev, sp_data->pcb_tz);
return 0;
}

static const struct of_device_id of_sunplus_thermal_ids[] = {
{ .compatible = "sunplus,sp7021-thermal" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_sunplus_thermal_ids);

static struct platform_driver sunplus_thermal_driver = {
.probe = sunplus_thermal_probe,
.remove = sunplus_thermal_remove,
.driver = {
.name = "sunplus-thermal",
.of_match_table = of_sunplus_thermal_ids,
},
};
module_platform_driver(sunplus_thermal_driver);

MODULE_AUTHOR("Li-hao Kuo <lhjeff911@gmail.com>");
MODULE_DESCRIPTION("Thermal driver for Sunplus SoC");
MODULE_LICENSE("GPL");

0 comments on commit 328f3fe

Please sign in to comment.