thermal: msm8960_tsens: Read TSENS temperature

Add kernel API to read TSENS temperature for clients
in the kernel space. Currently the TSENS driver only
supports reading the TSENS temperature from the
thermal sys.

Split the TSENS initialization into two parts.
First is to perform the initial calibration that is
used to convert the raw ADC code to Degrees Celcius
and initialize the TSENS HW. Second is to register the
TSENS driver to the linux thermal framework and create
the temperature zones that will be accessed by the
Thermal daemon to set thresholds, read the temperature
and receive notifications.

Change-Id: Id2305a7aa755e1e9cfaecd8b5c1870ed05d9b5e9
Signed-off-by: Praveen Chidambaram <pchidamb@codeaurora.org>
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>
diff --git a/drivers/thermal/msm8960_tsens.c b/drivers/thermal/msm8960_tsens.c
index a616ffc..f2be9dc 100644
--- a/drivers/thermal/msm8960_tsens.c
+++ b/drivers/thermal/msm8960_tsens.c
@@ -165,29 +165,47 @@
 	return code;
 }
 
-static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
-			     unsigned long *temp)
+static void tsens8960_get_temp(int sensor_num, unsigned long *temp)
 {
-	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
 	unsigned int code;
 
-	if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
-		return -EINVAL;
-
 	if (!tmdev->prev_reading_avail) {
-		while (!(readl_relaxed(TSENS_INT_STATUS_ADDR) &
-						TSENS_TRDY_MASK))
+		while (!(readl_relaxed(TSENS_INT_STATUS_ADDR)
+					& TSENS_TRDY_MASK))
 			usleep_range(TSENS_TRDY_RDY_MIN_TIME,
 				TSENS_TRDY_RDY_MAX_TIME);
 		tmdev->prev_reading_avail = true;
 	}
+
 	code = readl_relaxed(TSENS_S0_STATUS_ADDR +
-			(tm_sensor->sensor_num << TSENS_STATUS_ADDR_OFFSET));
-	*temp = tsens_tz_code_to_degC(code, tm_sensor->sensor_num);
+			(sensor_num << TSENS_STATUS_ADDR_OFFSET));
+	*temp = tsens_tz_code_to_degC(code, sensor_num);
+}
+
+static int tsens_tz_get_temp(struct thermal_zone_device *thermal,
+			     unsigned long *temp)
+{
+	struct tsens_tm_device_sensor *tm_sensor = thermal->devdata;
+
+	if (!tm_sensor || tm_sensor->mode != THERMAL_DEVICE_ENABLED || !temp)
+		return -EINVAL;
+
+	tsens8960_get_temp(tm_sensor->sensor_num, temp);
 
 	return 0;
 }
 
+int tsens_get_temp(struct tsens_device *device, unsigned long *temp)
+{
+	if (!tmdev)
+		return -ENODEV;
+
+	tsens8960_get_temp(device->sensor_num, temp);
+
+	return 0;
+}
+EXPORT_SYMBOL(tsens_get_temp);
+
 static int tsens_tz_get_mode(struct thermal_zone_device *thermal,
 			      enum thermal_device_mode *mode)
 {
@@ -745,12 +763,10 @@
 	return rc;
 }
 
-static int __devinit tsens_tm_probe(struct platform_device *pdev)
+int msm_tsens_early_init(struct tsens_platform_data *pdata)
 {
-	int rc, i;
-	struct tsens_platform_data *pdata;
+	int rc = 0;
 
-	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 		pr_err("No TSENS Platform data\n");
 		return -EINVAL;
@@ -759,7 +775,7 @@
 	tmdev = kzalloc(sizeof(struct tsens_tm_device) +
 			pdata->tsens_num_sensor *
 			sizeof(struct tsens_tm_device_sensor),
-			GFP_KERNEL);
+			GFP_ATOMIC);
 	if (tmdev == NULL) {
 		pr_err("%s: kzalloc() failed.\n", __func__);
 		return -ENOMEM;
@@ -782,11 +798,23 @@
 		return rc;
 	}
 
-	platform_set_drvdata(pdev, tmdev);
-
 	tsens_hw_init();
 
-	for (i = 0; i < pdata->tsens_num_sensor; i++) {
+	pr_info("msm_tsens_early_init: done\n");
+
+	return rc;
+}
+
+static int __init tsens_tm_init(void)
+{
+	int rc, i;
+
+	if (!tmdev) {
+		pr_info("%s : TSENS early init not done.\n", __func__);
+		return -EFAULT;
+	}
+
+	for (i = 0; i < tmdev->tsens_num_sensor; i++) {
 		char name[17];
 		snprintf(name, sizeof(name), "tsens_tz_sensor%d", i);
 		tmdev->sensor[i].mode = THERMAL_DEVICE_ENABLED;
@@ -812,22 +840,18 @@
 		goto fail;
 	}
 
-	tsens_disable_mode();
-
 	pr_notice("%s: OK\n", __func__);
 	mb();
 	return 0;
 fail:
 	tsens_disable_mode();
-	platform_set_drvdata(pdev, NULL);
 	kfree(tmdev);
 	mb();
 	return rc;
 }
 
-static int __devexit tsens_tm_remove(struct platform_device *pdev)
+static void __exit tsens_tm_remove(void)
 {
-	struct tsens_tm_device *tmdev = platform_get_drvdata(pdev);
 	int i;
 
 	tsens_disable_mode();
@@ -835,32 +859,11 @@
 	free_irq(TSENS_UPPER_LOWER_INT, tmdev);
 	for (i = 0; i < tmdev->tsens_num_sensor; i++)
 		thermal_zone_device_unregister(tmdev->sensor[i].tz_dev);
-	platform_set_drvdata(pdev, NULL);
 	kfree(tmdev);
-	return 0;
 }
 
-static struct platform_driver tsens_tm_driver = {
-	.probe	= tsens_tm_probe,
-	.remove	= __devexit_p(tsens_tm_remove),
-	.driver	= {
-		.name = "tsens8960-tm",
-		.owner = THIS_MODULE,
-	},
-};
-
-static int __init tsens_init(void)
-{
-	return platform_driver_register(&tsens_tm_driver);
-}
-
-static void __exit tsens_exit(void)
-{
-	platform_driver_unregister(&tsens_tm_driver);
-}
-
-module_init(tsens_init);
-module_exit(tsens_exit);
+module_init(tsens_tm_init);
+module_exit(tsens_tm_remove);
 
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("MSM8960 Temperature Sensor driver");
diff --git a/include/linux/msm_tsens.h b/include/linux/msm_tsens.h
index 2a92899..189548c 100644
--- a/include/linux/msm_tsens.h
+++ b/include/linux/msm_tsens.h
@@ -32,4 +32,11 @@
 	enum platform_type		hw_type;
 };
 
+struct tsens_device {
+	uint32_t			sensor_num;
+};
+
+int32_t tsens_get_temp(struct tsens_device *dev, unsigned long *temp);
+int msm_tsens_early_init(struct tsens_platform_data *pdata);
+
 #endif /*MSM_TSENS_H */