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/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