1 // SPDX-License-Identifier: GPL-2.0-only
3 * SPEAr thermal driver.
5 * Copyright (C) 2011-2012 ST Microelectronics
6 * Author: Vincenzo Frascino <vincenzo.frascino@st.com>
10 #include <linux/device.h>
11 #include <linux/err.h>
13 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/thermal.h>
19 #define MD_FACTOR 1000
21 /* SPEAr Thermal Sensor Dev Structure */
22 struct spear_thermal_dev
{
23 /* pointer to base address of the thermal sensor */
24 void __iomem
*thermal_base
;
27 /* pointer to thermal flags */
31 static inline int thermal_get_temp(struct thermal_zone_device
*thermal
,
34 struct spear_thermal_dev
*stdev
= thermal_zone_device_priv(thermal
);
37 * Data are ready to be read after 628 usec from POWERDOWN signal
40 *temp
= (readl_relaxed(stdev
->thermal_base
) & 0x7F) * MD_FACTOR
;
44 static struct thermal_zone_device_ops ops
= {
45 .get_temp
= thermal_get_temp
,
48 static int __maybe_unused
spear_thermal_suspend(struct device
*dev
)
50 struct thermal_zone_device
*spear_thermal
= dev_get_drvdata(dev
);
51 struct spear_thermal_dev
*stdev
= thermal_zone_device_priv(spear_thermal
);
52 unsigned int actual_mask
= 0;
54 /* Disable SPEAr Thermal Sensor */
55 actual_mask
= readl_relaxed(stdev
->thermal_base
);
56 writel_relaxed(actual_mask
& ~stdev
->flags
, stdev
->thermal_base
);
58 clk_disable(stdev
->clk
);
59 dev_info(dev
, "Suspended.\n");
64 static int __maybe_unused
spear_thermal_resume(struct device
*dev
)
66 struct thermal_zone_device
*spear_thermal
= dev_get_drvdata(dev
);
67 struct spear_thermal_dev
*stdev
= thermal_zone_device_priv(spear_thermal
);
68 unsigned int actual_mask
= 0;
71 ret
= clk_enable(stdev
->clk
);
73 dev_err(dev
, "Can't enable clock\n");
77 /* Enable SPEAr Thermal Sensor */
78 actual_mask
= readl_relaxed(stdev
->thermal_base
);
79 writel_relaxed(actual_mask
| stdev
->flags
, stdev
->thermal_base
);
81 dev_info(dev
, "Resumed.\n");
86 static SIMPLE_DEV_PM_OPS(spear_thermal_pm_ops
, spear_thermal_suspend
,
87 spear_thermal_resume
);
89 static int spear_thermal_probe(struct platform_device
*pdev
)
91 struct thermal_zone_device
*spear_thermal
= NULL
;
92 struct spear_thermal_dev
*stdev
;
93 struct device_node
*np
= pdev
->dev
.of_node
;
96 if (!np
|| !of_property_read_u32(np
, "st,thermal-flags", &val
)) {
97 dev_err(&pdev
->dev
, "Failed: DT Pdata not passed\n");
101 stdev
= devm_kzalloc(&pdev
->dev
, sizeof(*stdev
), GFP_KERNEL
);
105 /* Enable thermal sensor */
106 stdev
->thermal_base
= devm_platform_get_and_ioremap_resource(pdev
, 0, NULL
);
107 if (IS_ERR(stdev
->thermal_base
))
108 return PTR_ERR(stdev
->thermal_base
);
110 stdev
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
111 if (IS_ERR(stdev
->clk
)) {
112 dev_err(&pdev
->dev
, "Can't get clock\n");
113 return PTR_ERR(stdev
->clk
);
116 ret
= clk_enable(stdev
->clk
);
118 dev_err(&pdev
->dev
, "Can't enable clock\n");
123 writel_relaxed(stdev
->flags
, stdev
->thermal_base
);
125 spear_thermal
= thermal_tripless_zone_device_register("spear_thermal",
127 if (IS_ERR(spear_thermal
)) {
128 dev_err(&pdev
->dev
, "thermal zone device is NULL\n");
129 ret
= PTR_ERR(spear_thermal
);
132 ret
= thermal_zone_device_enable(spear_thermal
);
134 dev_err(&pdev
->dev
, "Cannot enable thermal zone\n");
138 platform_set_drvdata(pdev
, spear_thermal
);
140 dev_info(&pdev
->dev
, "Thermal Sensor Loaded at: 0x%p.\n",
141 stdev
->thermal_base
);
146 thermal_zone_device_unregister(spear_thermal
);
148 clk_disable(stdev
->clk
);
153 static void spear_thermal_exit(struct platform_device
*pdev
)
155 unsigned int actual_mask
= 0;
156 struct thermal_zone_device
*spear_thermal
= platform_get_drvdata(pdev
);
157 struct spear_thermal_dev
*stdev
= thermal_zone_device_priv(spear_thermal
);
159 thermal_zone_device_unregister(spear_thermal
);
161 /* Disable SPEAr Thermal Sensor */
162 actual_mask
= readl_relaxed(stdev
->thermal_base
);
163 writel_relaxed(actual_mask
& ~stdev
->flags
, stdev
->thermal_base
);
165 clk_disable(stdev
->clk
);
168 static const struct of_device_id spear_thermal_id_table
[] = {
169 { .compatible
= "st,thermal-spear1340" },
172 MODULE_DEVICE_TABLE(of
, spear_thermal_id_table
);
174 static struct platform_driver spear_thermal_driver
= {
175 .probe
= spear_thermal_probe
,
176 .remove
= spear_thermal_exit
,
178 .name
= "spear_thermal",
179 .pm
= &spear_thermal_pm_ops
,
180 .of_match_table
= spear_thermal_id_table
,
184 module_platform_driver(spear_thermal_driver
);
186 MODULE_AUTHOR("Vincenzo Frascino <vincenzo.frascino@st.com>");
187 MODULE_DESCRIPTION("SPEAr thermal driver");
188 MODULE_LICENSE("GPL");