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, ®_fops);
debugfs_create_file("ibat", 0644, pmic_adc->dent,
(void *)CHANNEL_IBAT, ®_fops);
- debugfs_create_file("pa_therm", 0644, pmic_adc->dent,
+ debugfs_create_file("pa_therm1", 0644, pmic_adc->dent,
(void *)ADC_MPP_1_AMUX8, ®_fops);
debugfs_create_file("xo_therm", 0644, pmic_adc->dent,
(void *)CHANNEL_MUXOFF, ®_fops);
+ debugfs_create_file("pa_therm0", 0644, pmic_adc->dent,
+ (void *)ADC_MPP_1_AMUX3, ®_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>