forked from torvalds/linux
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
thermal: Add thermal driver for Sunplus
Add thermal driver for Sunplus. Signed-off-by: Li-hao Kuo <lhjeff911@gmail.com>
- Loading branch information
1 parent
62f46fc
commit 328f3fe
Showing
4 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); |