1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
6 #include <linux/debugfs.h>
8 #include <linux/module.h>
10 #include <linux/of_platform.h>
11 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/thermal.h>
17 static int tsens_get_temp(void *data
, int *temp
)
19 struct tsens_sensor
*s
= data
;
20 struct tsens_priv
*priv
= s
->priv
;
22 return priv
->ops
->get_temp(s
, temp
);
25 static int tsens_get_trend(void *data
, int trip
, enum thermal_trend
*trend
)
27 struct tsens_sensor
*s
= data
;
28 struct tsens_priv
*priv
= s
->priv
;
30 if (priv
->ops
->get_trend
)
31 return priv
->ops
->get_trend(s
, trend
);
36 static int __maybe_unused
tsens_suspend(struct device
*dev
)
38 struct tsens_priv
*priv
= dev_get_drvdata(dev
);
40 if (priv
->ops
&& priv
->ops
->suspend
)
41 return priv
->ops
->suspend(priv
);
46 static int __maybe_unused
tsens_resume(struct device
*dev
)
48 struct tsens_priv
*priv
= dev_get_drvdata(dev
);
50 if (priv
->ops
&& priv
->ops
->resume
)
51 return priv
->ops
->resume(priv
);
56 static SIMPLE_DEV_PM_OPS(tsens_pm_ops
, tsens_suspend
, tsens_resume
);
58 static const struct of_device_id tsens_table
[] = {
60 .compatible
= "qcom,msm8916-tsens",
63 .compatible
= "qcom,msm8974-tsens",
66 .compatible
= "qcom,msm8976-tsens",
69 .compatible
= "qcom,msm8996-tsens",
72 .compatible
= "qcom,tsens-v1",
73 .data
= &data_tsens_v1
,
75 .compatible
= "qcom,tsens-v2",
76 .data
= &data_tsens_v2
,
80 MODULE_DEVICE_TABLE(of
, tsens_table
);
82 static const struct thermal_zone_of_device_ops tsens_of_ops
= {
83 .get_temp
= tsens_get_temp
,
84 .get_trend
= tsens_get_trend
,
85 .set_trips
= tsens_set_trips
,
88 static int tsens_register(struct tsens_priv
*priv
)
91 struct thermal_zone_device
*tzd
;
92 struct platform_device
*pdev
;
94 for (i
= 0; i
< priv
->num_sensors
; i
++) {
95 priv
->sensor
[i
].priv
= priv
;
96 tzd
= devm_thermal_zone_of_sensor_register(priv
->dev
, priv
->sensor
[i
].hw_id
,
101 priv
->sensor
[i
].tzd
= tzd
;
102 if (priv
->ops
->enable
)
103 priv
->ops
->enable(priv
, i
);
106 pdev
= of_find_device_by_node(priv
->dev
->of_node
);
110 irq
= platform_get_irq_byname(pdev
, "uplow");
113 /* For old DTs with no IRQ defined */
119 ret
= devm_request_threaded_irq(&pdev
->dev
, irq
,
120 NULL
, tsens_irq_thread
,
121 IRQF_TRIGGER_HIGH
| IRQF_ONESHOT
,
122 dev_name(&pdev
->dev
), priv
);
124 dev_err(&pdev
->dev
, "%s: failed to get irq\n", __func__
);
128 enable_irq_wake(irq
);
131 put_device(&pdev
->dev
);
135 static int tsens_probe(struct platform_device
*pdev
)
139 struct device_node
*np
;
140 struct tsens_priv
*priv
;
141 const struct tsens_plat_data
*data
;
142 const struct of_device_id
*id
;
145 if (pdev
->dev
.of_node
)
148 dev
= pdev
->dev
.parent
;
152 id
= of_match_node(tsens_table
, np
);
158 num_sensors
= data
->num_sensors
;
161 of_property_read_u32(np
, "#qcom,sensors", &num_sensors
);
163 if (num_sensors
<= 0) {
164 dev_err(dev
, "%s: invalid number of sensors\n", __func__
);
168 priv
= devm_kzalloc(dev
,
169 struct_size(priv
, sensor
, num_sensors
),
175 priv
->num_sensors
= num_sensors
;
176 priv
->ops
= data
->ops
;
177 for (i
= 0; i
< priv
->num_sensors
; i
++) {
179 priv
->sensor
[i
].hw_id
= data
->hw_ids
[i
];
181 priv
->sensor
[i
].hw_id
= i
;
183 priv
->feat
= data
->feat
;
184 priv
->fields
= data
->fields
;
186 platform_set_drvdata(pdev
, priv
);
188 if (!priv
->ops
|| !priv
->ops
->init
|| !priv
->ops
->get_temp
)
191 ret
= priv
->ops
->init(priv
);
193 dev_err(dev
, "%s: init failed\n", __func__
);
197 if (priv
->ops
->calibrate
) {
198 ret
= priv
->ops
->calibrate(priv
);
200 if (ret
!= -EPROBE_DEFER
)
201 dev_err(dev
, "%s: calibration failed\n", __func__
);
206 return tsens_register(priv
);
209 static int tsens_remove(struct platform_device
*pdev
)
211 struct tsens_priv
*priv
= platform_get_drvdata(pdev
);
213 debugfs_remove_recursive(priv
->debug_root
);
214 tsens_disable_irq(priv
);
215 if (priv
->ops
->disable
)
216 priv
->ops
->disable(priv
);
221 static struct platform_driver tsens_driver
= {
222 .probe
= tsens_probe
,
223 .remove
= tsens_remove
,
225 .name
= "qcom-tsens",
227 .of_match_table
= tsens_table
,
230 module_platform_driver(tsens_driver
);
232 MODULE_LICENSE("GPL v2");
233 MODULE_DESCRIPTION("QCOM Temperature Sensor driver");
234 MODULE_ALIAS("platform:qcom-tsens");