1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2018-2020 NXP.
6 #include <dt-bindings/firmware/imx/rsrc.h>
8 #include <linux/firmware/imx/sci.h>
9 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
13 #include <linux/thermal.h>
15 #include "thermal_hwmon.h"
17 #define IMX_SC_MISC_FUNC_GET_TEMP 13
19 static struct imx_sc_ipc
*thermal_ipc_handle
;
21 struct imx_sc_sensor
{
22 struct thermal_zone_device
*tzd
;
29 } __packed
__aligned(4);
31 struct resp_get_temp
{
34 } __packed
__aligned(4);
36 struct imx_sc_msg_misc_get_temp
{
37 struct imx_sc_rpc_msg hdr
;
39 struct req_get_temp req
;
40 struct resp_get_temp resp
;
42 } __packed
__aligned(4);
44 static int imx_sc_thermal_get_temp(struct thermal_zone_device
*tz
, int *temp
)
46 struct imx_sc_msg_misc_get_temp msg
;
47 struct imx_sc_rpc_msg
*hdr
= &msg
.hdr
;
48 struct imx_sc_sensor
*sensor
= thermal_zone_device_priv(tz
);
51 msg
.data
.req
.resource_id
= sensor
->resource_id
;
52 msg
.data
.req
.type
= IMX_SC_C_TEMP
;
54 hdr
->ver
= IMX_SC_RPC_VERSION
;
55 hdr
->svc
= IMX_SC_RPC_SVC_MISC
;
56 hdr
->func
= IMX_SC_MISC_FUNC_GET_TEMP
;
59 ret
= imx_scu_call_rpc(thermal_ipc_handle
, &msg
, true);
63 *temp
= msg
.data
.resp
.celsius
* 1000 + msg
.data
.resp
.tenths
* 100;
68 static const struct thermal_zone_device_ops imx_sc_thermal_ops
= {
69 .get_temp
= imx_sc_thermal_get_temp
,
72 static int imx_sc_thermal_probe(struct platform_device
*pdev
)
74 struct imx_sc_sensor
*sensor
;
75 const int *resource_id
;
78 ret
= imx_scu_get_handle(&thermal_ipc_handle
);
82 resource_id
= of_device_get_match_data(&pdev
->dev
);
86 for (i
= 0; resource_id
[i
] >= 0; i
++) {
88 sensor
= devm_kzalloc(&pdev
->dev
, sizeof(*sensor
), GFP_KERNEL
);
92 sensor
->resource_id
= resource_id
[i
];
94 sensor
->tzd
= devm_thermal_of_zone_register(&pdev
->dev
, sensor
->resource_id
,
95 sensor
, &imx_sc_thermal_ops
);
96 if (IS_ERR(sensor
->tzd
)) {
98 * Save the error value before freeing the
99 * sensor pointer, otherwise we endup with a
100 * use-after-free error
102 ret
= PTR_ERR(sensor
->tzd
);
104 devm_kfree(&pdev
->dev
, sensor
);
107 * The thermal framework notifies us there is
108 * no thermal zone description for such a
114 return dev_err_probe(&pdev
->dev
, ret
, "failed to register thermal zone\n");
117 devm_thermal_add_hwmon_sysfs(&pdev
->dev
, sensor
->tzd
);
123 static const int imx_sc_sensors
[] = {
124 IMX_SC_R_SYSTEM
, IMX_SC_R_PMIC_0
,
125 IMX_SC_R_AP_0
, IMX_SC_R_AP_1
,
126 IMX_SC_R_GPU_0_PID0
, IMX_SC_R_GPU_1_PID0
,
127 IMX_SC_R_DRC_0
, -1 };
129 static const struct of_device_id imx_sc_thermal_table
[] = {
130 { .compatible
= "fsl,imx-sc-thermal", .data
= imx_sc_sensors
},
133 MODULE_DEVICE_TABLE(of
, imx_sc_thermal_table
);
135 static struct platform_driver imx_sc_thermal_driver
= {
136 .probe
= imx_sc_thermal_probe
,
138 .name
= "imx-sc-thermal",
139 .of_match_table
= imx_sc_thermal_table
,
142 module_platform_driver(imx_sc_thermal_driver
);
144 MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
145 MODULE_DESCRIPTION("Thermal driver for NXP i.MX SoCs with system controller");
146 MODULE_LICENSE("GPL v2");