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",
78 MODULE_DEVICE_TABLE(of
, tsens_table
);
80 static const struct thermal_zone_of_device_ops tsens_of_ops
= {
81 .get_temp
= tsens_get_temp
,
82 .get_trend
= tsens_get_trend
,
85 static int tsens_register(struct tsens_device
*tmdev
)
88 struct thermal_zone_device
*tzd
;
89 u32
*hw_id
, n
= tmdev
->num_sensors
;
91 hw_id
= devm_kcalloc(tmdev
->dev
, n
, sizeof(u32
), GFP_KERNEL
);
95 for (i
= 0; i
< tmdev
->num_sensors
; i
++) {
96 tmdev
->sensor
[i
].tmdev
= tmdev
;
97 tmdev
->sensor
[i
].id
= i
;
98 tzd
= devm_thermal_zone_of_sensor_register(tmdev
->dev
, i
,
103 tmdev
->sensor
[i
].tzd
= tzd
;
104 if (tmdev
->ops
->enable
)
105 tmdev
->ops
->enable(tmdev
, i
);
110 static int tsens_probe(struct platform_device
*pdev
)
114 struct device_node
*np
;
115 struct tsens_sensor
*s
;
116 struct tsens_device
*tmdev
;
117 const struct tsens_data
*data
;
118 const struct of_device_id
*id
;
120 if (pdev
->dev
.of_node
)
123 dev
= pdev
->dev
.parent
;
127 id
= of_match_node(tsens_table
, np
);
133 if (data
->num_sensors
<= 0) {
134 dev_err(dev
, "invalid number of sensors\n");
138 tmdev
= devm_kzalloc(dev
, sizeof(*tmdev
) +
139 data
->num_sensors
* sizeof(*s
), GFP_KERNEL
);
144 tmdev
->num_sensors
= data
->num_sensors
;
145 tmdev
->ops
= data
->ops
;
146 for (i
= 0; i
< tmdev
->num_sensors
; i
++) {
148 tmdev
->sensor
[i
].hw_id
= data
->hw_ids
[i
];
150 tmdev
->sensor
[i
].hw_id
= i
;
153 if (!tmdev
->ops
|| !tmdev
->ops
->init
|| !tmdev
->ops
->get_temp
)
156 ret
= tmdev
->ops
->init(tmdev
);
158 dev_err(dev
, "tsens init failed\n");
162 if (tmdev
->ops
->calibrate
) {
163 ret
= tmdev
->ops
->calibrate(tmdev
);
165 dev_err(dev
, "tsens calibration failed\n");
170 ret
= tsens_register(tmdev
);
172 platform_set_drvdata(pdev
, tmdev
);
177 static int tsens_remove(struct platform_device
*pdev
)
179 struct tsens_device
*tmdev
= platform_get_drvdata(pdev
);
181 if (tmdev
->ops
->disable
)
182 tmdev
->ops
->disable(tmdev
);
187 static struct platform_driver tsens_driver
= {
188 .probe
= tsens_probe
,
189 .remove
= tsens_remove
,
191 .name
= "qcom-tsens",
193 .of_match_table
= tsens_table
,
196 module_platform_driver(tsens_driver
);
198 MODULE_LICENSE("GPL v2");
199 MODULE_DESCRIPTION("QCOM Temperature Sensor driver");
200 MODULE_ALIAS("platform:qcom-tsens");