hwmon: pm8921-adc: Add sysfs interface

-Add sysfs interface to read PM8921 HK/XOADC
and thermistor temperature measurements mapped
through MPP's.
-Move PM8921 ADC from directory /drivers/mfd to
/drivers/hwmon for userspace clients to read ADC
through hwmon.

CRs-Fixed: 302365
Signed-off-by: Siddartha Mohanadoss <smohanad@codeaurora.org>

Conflicts:

	drivers/mfd/Kconfig
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index d5f8f75..62213bd 100755
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -260,12 +260,12 @@
 # CONFIG_BATTERY_MSM is not set
 CONFIG_PM8921_CHARGER=y
 CONFIG_PM8921_BMS=y
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+CONFIG_SENSORS_PM8921_ADC=y
 CONFIG_THERMAL=y
 CONFIG_THERMAL_TSENS8960=y
 CONFIG_THERMAL_PM8XXX=y
 CONFIG_MFD_PM8921_CORE=y
-CONFIG_MFD_PM8921_ADC=y
 CONFIG_MFD_PM8XXX_BATT_ALARM=y
 CONFIG_WCD9310_CODEC=y
 CONFIG_REGULATOR_GPIO=y
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index f032bab..895d6dc 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -21,6 +21,7 @@
 #include <linux/msm_ssbi.h>
 #include <linux/regulator/gpio-regulator.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/regulator/consumer.h>
 #include <linux/spi/spi.h>
 #include <linux/slimbus/slimbus.h>
@@ -2284,10 +2285,6 @@
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
 	{"ibat", CHANNEL_IBAT, CHAN_PATH_SCALING1, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
-	{"m4", CHANNEL_MPP_1, CHAN_PATH_SCALING1, AMUX_RSV1,
-		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
-	{"m5", CHANNEL_MPP_2, CHAN_PATH_SCALING2, AMUX_RSV1,
-		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
 	{"batt_therm", CHANNEL_BATT_THERM, CHAN_PATH_SCALING1, AMUX_RSV2,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_BATT_THERM},
 	{"batt_id", CHANNEL_BATT_ID, CHAN_PATH_SCALING1, AMUX_RSV1,
@@ -2302,10 +2299,12 @@
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
 	{"chg_temp", CHANNEL_CHG_TEMP, CHAN_PATH_SCALING1, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_DEFAULT},
-	{"pa_therm", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
+	{"pa_therm1", ADC_MPP_1_AMUX8, CHAN_PATH_SCALING1, AMUX_RSV1,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
 	{"xo_therm", CHANNEL_MUXOFF, CHAN_PATH_SCALING1, AMUX_RSV0,
 		ADC_DECIMATION_TYPE2, ADC_SCALE_XOTHERM},
+	{"pa_therm0", ADC_MPP_1_AMUX3, CHAN_PATH_SCALING1, AMUX_RSV1,
+		ADC_DECIMATION_TYPE2, ADC_SCALE_PA_THERM},
 };
 
 static struct pm8921_adc_properties pm8921_adc_data = {
@@ -2316,9 +2315,9 @@
 
 static struct pm8921_adc_platform_data pm8921_adc_pdata = {
 	.adc_channel		= pm8921_adc_channels_data,
-	.adc_num_channel	= ARRAY_SIZE(pm8921_adc_channels_data),
+	.adc_num_board_channel	= ARRAY_SIZE(pm8921_adc_channels_data),
 	.adc_prop		= &pm8921_adc_data,
-	.adc_mpp_base		= PM8921_MPP_PM_TO_SYS(0),
+	.adc_mpp_base		= PM8921_MPP_PM_TO_SYS(1),
 };
 
 static void __init msm8960_map_io(void)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index ef3cb2e..f9d671e 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -788,6 +788,15 @@
 	  internally uses an array of LTC2499 and EPM ADCs in a differential
 	  configuration to provide a flat set of channels that can be addressed.
 
+config SENSORS_PM8921_ADC
+	tristate "Support for Qualcomm PM8921 ADC"
+	depends on MFD_PM8921_CORE
+	help
+	  This is the ADC arbiter driver for Qualcomm PM8921 Chip.
+
+	  The driver supports reading the HKADC, XOADC and support to set and receive
+	  temperature threshold notifications using the Battery temperature module.
+
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
 	select HWMON_VID
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eacfcb5..c25ffcb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -120,6 +120,7 @@
 obj-$(CONFIG_SENSORS_WM8350)	+= wm8350-hwmon.o
 obj-$(CONFIG_SENSORS_WPCE775X)	+= wpce775x.o
 obj-$(CONFIG_SENSORS_MSM_ADC)	+= msm_adc.o m_adcproc.o
+obj-$(CONFIG_SENSORS_PM8921_ADC)	+= pm8921-adc.o msmproc_adc.o
 
 # PMBus drivers
 obj-$(CONFIG_PMBUS)		+= pmbus_core.o
diff --git a/drivers/mfd/msmproc_adc.c b/drivers/hwmon/msmproc_adc.c
similarity index 99%
rename from drivers/mfd/msmproc_adc.c
rename to drivers/hwmon/msmproc_adc.c
index 5f2f975..a0ee748 100644
--- a/drivers/mfd/msmproc_adc.c
+++ b/drivers/hwmon/msmproc_adc.c
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/err.h>
 #include <linux/module.h>
-#include <linux/mfd/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 #define KELVINMIL_DEGMIL	273160
 
 static const struct pm8921_adc_map_pt adcmap_batttherm[] = {
diff --git a/drivers/mfd/pm8921-adc.c b/drivers/hwmon/pm8921-adc.c
similarity index 92%
rename from drivers/mfd/pm8921-adc.c
rename to drivers/hwmon/pm8921-adc.c
index b545fa5..5ab6296 100644
--- a/drivers/mfd/pm8921-adc.c
+++ b/drivers/hwmon/pm8921-adc.c
@@ -26,9 +26,11 @@
 #include <linux/platform_device.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/mpp.h>
-#include <linux/mfd/pm8921-adc.h>
 #include <linux/debugfs.h>
 #include <linux/regulator/consumer.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 
 /* User Bank register set */
 #define PM8921_ADC_ARB_USRP_CNTRL1			0x197
@@ -127,6 +129,7 @@
 	struct mutex				mpp_adc_lock;
 	spinlock_t				btm_lock;
 	uint32_t				adc_num_channel;
+	uint32_t				adc_num_board_channel;
 	struct completion			adc_rslt_completion;
 	struct pm8921_adc_amux			*adc_channel;
 	struct pm8921_adc_amux_properties	*conv;
@@ -137,6 +140,8 @@
 	struct work_struct			warm_work;
 	struct work_struct			cool_work;
 	uint32_t				mpp_base;
+	struct sensor_device_attribute		*sens_attr;
+	struct device				*hwmon;
 };
 
 struct pm8921_adc_amux_properties {
@@ -763,7 +768,7 @@
 
 	mutex_lock(&adc_pmic->mpp_adc_lock);
 
-	rc = pm8xxx_mpp_config((mpp_num + adc_pmic->mpp_base),
+	rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
 					&pm8921_adc_mpp_config);
 	if (rc < 0) {
 		pr_err("pm8921 adc mpp config error with %d\n", rc);
@@ -777,7 +782,7 @@
 	if (rc < 0)
 		pr_err("pm8921 adc read error with %d\n", rc);
 
-	rc = pm8xxx_mpp_config((mpp_num + adc_pmic->mpp_base),
+	rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
 					&pm8921_adc_mpp_unconfig);
 	if (rc < 0)
 		pr_err("pm8921 adc mpp config error with %d\n", rc);
@@ -978,6 +983,25 @@
 }
 EXPORT_SYMBOL_GPL(pm8921_adc_btm_end);
 
+static ssize_t pm8921_adc_show(struct device *dev,
+			struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+	struct pm8921_adc *adc_pmic = pmic_adc;
+	struct pm8921_adc_chan_result result;
+	int rc = -1;
+
+	if (attr->index < adc_pmic->adc_num_channel)
+		rc = pm8921_adc_read(attr->index, &result);
+
+	if (rc)
+		return 0;
+
+	return snprintf(buf, sizeof(struct pm8921_adc_chan_result),
+				"Result:%lld Raw:%d\n",
+				result.physical, result.adc_code);
+}
+
 static int get_adc(void *data, u64 *val)
 {
 	struct pm8921_adc_chan_result result;
@@ -1000,8 +1024,8 @@
 	int i = (int)data;
 	int rc;
 
-	rc = pm8921_adc_mpp_config_read(PM8921_AMUX_MPP_8,
-		i, &result);
+	rc = pm8921_adc_mpp_config_read(i,
+		ADC_MPP_1_AMUX6, &result);
 	if (!rc)
 		pr_info("ADC MPP value raw:%x physical:%lld\n",
 			result.adc_code, result.physical);
@@ -1047,22 +1071,62 @@
 			    (void *)CHANNEL_ICHG, &reg_fops);
 	debugfs_create_file("ibat", 0644, pmic_adc->dent,
 			    (void *)CHANNEL_IBAT, &reg_fops);
-	debugfs_create_file("pa_therm", 0644, pmic_adc->dent,
+	debugfs_create_file("pa_therm1", 0644, pmic_adc->dent,
 			    (void *)ADC_MPP_1_AMUX8, &reg_fops);
 	debugfs_create_file("xo_therm", 0644, pmic_adc->dent,
 			    (void *)CHANNEL_MUXOFF, &reg_fops);
+	debugfs_create_file("pa_therm0", 0644, pmic_adc->dent,
+			    (void *)ADC_MPP_1_AMUX3, &reg_fops);
 }
 #else
 static inline void create_debugfs_entries(void)
 {
 }
 #endif
+static struct sensor_device_attribute pm8921_adc_attr =
+	SENSOR_ATTR(NULL, S_IRUGO, pm8921_adc_show, NULL, 0);
+
+static int32_t pm8921_adc_init_hwmon(struct platform_device *pdev)
+{
+	struct pm8921_adc *adc_pmic = pmic_adc;
+	int rc = 0, i;
+
+	adc_pmic->sens_attr = kzalloc(pmic_adc->adc_num_board_channel *
+		sizeof(struct sensor_device_attribute), GFP_KERNEL);
+
+	if (!adc_pmic->sens_attr) {
+		dev_err(&pdev->dev, "Unable to allocate memory\n");
+		rc = -ENOMEM;
+		goto hwmon_err_sens;
+	}
+
+	for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
+		pm8921_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
+		pm8921_adc_attr.dev_attr.attr.name =
+						adc_pmic->adc_channel[i].name;
+		memcpy(&adc_pmic->sens_attr[i], &pm8921_adc_attr,
+						sizeof(pm8921_adc_attr));
+		rc = device_create_file(&pdev->dev,
+				&adc_pmic->sens_attr[i].dev_attr);
+		if (rc) {
+			dev_err(&pdev->dev, "device_create_file failed for "
+					    "dev %s\n",
+					    adc_pmic->adc_channel[i].name);
+			goto hwmon_err_sens;
+		}
+	}
+	return 0;
+
+hwmon_err_sens:
+	pr_info("Init HWMON failed for pm8921_adc with %d\n", rc);
+	return rc;
+}
 
 static int __devexit pm8921_adc_teardown(struct platform_device *pdev)
 {
 	struct pm8921_adc *adc_pmic = pmic_adc;
+	int i;
 
-	device_init_wakeup(&pdev->dev, 0);
 	free_irq(adc_pmic->adc_irq, adc_pmic);
 	free_irq(adc_pmic->btm_warm_irq, adc_pmic);
 	free_irq(adc_pmic->btm_cool_irq, adc_pmic);
@@ -1071,6 +1135,10 @@
 	kfree(adc_pmic->conv->chan_prop);
 	kfree(adc_pmic->adc_channel);
 	kfree(adc_pmic->batt);
+	for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
+		device_remove_file(adc_pmic->dev,
+				&adc_pmic->sens_attr[i].dev_attr);
+	kfree(adc_pmic->sens_attr);
 	kfree(adc_pmic);
 	pm8921_adc_initialized = false;
 
@@ -1127,6 +1195,7 @@
 
 	init_completion(&adc_pmic->adc_rslt_completion);
 	adc_pmic->adc_channel = pdata->adc_channel;
+	adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
 	adc_pmic->adc_num_channel = ADC_MPP_2_CHANNEL_NONE;
 	adc_pmic->mpp_base = pdata->adc_mpp_base;
 
@@ -1188,7 +1257,6 @@
 	}
 
 	disable_irq_nosync(adc_pmic->btm_cool_irq);
-	device_init_wakeup(&pdev->dev, pdata->adc_wakeup);
 	platform_set_drvdata(pdev, adc_pmic);
 	pmic_adc = adc_pmic;
 
@@ -1198,6 +1266,13 @@
 	pm8921_adc_calib_first_adc = false;
 	pm8921_adc_calib_device_init = false;
 	pm8921_adc_initialized = true;
+
+	rc = pm8921_adc_init_hwmon(pdev);
+	if (rc) {
+		pr_err("pm8921 adc init hwmon failed with %d\n", rc);
+		goto err_cleanup;
+	}
+	adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
 	return 0;
 
 err_cleanup:
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b17495f..d291baa 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -827,15 +827,6 @@
 config TPS65911_COMPARATOR
 	tristate
 
-config MFD_PM8921_ADC
-	tristate "Support for Qualcomm PM8921 ADC"
-	depends on MFD_PM8921_CORE
-	help
-	  This is the ADC arbiter driver for Qualcomm PM8921 Chip.
-
-	  The driver supports reading the HKADC, XOADC and support to set and receive
-	  temperature threshold notifications using the Battery temperature module.
-
 config MFD_PM8XXX_DEBUG
 	tristate "Qualcomm PM8xxx debugfs support"
 	depends on MFD_PM8XXX && DEBUG_FS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b15e09a..5813b86 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -122,4 +122,3 @@
 obj-$(CONFIG_MFD_PM8XXX_PWM) 	+= pm8xxx-pwm.o
 obj-$(CONFIG_MFD_PM8XXX_MISC) 	+= pm8xxx-misc.o
 obj-$(CONFIG_MFD_PM8XXX_BATT_ALARM) 	+= pm8xxx-batt-alarm.o
-obj-$(CONFIG_MFD_PM8921_ADC)	+= pm8921-adc.o msmproc_adc.o
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 79124f7..1307da4 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -18,7 +18,7 @@
 #include <linux/errno.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 84e5ef3..fba714e 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -18,7 +18,7 @@
 #include <linux/errno.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
-#include <linux/mfd/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/interrupt.h>
 #include <linux/power_supply.h>
diff --git a/drivers/thermal/pm8xxx-tm.c b/drivers/thermal/pm8xxx-tm.c
index a094aed..d9f9c9e 100644
--- a/drivers/thermal/pm8xxx-tm.c
+++ b/drivers/thermal/pm8xxx-tm.c
@@ -29,7 +29,7 @@
 #include <linux/mfd/pm8xxx/core.h>
 #include <linux/mfd/pm8xxx/tm.h>
 #include <linux/completion.h>
-#include <linux/mfd/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 
 /* Register TEMP_ALARM_CTRL bits */
 #define	TEMP_ALARM_CTRL_ST3_SD		0x80
diff --git a/include/linux/mfd/pm8921-adc.h b/include/linux/mfd/pm8xxx/pm8921-adc.h
similarity index 96%
rename from include/linux/mfd/pm8921-adc.h
rename to include/linux/mfd/pm8xxx/pm8921-adc.h
index 412bd91..2d81134 100644
--- a/include/linux/mfd/pm8921-adc.h
+++ b/include/linux/mfd/pm8xxx/pm8921-adc.h
@@ -15,8 +15,8 @@
  *
  */
 
-#ifndef __MFD_PM8921_ADC_H
-#define __MFD_PM8921_ADC_H
+#ifndef __PM8921_ADC_H
+#define __PM8921_ADC_H
 
 #include <linux/kernel.h>
 #include <linux/list.h>
@@ -296,7 +296,8 @@
 	int64_t		physical;
 };
 
-#if defined(CONFIG_MFD_PM8921_ADC) || defined(CONFIG_MFD_PM8921_ADC_MODULE)
+#if defined(CONFIG_SENSORS_PM8921_ADC)					\
+			|| defined(CONFIG_SENSORS_PM8921_ADC_MODULE)
 /**
  * pm8921_adc_scale_default() - Scales the pre-calibrated digital output
  *		of an ADC to the ADC reference and compensates for the
@@ -467,18 +468,21 @@
  * struct pm8921_adc_platform_data - PM8921 ADC platform data
  * @adc_prop: ADC specific parameters, voltage and channel setup
  * @adc_channel: Channel properties of the ADC arbiter
- * @adc_num_channel: Total number of chanels supported
+ * @adc_num_board_channel: Number of channels added in the board file
+ * @adc_mpp_base: PM8921 MPP0 base passed from board file. This is used
+ *		  to offset the PM8921 MPP passed to configure the
+ *		  the MPP to AMUX mapping.
  */
 struct pm8921_adc_platform_data {
 	struct pm8921_adc_properties	*adc_prop;
 	struct pm8921_adc_amux		*adc_channel;
-	uint32_t			adc_num_channel;
-	u32				adc_wakeup;
+	uint32_t			adc_num_board_channel;
 	uint32_t			adc_mpp_base;
 };
 
 /* Public API */
-#if defined(CONFIG_MFD_PM8921_ADC) || defined(CONFIG_MFD_PM8921_ADC_MODULE)
+#if defined(CONFIG_SENSORS_PM8921_ADC)				\
+			|| defined(CONFIG_SENSORS_PM8921_ADC_MODULE)
 /**
  * pm8921_adc_read() - Performs ADC read on the channel.
  * @channel:	Input channel to perform the ADC read.
@@ -555,4 +559,4 @@
 { return -ENXIO; }
 #endif
 
-#endif /* MFD_PM8921_ADC_H */
+#endif /* PM8921_ADC_H */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 36f6fc9..bde5bbc 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -31,7 +31,7 @@
 #include <linux/input/pmic8xxx-keypad.h>
 #include <linux/regulator/pm8921-regulator.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
-#include <linux/mfd/pm8921-adc.h>
+#include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
 #include <linux/leds.h>
 #include <linux/mfd/pm8xxx/vibrator.h>