2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <linux/err.h>
16 #include <linux/module.h>
18 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 #include <linux/thermal.h>
24 static int tsens_get_temp(void *data
, int *temp
)
26 const struct tsens_sensor
*s
= data
;
27 struct tsens_device
*tmdev
= s
->tmdev
;
29 return tmdev
->ops
->get_temp(tmdev
, s
->id
, temp
);
32 static int tsens_get_trend(void *p
, int trip
, enum thermal_trend
*trend
)
34 const struct tsens_sensor
*s
= p
;
35 struct tsens_device
*tmdev
= s
->tmdev
;
37 if (tmdev
->ops
->get_trend
)
38 return tmdev
->ops
->get_trend(tmdev
, s
->id
, trend
);
43 static int __maybe_unused
tsens_suspend(struct device
*dev
)
45 struct tsens_device
*tmdev
= dev_get_drvdata(dev
);
47 if (tmdev
->ops
&& tmdev
->ops
->suspend
)
48 return tmdev
->ops
->suspend(tmdev
);
53 static int __maybe_unused
tsens_resume(struct device
*dev
)
55 struct tsens_device
*tmdev
= dev_get_drvdata(dev
);
57 if (tmdev
->ops
&& tmdev
->ops
->resume
)
58 return tmdev
->ops
->resume(tmdev
);
63 static SIMPLE_DEV_PM_OPS(tsens_pm_ops
, tsens_suspend
, tsens_resume
);
65 static const struct of_device_id tsens_table
[] = {
67 .compatible
= "qcom,msm8916-tsens",
70 .compatible
= "qcom,msm8974-tsens",
73 .compatible
= "qcom,msm8996-tsens",
76 .compatible
= "qcom,tsens-v2",
77 .data
= &data_tsens_v2
,
81 MODULE_DEVICE_TABLE(of
, tsens_table
);
83 static const struct thermal_zone_of_device_ops tsens_of_ops
= {
84 .get_temp
= tsens_get_temp
,
85 .get_trend
= tsens_get_trend
,
88 static int tsens_register(struct tsens_device
*tmdev
)
91 struct thermal_zone_device
*tzd
;
92 u32
*hw_id
, n
= tmdev
->num_sensors
;
94 hw_id
= devm_kcalloc(tmdev
->dev
, n
, sizeof(u32
), GFP_KERNEL
);
98 for (i
= 0; i
< tmdev
->num_sensors
; i
++) {
99 tmdev
->sensor
[i
].tmdev
= tmdev
;
100 tmdev
->sensor
[i
].id
= i
;
101 tzd
= devm_thermal_zone_of_sensor_register(tmdev
->dev
, i
,
106 tmdev
->sensor
[i
].tzd
= tzd
;
107 if (tmdev
->ops
->enable
)
108 tmdev
->ops
->enable(tmdev
, i
);
113 static int tsens_probe(struct platform_device
*pdev
)
117 struct device_node
*np
;
118 struct tsens_device
*tmdev
;
119 const struct tsens_data
*data
;
120 const struct of_device_id
*id
;
123 if (pdev
->dev
.of_node
)
126 dev
= pdev
->dev
.parent
;
130 id
= of_match_node(tsens_table
, np
);
136 num_sensors
= data
->num_sensors
;
139 of_property_read_u32(np
, "#qcom,sensors", &num_sensors
);
141 if (num_sensors
<= 0) {
142 dev_err(dev
, "invalid number of sensors\n");
146 tmdev
= devm_kzalloc(dev
,
147 struct_size(tmdev
, sensor
, num_sensors
),
153 tmdev
->num_sensors
= num_sensors
;
154 tmdev
->ops
= data
->ops
;
155 for (i
= 0; i
< tmdev
->num_sensors
; i
++) {
157 tmdev
->sensor
[i
].hw_id
= data
->hw_ids
[i
];
159 tmdev
->sensor
[i
].hw_id
= i
;
162 if (!tmdev
->ops
|| !tmdev
->ops
->init
|| !tmdev
->ops
->get_temp
)
165 ret
= tmdev
->ops
->init(tmdev
);
167 dev_err(dev
, "tsens init failed\n");
171 if (tmdev
->ops
->calibrate
) {
172 ret
= tmdev
->ops
->calibrate(tmdev
);
174 if (ret
!= -EPROBE_DEFER
)
175 dev_err(dev
, "tsens calibration failed\n");
180 ret
= tsens_register(tmdev
);
182 platform_set_drvdata(pdev
, tmdev
);
187 static int tsens_remove(struct platform_device
*pdev
)
189 struct tsens_device
*tmdev
= platform_get_drvdata(pdev
);
191 if (tmdev
->ops
->disable
)
192 tmdev
->ops
->disable(tmdev
);
197 static struct platform_driver tsens_driver
= {
198 .probe
= tsens_probe
,
199 .remove
= tsens_remove
,
201 .name
= "qcom-tsens",
203 .of_match_table
= tsens_table
,
206 module_platform_driver(tsens_driver
);
208 MODULE_LICENSE("GPL v2");
209 MODULE_DESCRIPTION("QCOM Temperature Sensor driver");
210 MODULE_ALIAS("platform:qcom-tsens");