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
->devdata
;
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
= spear_thermal
->devdata
;
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
= spear_thermal
->devdata
;
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
;
97 if (!np
|| !of_property_read_u32(np
, "st,thermal-flags", &val
)) {
98 dev_err(&pdev
->dev
, "Failed: DT Pdata not passed\n");
102 stdev
= devm_kzalloc(&pdev
->dev
, sizeof(*stdev
), GFP_KERNEL
);
106 /* Enable thermal sensor */
107 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
108 stdev
->thermal_base
= devm_ioremap_resource(&pdev
->dev
, res
);
109 if (IS_ERR(stdev
->thermal_base
))
110 return PTR_ERR(stdev
->thermal_base
);
112 stdev
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
113 if (IS_ERR(stdev
->clk
)) {
114 dev_err(&pdev
->dev
, "Can't get clock\n");
115 return PTR_ERR(stdev
->clk
);
118 ret
= clk_enable(stdev
->clk
);
120 dev_err(&pdev
->dev
, "Can't enable clock\n");
125 writel_relaxed(stdev
->flags
, stdev
->thermal_base
);
127 spear_thermal
= thermal_zone_device_register("spear_thermal", 0, 0,
128 stdev
, &ops
, NULL
, 0, 0);
129 if (IS_ERR(spear_thermal
)) {
130 dev_err(&pdev
->dev
, "thermal zone device is NULL\n");
131 ret
= PTR_ERR(spear_thermal
);
135 platform_set_drvdata(pdev
, spear_thermal
);
137 dev_info(&spear_thermal
->device
, "Thermal Sensor Loaded at: 0x%p.\n",
138 stdev
->thermal_base
);
143 clk_disable(stdev
->clk
);
148 static int spear_thermal_exit(struct platform_device
*pdev
)
150 unsigned int actual_mask
= 0;
151 struct thermal_zone_device
*spear_thermal
= platform_get_drvdata(pdev
);
152 struct spear_thermal_dev
*stdev
= spear_thermal
->devdata
;
154 thermal_zone_device_unregister(spear_thermal
);
156 /* Disable SPEAr Thermal Sensor */
157 actual_mask
= readl_relaxed(stdev
->thermal_base
);
158 writel_relaxed(actual_mask
& ~stdev
->flags
, stdev
->thermal_base
);
160 clk_disable(stdev
->clk
);
165 static const struct of_device_id spear_thermal_id_table
[] = {
166 { .compatible
= "st,thermal-spear1340" },
169 MODULE_DEVICE_TABLE(of
, spear_thermal_id_table
);
171 static struct platform_driver spear_thermal_driver
= {
172 .probe
= spear_thermal_probe
,
173 .remove
= spear_thermal_exit
,
175 .name
= "spear_thermal",
176 .pm
= &spear_thermal_pm_ops
,
177 .of_match_table
= spear_thermal_id_table
,
181 module_platform_driver(spear_thermal_driver
);
183 MODULE_AUTHOR("Vincenzo Frascino <vincenzo.frascino@st.com>");
184 MODULE_DESCRIPTION("SPEAr thermal driver");
185 MODULE_LICENSE("GPL");