linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/35] mfd: ab8500: Internal development push
@ 2013-02-15 12:56 Lee Jones
  2013-02-15 12:56 ` [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume Lee Jones
                   ` (34 more replies)
  0 siblings, 35 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sam,

This is the patch-set we've been speaking about. It's the entire
development history for the ABx500 related MFD changes from
ST-Ericsson's internal kernel. This brings us bang up-to-date.

Please don't apply patches directly from this submission, as
there are some interdependencies which we need to sort out
between you, Anton and I.

Enjoy! =:-)


 drivers/mfd/ab8500-core.c                 |  524 +++++++++++++++++++-------
 drivers/mfd/ab8500-debugfs.c              | 2511 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
 drivers/mfd/ab8500-gpadc.c                |  577 +++++++++++++++++++++++------
 drivers/mfd/ab8500-sysctrl.c              |   98 ++++-
 include/linux/mfd/abx500.h                |    2 -
 include/linux/mfd/abx500/ab8500-gpadc.h   |   74 +++-
 include/linux/mfd/abx500/ab8500-sysctrl.h |    6 +
 include/linux/mfd/abx500/ab8500.h         |  242 +++++++++---
 8 files changed, 3177 insertions(+), 857 deletions(-)

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-20 13:19   ` Mark Brown
  2013-02-15 12:56 ` [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing Lee Jones
                   ` (33 subsequent siblings)
  34 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Daniel WILLERUD <daniel.willerud@stericsson.com>

suspend/resume methods implemented to prevent suspend while the gpadc
driver is busy.

Signed-off-by: Daniel WILLERUD <daniel.willerud@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com>
---
 drivers/mfd/ab8500-gpadc.c |   28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index b1f3561..9ed3afc 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -605,6 +605,31 @@ static int ab8500_gpadc_runtime_idle(struct device *dev)
 	return 0;
 }
 
+static int ab8500_gpadc_suspend(struct device *dev)
+{
+	struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+	mutex_lock(&gpadc->ab8500_gpadc_lock);
+
+	pm_runtime_get_sync(dev);
+
+	regulator_disable(gpadc->regu);
+	return 0;
+}
+
+static int ab8500_gpadc_resume(struct device *dev)
+{
+	struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
+
+	regulator_enable(gpadc->regu);
+
+	pm_runtime_mark_last_busy(gpadc->dev);
+	pm_runtime_put_autosuspend(gpadc->dev);
+
+	mutex_unlock(&gpadc->ab8500_gpadc_lock);
+	return 0;
+}
+
 static int ab8500_gpadc_probe(struct platform_device *pdev)
 {
 	int ret = 0;
@@ -698,6 +723,9 @@ static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
 	SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
 			   ab8500_gpadc_runtime_resume,
 			   ab8500_gpadc_runtime_idle)
+	SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
+				ab8500_gpadc_resume)
+
 };
 
 static struct platform_driver ab8500_gpadc_driver = {
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
  2013-02-15 12:56 ` [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-20 13:23   ` Mark Brown
  2013-02-15 12:56 ` [PATCH 03/35] mfd: ab8500-gpadc: Reread on failure Lee Jones
                   ` (32 subsequent siblings)
  34 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jonas Aaberg <jonas.aberg@stericsson.com>

Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org
---
 drivers/mfd/ab8500-gpadc.c |   19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 9ed3afc..34c1d04 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -140,6 +140,9 @@ struct ab8500_gpadc *ab8500_gpadc_get(char *name)
 {
 	struct ab8500_gpadc *gpadc;
 
+	if (list_empty(&ab8500_gpadc_list))
+		return NULL;
+
 	list_for_each_entry(gpadc, &ab8500_gpadc_list, node) {
 		if (!strcmp(name, dev_name(gpadc->dev)))
 		    return gpadc;
@@ -587,7 +590,8 @@ static int ab8500_gpadc_runtime_suspend(struct device *dev)
 {
 	struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
 
-	regulator_disable(gpadc->regu);
+	if (gpadc->regu)
+		regulator_disable(gpadc->regu);
 	return 0;
 }
 
@@ -595,7 +599,8 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
 {
 	struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
 
-	regulator_enable(gpadc->regu);
+	if (gpadc->regu)
+		regulator_enable(gpadc->regu);
 	return 0;
 }
 
@@ -670,9 +675,8 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	/* VTVout LDO used to power up ab8500-GPADC */
 	gpadc->regu = regulator_get(&pdev->dev, "vddadc");
 	if (IS_ERR(gpadc->regu)) {
-		ret = PTR_ERR(gpadc->regu);
-		dev_err(gpadc->dev, "failed to get vtvout LDO\n");
-		goto fail_irq;
+		dev_warn(gpadc->dev, "failed to get vtvout LDO\n");
+		gpadc->regu = NULL;
 	}
 
 	platform_set_drvdata(pdev, gpadc);
@@ -688,8 +692,6 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	list_add_tail(&gpadc->node, &ab8500_gpadc_list);
 	dev_dbg(gpadc->dev, "probe success\n");
 	return 0;
-fail_irq:
-	free_irq(gpadc->irq, gpadc);
 fail:
 	kfree(gpadc);
 	gpadc = NULL;
@@ -708,7 +710,8 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 	pm_runtime_get_sync(gpadc->dev);
 	pm_runtime_disable(gpadc->dev);
 
-	regulator_disable(gpadc->regu);
+	if (gpadc->regu)
+		regulator_disable(gpadc->regu);
 
 	pm_runtime_set_suspended(gpadc->dev);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 03/35] mfd: ab8500-gpadc: Reread on failure
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
  2013-02-15 12:56 ` [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume Lee Jones
  2013-02-15 12:56 ` [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 04/35] mfd: ab8500-gpadc: Add gpadc hw conversion Lee Jones
                   ` (31 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jonas Aaberg <jonas.aberg@stericsson.com>

Reread the gpadc once upon failure.

Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-gpadc.c |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 34c1d04..1b48ac1 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -259,6 +259,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
 	int voltage;
 
 	ad_value = ab8500_gpadc_read_raw(gpadc, channel);
+
+	/* On failure retry a second time */
+	if (ad_value < 0)
+		ad_value = ab8500_gpadc_read_raw(gpadc, channel);
+
 	if (ad_value < 0) {
 		dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n", channel);
 		return ad_value;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 04/35] mfd: ab8500-gpadc: Add gpadc hw conversion
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (2 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 03/35] mfd: ab8500-gpadc: Reread on failure Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 05/35] mfd: ab8500-core: APE Interrupts are not cleared Lee Jones
                   ` (30 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Michel JAOUEN <michel.jaouen@stericsson.com>

Add the support of gpacd hw conversion and make the number of
sample configurable.

Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
Tested-by: Michel JAOUEN <michel.jaouen@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c            |  292 ++++++++++++++++++++++++++++---
 drivers/mfd/ab8500-gpadc.c              |  282 +++++++++++++++++++++--------
 include/linux/mfd/abx500/ab8500-gpadc.h |   30 +++-
 3 files changed, 500 insertions(+), 104 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index ba25f95..8078a93 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -100,6 +100,11 @@ static int num_irqs;
 static struct device_attribute **dev_attr;
 static char **event_name;
 
+static u8 avg_sample = SAMPLE_16;
+static u8 trig_edge = RISING_EDGE;
+static u8 conv_type = ADC_SW;
+static u8 trig_timer;
+
 /**
  * struct ab8500_reg_range
  * @first: the first address of the range
@@ -807,9 +812,10 @@ static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL);
+	bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-			BAT_CTRL, bat_ctrl_raw);
+		BAT_CTRL, bat_ctrl_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			bat_ctrl_convert, bat_ctrl_raw);
@@ -835,9 +841,10 @@ static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL);
+	btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
-			btemp_ball_raw);
+		btemp_ball_raw);
 
 	return seq_printf(s,
 			"%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
@@ -864,9 +871,10 @@ static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V);
+	main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-			MAIN_CHARGER_V, main_charger_v_raw);
+		MAIN_CHARGER_V, main_charger_v_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			main_charger_v_convert, main_charger_v_raw);
@@ -894,9 +902,10 @@ static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1);
+	acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
-			acc_detect1_raw);
+		acc_detect1_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			acc_detect1_convert, acc_detect1_raw);
@@ -924,9 +933,10 @@ static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2);
+	acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-	    ACC_DETECT2, acc_detect2_raw);
+		ACC_DETECT2, acc_detect2_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			acc_detect2_convert, acc_detect2_raw);
@@ -954,9 +964,10 @@ static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1);
+	aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
-			aux1_raw);
+		aux1_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			aux1_convert, aux1_raw);
@@ -982,9 +993,10 @@ static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2);
+	aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
-			aux2_raw);
+		aux2_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			aux2_convert, aux2_raw);
@@ -1010,9 +1022,10 @@ static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V);
+	main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
-			main_bat_v_raw);
+		main_bat_v_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			main_bat_v_convert, main_bat_v_raw);
@@ -1039,9 +1052,10 @@ static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V);
+	vbus_v_raw =  ab8500_gpadc_read_raw(gpadc, VBUS_V,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
-			vbus_v_raw);
+		vbus_v_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			vbus_v_convert, vbus_v_raw);
@@ -1067,9 +1081,10 @@ static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C);
+	main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-			MAIN_CHARGER_C, main_charger_c_raw);
+		MAIN_CHARGER_C, main_charger_c_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			main_charger_c_convert, main_charger_c_raw);
@@ -1097,9 +1112,10 @@ static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C);
+	usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-	    USB_CHARGER_C, usb_charger_c_raw);
+		USB_CHARGER_C, usb_charger_c_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			usb_charger_c_convert, usb_charger_c_raw);
@@ -1127,9 +1143,10 @@ static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V);
+	bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
-			BK_BAT_V, bk_bat_v_raw);
+		BK_BAT_V, bk_bat_v_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			bk_bat_v_convert, bk_bat_v_raw);
@@ -1155,9 +1172,10 @@ static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p)
 	struct ab8500_gpadc *gpadc;
 
 	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
-	die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP);
+	die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP,
+		avg_sample, trig_edge, trig_timer, conv_type);
 	die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
-			die_temp_raw);
+		die_temp_raw);
 
 	return seq_printf(s, "%d,0x%X\n",
 			die_temp_convert, die_temp_raw);
@@ -1176,6 +1194,208 @@ static const struct file_operations ab8500_gpadc_die_temp_fops = {
 	.owner = THIS_MODULE,
 };
 
+static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p)
+{
+	return seq_printf(s, "%d\n", avg_sample);
+}
+
+static int ab8500_gpadc_avg_sample_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_gpadc_avg_sample_print,
+			inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
+	const char __user *user_buf,
+	size_t count, loff_t *ppos)
+{
+	struct device *dev = ((struct seq_file *)(file->private_data))->private;
+	char buf[32];
+	int buf_size;
+	unsigned long user_avg_sample;
+	int err;
+
+	/* Get userspace string and assure termination */
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	err = strict_strtoul(buf, 0, &user_avg_sample);
+	if (err)
+		return -EINVAL;
+	if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4)
+			|| (user_avg_sample == SAMPLE_8)
+			|| (user_avg_sample == SAMPLE_16)) {
+		avg_sample = (u8) user_avg_sample;
+	} else {
+		dev_err(dev, "debugfs error input: "
+			"should be egal to 1, 4, 8 or 16\n");
+		return -EINVAL;
+	}
+	return buf_size;
+}
+
+static const struct file_operations ab8500_gpadc_avg_sample_fops = {
+	.open = ab8500_gpadc_avg_sample_open,
+	.read = seq_read,
+	.write = ab8500_gpadc_avg_sample_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_trig_edge_print(struct seq_file *s, void *p)
+{
+	return seq_printf(s, "%d\n", trig_edge);
+}
+
+static int ab8500_gpadc_trig_edge_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_gpadc_trig_edge_print,
+			inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
+	const char __user *user_buf,
+	size_t count, loff_t *ppos)
+{
+	struct device *dev = ((struct seq_file *)(file->private_data))->private;
+	char buf[32];
+	int buf_size;
+	unsigned long user_trig_edge;
+	int err;
+
+	/* Get userspace string and assure termination */
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	err = strict_strtoul(buf, 0, &user_trig_edge);
+	if (err)
+		return -EINVAL;
+	if ((user_trig_edge == RISING_EDGE)
+			|| (user_trig_edge == FALLING_EDGE)) {
+		trig_edge = (u8) user_trig_edge;
+	} else {
+		dev_err(dev, "Wrong input:\n"
+			"Enter 0. Rising edge\n"
+			"Enter 1. Falling edge\n");
+		return -EINVAL;
+	}
+	return buf_size;
+}
+
+static const struct file_operations ab8500_gpadc_trig_edge_fops = {
+	.open = ab8500_gpadc_trig_edge_open,
+	.read = seq_read,
+	.write = ab8500_gpadc_trig_edge_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_trig_timer_print(struct seq_file *s, void *p)
+{
+	return seq_printf(s, "%d\n", trig_timer);
+}
+
+static int ab8500_gpadc_trig_timer_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_gpadc_trig_timer_print,
+			inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
+	const char __user *user_buf,
+	size_t count, loff_t *ppos)
+{
+	struct device *dev = ((struct seq_file *)(file->private_data))->private;
+	char buf[32];
+	int buf_size;
+	unsigned long user_trig_timer;
+	int err;
+
+	/* Get userspace string and assure termination */
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	err = strict_strtoul(buf, 0, &user_trig_timer);
+	if (err)
+		return -EINVAL;
+	if ((user_trig_timer >= 0) && (user_trig_timer <= 255)) {
+		trig_timer = (u8) user_trig_timer;
+	} else {
+		dev_err(dev, "debugfs error input: "
+			"should be beetween 0 to 255\n");
+		return -EINVAL;
+	}
+	return buf_size;
+}
+
+static const struct file_operations ab8500_gpadc_trig_timer_fops = {
+	.open = ab8500_gpadc_trig_timer_open,
+	.read = seq_read,
+	.write = ab8500_gpadc_trig_timer_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8500_gpadc_conv_type_print(struct seq_file *s, void *p)
+{
+	return seq_printf(s, "%d\n", conv_type);
+}
+
+static int ab8500_gpadc_conv_type_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_gpadc_conv_type_print,
+			inode->i_private);
+}
+
+static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
+	const char __user *user_buf,
+	size_t count, loff_t *ppos)
+{
+	struct device *dev = ((struct seq_file *)(file->private_data))->private;
+	char buf[32];
+	int buf_size;
+	unsigned long user_conv_type;
+	int err;
+
+	/* Get userspace string and assure termination */
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = 0;
+
+	err = strict_strtoul(buf, 0, &user_conv_type);
+	if (err)
+		return -EINVAL;
+	if ((user_conv_type == ADC_SW)
+			|| (user_conv_type == ADC_HW)) {
+		conv_type = (u8) user_conv_type;
+	} else {
+		dev_err(dev, "Wrong input:\n"
+			"Enter 0. ADC SW conversion\n"
+			"Enter 1. ADC HW conversion\n");
+		return -EINVAL;
+	}
+	return buf_size;
+}
+
+static const struct file_operations ab8500_gpadc_conv_type_fops = {
+	.open = ab8500_gpadc_conv_type_open,
+	.read = seq_read,
+	.write = ab8500_gpadc_conv_type_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 /*
  * return length of an ASCII numerical value, 0 is string is not a
  * numerical value.
@@ -1721,6 +1941,26 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	if (!file)
 		goto err;
 
+	file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUGO),
+		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_avg_sample_fops);
+	if (!file)
+		goto err;
+
+	file = debugfs_create_file("trig_edge", (S_IRUGO | S_IWUGO),
+		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_edge_fops);
+	if (!file)
+		goto err;
+
+	file = debugfs_create_file("trig_timer", (S_IRUGO | S_IWUGO),
+		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_timer_fops);
+	if (!file)
+		goto err;
+
+	file = debugfs_create_file("conv_type", (S_IRUGO | S_IWUGO),
+		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_conv_type_fops);
+	if (!file)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 1b48ac1..5942f2f 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -55,13 +55,18 @@
 #define EN_VTVOUT			0x02
 #define EN_GPADC			0x01
 #define DIS_GPADC			0x00
-#define SW_AVG_16			0x60
+#define AVG_1				0x00
+#define AVG_4				0x20
+#define AVG_8				0x40
+#define AVG_16				0x60
 #define ADC_SW_CONV			0x04
 #define EN_ICHAR			0x80
 #define BTEMP_PULL_UP			0x08
 #define EN_BUF				0x40
 #define DIS_ZERO			0x00
 #define GPADC_BUSY			0x01
+#define EN_FALLING			0x10
+#define EN_TRIG_EDGE			0x02
 
 /* GPADC constants from AB8500 spec, UM0836 */
 #define ADC_RESOLUTION			1024
@@ -116,7 +121,10 @@ struct adc_cal_data {
  *				the completion of gpadc conversion
  * @ab8500_gpadc_lock:		structure of type mutex
  * @regu:			pointer to the struct regulator
- * @irq:			interrupt number that is used by gpadc
+ * @irq_sw:			interrupt number that is used by gpadc for Sw
+ *				conversion
+ * @irq_hw:			interrupt number that is used by gpadc for Hw
+ *				conversion
  * @cal_data			array of ADC calibration data structs
  */
 struct ab8500_gpadc {
@@ -126,7 +134,8 @@ struct ab8500_gpadc {
 	struct completion ab8500_gpadc_complete;
 	struct mutex ab8500_gpadc_lock;
 	struct regulator *regu;
-	int irq;
+	int irq_sw;
+	int irq_hw;
 	struct adc_cal_data cal_data[NBR_CAL_INPUTS];
 };
 
@@ -247,30 +256,35 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
 EXPORT_SYMBOL(ab8500_gpadc_ad_to_voltage);
 
 /**
- * ab8500_gpadc_convert() - gpadc conversion
+ * ab8500_gpadc_sw_hw_convert() - gpadc conversion
  * @channel:	analog channel to be converted to digital data
+ * @avg_sample:  number of ADC sample to average
+ * @trig_egde:  selected ADC trig edge
+ * @trig_timer: selected ADC trigger delay timer
+ * @conv_type: selected conversion type (HW or SW conversion)
  *
  * This function converts the selected analog i/p to digital
  * data.
  */
-int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
+int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
 {
 	int ad_value;
 	int voltage;
 
-	ad_value = ab8500_gpadc_read_raw(gpadc, channel);
-
-	/* On failure retry a second time */
+	ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
+			trig_edge, trig_timer, conv_type);
+/* On failure retry a second time */
 	if (ad_value < 0)
-		ad_value = ab8500_gpadc_read_raw(gpadc, channel);
-
-	if (ad_value < 0) {
-		dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n", channel);
+		ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample,
+			trig_edge, trig_timer, conv_type);
+if (ad_value < 0) {
+		dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n",
+				channel);
 		return ad_value;
 	}
 
 	voltage = ab8500_gpadc_ad_to_voltage(gpadc, channel, ad_value);
-
 	if (voltage < 0)
 		dev_err(gpadc->dev, "GPADC to voltage conversion failed ch:"
 			" %d AD: 0x%x\n", channel, ad_value);
@@ -282,11 +296,16 @@ EXPORT_SYMBOL(ab8500_gpadc_convert);
 /**
  * ab8500_gpadc_read_raw() - gpadc read
  * @channel:	analog channel to be read
+ * @avg_sample:  number of ADC sample to average
+ * @trig_edge:  selected trig edge
+ * @trig_timer: selected ADC trigger delay timer
+ * @conv_type: selected conversion type (HW or SW conversion)
  *
- * This function obtains the raw ADC value, this then needs
- * to be converted by calling ab8500_gpadc_ad_to_voltage()
+ * This function obtains the raw ADC value for an hardware conversion,
+ * this then needs to be converted by calling ab8500_gpadc_ad_to_voltage()
  */
-int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
+int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
 {
 	int ret;
 	int looplimit = 0;
@@ -296,7 +315,6 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 		return -ENODEV;
 
 	mutex_lock(&gpadc->ab8500_gpadc_lock);
-
 	/* Enable VTVout LDO this is required for GPADC */
 	pm_runtime_get_sync(gpadc->dev);
 
@@ -324,9 +342,29 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 		goto out;
 	}
 
-	/* Select the channel source and set average samples to 16 */
-	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
-		AB8500_GPADC_CTRL2_REG, (channel | SW_AVG_16));
+	/* Select the channel source and set average samples */
+	switch (avg_sample) {
+	case SAMPLE_1:
+		val = channel | AVG_1;
+		break;
+	case SAMPLE_4:
+		val = channel | AVG_4;
+		break;
+	case SAMPLE_8:
+		val = channel | AVG_8;
+		break;
+	default:
+		val = channel | AVG_16;
+		break;
+
+	}
+
+	if (conv_type == ADC_HW)
+		ret = abx500_set_register_interruptible(gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val);
+	else
+		ret = abx500_set_register_interruptible(gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val);
 	if (ret < 0) {
 		dev_err(gpadc->dev,
 			"gpadc_conversion: set avg samples failed\n");
@@ -338,22 +376,43 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 	 * charging current sense if it needed, ABB 3.0 needs some special
 	 * treatment too.
 	 */
+	if ((conv_type == ADC_HW) && (trig_edge)) {
+		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+			EN_FALLING, EN_FALLING);
+
+	}
 	switch (channel) {
 	case MAIN_CHARGER_C:
 	case USB_CHARGER_C:
-		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-			EN_BUF | EN_ICHAR,
-			EN_BUF | EN_ICHAR);
-		break;
-	case BTEMP_BALL:
-		if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
-			/* Turn on btemp pull-up on ABB 3.0 */
+		if (conv_type == ADC_HW)
 			ret = abx500_mask_and_set_register_interruptible(
 				gpadc->dev,
 				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF | BTEMP_PULL_UP,
-				EN_BUF | BTEMP_PULL_UP);
+				EN_BUF | EN_ICHAR | EN_TRIG_EDGE,
+				EN_BUF | EN_ICHAR | EN_TRIG_EDGE);
+		else
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF | EN_ICHAR,
+				EN_BUF | EN_ICHAR);
+		break;
+	case BTEMP_BALL:
+		if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
+			if (conv_type == ADC_HW)
+				/* Turn on btemp pull-up on ABB 3.0 */
+				ret = abx500_mask_and_set_register_interruptible
+					(gpadc->dev,
+					AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+					EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE,
+					EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE);
+			else
+				ret = abx500_mask_and_set_register_interruptible
+					(gpadc->dev,
+					AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+					EN_BUF | BTEMP_PULL_UP,
+					EN_BUF | BTEMP_PULL_UP);
 
 		 /*
 		  * Delay might be needed for ABB8500 cut 3.0, if not, remove
@@ -364,8 +423,17 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 		}
 		/* Intentional fallthrough */
 	default:
-		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
+		if (conv_type == ADC_HW)
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF | EN_TRIG_EDGE,
+				EN_BUF | EN_TRIG_EDGE);
+		else
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC,
+				AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
 		break;
 	}
 	if (ret < 0) {
@@ -374,36 +442,83 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 		goto out;
 	}
 
-	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
-		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
-	if (ret < 0) {
-		dev_err(gpadc->dev,
-			"gpadc_conversion: start s/w conversion failed\n");
-		goto out;
+	/* Set trigger delay timer */
+	if (conv_type == ADC_HW) {
+		ret = abx500_set_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: trig timer failed\n");
+			goto out;
+		}
+	}
+
+	/* Start SW conversion */
+	if (conv_type == ADC_SW) {
+		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+			ADC_SW_CONV, ADC_SW_CONV);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: start s/w conv failed\n");
+			goto out;
+		}
 	}
+
 	/* wait for completion of conversion */
-	if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
-					 msecs_to_jiffies(CONVERSION_TIME))) {
-		dev_err(gpadc->dev,
-			"timeout: didn't receive GPADC conversion interrupt\n");
-		ret = -EINVAL;
-		goto out;
+	if (conv_type == ADC_HW) {
+		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
+			2*HZ)) {
+				dev_err(gpadc->dev,
+					"timeout didn't receive"
+					" hw GPADC conv interrupt\n");
+				ret = -EINVAL;
+				goto out;
+		}
+	} else {
+		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
+			msecs_to_jiffies(CONVERSION_TIME))) {
+				dev_err(gpadc->dev,
+					"timeout didn't receive"
+					" sw GPADC conv interrupt\n");
+				ret = -EINVAL;
+				goto out;
+		}
 	}
 
 	/* Read the converted RAW data */
-	ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
-		AB8500_GPADC_MANDATAL_REG, &low_data);
-	if (ret < 0) {
-		dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
-		goto out;
-	}
+	if (conv_type == ADC_HW) {
+		ret = abx500_get_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_AUTODATAL_REG, &low_data);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: read hw low data failed\n");
+			goto out;
+		}
 
-	ret = abx500_get_register_interruptible(gpadc->dev, AB8500_GPADC,
-		AB8500_GPADC_MANDATAH_REG, &high_data);
-	if (ret < 0) {
-		dev_err(gpadc->dev,
-			"gpadc_conversion: read high data failed\n");
-		goto out;
+		ret = abx500_get_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_AUTODATAH_REG, &high_data);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: read hw high data failed\n");
+			goto out;
+		}
+	} else {
+		ret = abx500_get_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_MANDATAL_REG, &low_data);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: read sw low data failed\n");
+			goto out;
+		}
+
+		ret = abx500_get_register_interruptible(gpadc->dev,
+			AB8500_GPADC, AB8500_GPADC_MANDATAH_REG, &high_data);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"gpadc_conversion: read sw high data failed\n");
+			goto out;
+		}
 	}
 
 	/* Disable GPADC */
@@ -414,6 +529,7 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel)
 		goto out;
 	}
 
+	/* Disable VTVout LDO this is required for GPADC */
 	pm_runtime_mark_last_busy(gpadc->dev);
 	pm_runtime_put_autosuspend(gpadc->dev);
 
@@ -430,9 +546,7 @@ out:
 	 */
 	(void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
 		AB8500_GPADC_CTRL1_REG, DIS_GPADC);
-
 	pm_runtime_put(gpadc->dev);
-
 	mutex_unlock(&gpadc->ab8500_gpadc_lock);
 	dev_err(gpadc->dev,
 		"gpadc_conversion: Failed to AD convert channel %d\n", channel);
@@ -441,16 +555,16 @@ out:
 EXPORT_SYMBOL(ab8500_gpadc_read_raw);
 
 /**
- * ab8500_bm_gpswadcconvend_handler() - isr for s/w gpadc conversion completion
+ * ab8500_bm_gpadcconvend_handler() - isr for gpadc conversion completion
  * @irq:	irq number
  * @data:	pointer to the data passed during request irq
  *
- * This is a interrupt service routine for s/w gpadc conversion completion.
+ * This is a interrupt service routine for gpadc conversion completion.
  * Notifies the gpadc completion is completed and the converted raw value
  * can be read from the registers.
  * Returns IRQ status(IRQ_HANDLED)
  */
-static irqreturn_t ab8500_bm_gpswadcconvend_handler(int irq, void *_gpadc)
+static irqreturn_t ab8500_bm_gpadcconvend_handler(int irq, void *_gpadc)
 {
 	struct ab8500_gpadc *gpadc = _gpadc;
 
@@ -651,11 +765,19 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
-	if (gpadc->irq < 0) {
-		dev_err(&pdev->dev, "failed to get platform irq-%d\n",
-			gpadc->irq);
-		ret = gpadc->irq;
+	gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END");
+	if (gpadc->irq_sw < 0) {
+		dev_err(gpadc->dev, "failed to get platform irq-%d\n",
+			gpadc->irq_sw);
+		ret = gpadc->irq_sw;
+		goto fail;
+	}
+
+	gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
+	if (gpadc->irq_hw < 0) {
+		dev_err(gpadc->dev, "failed to get platform irq-%d\n",
+			gpadc->irq_hw);
+		ret = gpadc->irq_hw;
 		goto fail;
 	}
 
@@ -666,14 +788,21 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	/* Initialize completion used to notify completion of conversion */
 	init_completion(&gpadc->ab8500_gpadc_complete);
 
-	/* Register interrupt  - SwAdcComplete */
-	ret = request_threaded_irq(gpadc->irq, NULL,
-		ab8500_bm_gpswadcconvend_handler,
-		IRQF_ONESHOT | IRQF_NO_SUSPEND | IRQF_SHARED,
-				"ab8500-gpadc", gpadc);
+	/* Register interrupts */
+	ret = request_threaded_irq(gpadc->irq_sw, NULL,
+		ab8500_bm_gpadcconvend_handler,
+		IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-sw", gpadc);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
+			gpadc->irq_sw);
+		goto fail;
+	}
+	ret = request_threaded_irq(gpadc->irq_hw, NULL,
+		ab8500_bm_gpadcconvend_handler,
+		IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-hw", gpadc);
 	if (ret < 0) {
 		dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
-			gpadc->irq);
+			gpadc->irq_hw);
 		goto fail;
 	}
 
@@ -697,6 +826,9 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	list_add_tail(&gpadc->node, &ab8500_gpadc_list);
 	dev_dbg(gpadc->dev, "probe success\n");
 	return 0;
+fail_irq:
+	free_irq(gpadc->irq_sw, gpadc);
+	free_irq(gpadc->irq_hw, gpadc);
 fail:
 	kfree(gpadc);
 	gpadc = NULL;
@@ -710,7 +842,8 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 	/* remove this gpadc entry from the list */
 	list_del(&gpadc->node);
 	/* remove interrupt  - completion of Sw ADC conversion */
-	free_irq(gpadc->irq, gpadc);
+	free_irq(gpadc->irq_sw, gpadc);
+	free_irq(gpadc->irq_hw, gpadc);
 
 	pm_runtime_get_sync(gpadc->dev);
 	pm_runtime_disable(gpadc->dev);
@@ -760,6 +893,7 @@ subsys_initcall_sync(ab8500_gpadc_init);
 module_exit(ab8500_gpadc_exit);
 
 MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson");
+MODULE_AUTHOR("Arun R Murthy, Daniel Willerud, Johan Palsson,"
+		"M'boumba Cedric Madianga");
 MODULE_ALIAS("platform:ab8500_gpadc");
 MODULE_DESCRIPTION("AB8500 GPADC driver");
diff --git a/include/linux/mfd/abx500/ab8500-gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h
index 2529667..7694e7a 100644
--- a/include/linux/mfd/abx500/ab8500-gpadc.h
+++ b/include/linux/mfd/abx500/ab8500-gpadc.h
@@ -4,12 +4,14 @@
  *
  * Author: Arun R Murthy <arun.murthy@stericsson.com>
  * Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ * Author: M'boumba Cedric Madianga <cedric.madianga@stericsson.com>
  */
 
 #ifndef	_AB8500_GPADC_H
 #define _AB8500_GPADC_H
 
-/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2) */
+/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2
+ * and ADCHwSel[4:0] in GPADCCtrl3 ) */
 #define BAT_CTRL	0x01
 #define BTEMP_BALL	0x02
 #define MAIN_CHARGER_V	0x03
@@ -24,12 +26,32 @@
 #define BK_BAT_V	0x0C
 #define DIE_TEMP	0x0D
 
+#define SAMPLE_1        1
+#define SAMPLE_4        4
+#define SAMPLE_8        8
+#define SAMPLE_16       16
+#define RISING_EDGE     0
+#define FALLING_EDGE    1
+
+/* Arbitrary ADC conversion type constants */
+#define ADC_SW				0
+#define ADC_HW				1
+
+
 struct ab8500_gpadc;
 
 struct ab8500_gpadc *ab8500_gpadc_get(char *name);
-int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel);
-int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel);
+int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
+static inline int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
+{
+	return ab8500_gpadc_sw_hw_convert(gpadc, channel,
+			SAMPLE_16, 0, 0, ADC_SW);
+}
+
+int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
 int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
-    u8 channel, int ad_value);
+		u8 channel, int ad_value);
 
 #endif /* _AB8500_GPADC_H */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 05/35] mfd: ab8500-core: APE Interrupts are not cleared
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (3 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 04/35] mfd: ab8500-gpadc: Add gpadc hw conversion Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification Lee Jones
                   ` (29 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marcus Cooper <marcus.xm.cooper@stericsson.com>

There are missing register descriptions from the AB8505 user manual
and these need to be masked so that the APEINT line can toggle.
This patch also affects the behaviour of AB9540.

Signed-off-by: Marcus Cooper <marcus.xm.cooper@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Maxime COQUELIN <maxime.coquelin@stericsson.com>
Reviewed-by: Alexandre TORGUE <alexandre.torgue@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-core.c         |    5 +++--
 include/linux/mfd/abx500/ab8500.h |   38 +++++++++++++++++++++++++++----------
 2 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 05a7af4..7c20728 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -94,6 +94,7 @@
 #define AB8500_IT_MASK22_REG		0x55
 #define AB8500_IT_MASK23_REG		0x56
 #define AB8500_IT_MASK24_REG		0x57
+#define AB8500_IT_MASK25_REG		0x58
 
 /*
  * latch hierarchy registers
@@ -129,9 +130,9 @@ static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
 };
 
-/* AB9540 support */
+/* AB9540 / AB8505 support */
 static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
-	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24,
+	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
 };
 
 static const char ab8500_version_str[][7] = {
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index fa7173d..f24df87 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -165,12 +165,12 @@ enum ab8500_version {
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R4R		95
 /* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
-#define AB8500_INT_ID_WAKEUP_F		96
-#define AB8500_INT_ID_DET_R1F		98
-#define AB8500_INT_ID_DET_R2F		99
-#define AB8500_INT_ID_DET_R3F		100
-#define AB8500_INT_ID_DET_R4F		101
-#define AB8500_INT_CHAUTORESTARTAFTSEC  102
+#define AB8500_INT_ID_WAKEUP_F		96 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R1F		98 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R2F		99 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R3F		100 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R4F		101 /* not 8505/9540 */
+#define AB8500_INT_CHAUTORESTARTAFTSEC	102 /* not 8505/9540 */
 #define AB8500_INT_CHSTOPBYSEC		103
 /* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
 #define AB8500_INT_USB_CH_TH_PROT_F	104
@@ -181,7 +181,7 @@ enum ab8500_version {
 #define AB8500_INT_CHCURLIMHSCHIRP	110
 #define AB8500_INT_XTAL32K_KO		111
 
-/* Definitions for AB9540 */
+/* Definitions for AB9540 / AB8505 */
 /* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
 #define AB9540_INT_GPIO50R		113
 #define AB9540_INT_GPIO51R		114 /* not 8505 */
@@ -204,6 +204,24 @@ enum ab8500_version {
 #define AB8505_INT_KEYDEGLITCH		132
 #define AB8505_INT_MODPWRSTATUSF	134
 #define AB8505_INT_MODPWRSTATUSR	135
+/* ab8500_irq_regoffset[17] -> IT[Source|Latch|Mask]6 */
+#define AB8500_INT_HOOK_DET_NEG_F	138
+#define AB8500_INT_HOOK_DET_NEG_R	139
+#define AB8500_INT_HOOK_DET_POS_F	140
+#define AB8500_INT_HOOK_DET_POS_R	141
+#define AB8500_INT_PLUG_DET_COMP_F	142
+#define AB8500_INT_PLUG_DET_COMP_R	143
+/* ab8500_irq_regoffset[18] -> IT[Source|Latch|Mask]23 */
+#define AB8505_INT_COLL			144
+#define AB8505_INT_RESERR		145
+#define AB8505_INT_FRAERR		146
+#define AB8505_INT_COMERR		147
+#define AB8505_INT_SPDSET		148
+#define AB8505_INT_DSENT		149
+#define AB8505_INT_DREC			150
+#define AB8505_INT_ACC_INT		151
+/* ab8500_irq_regoffset[19] -> IT[Source|Latch|Mask]24 */
+#define AB8505_INT_NOPINT		152
 
 /*
  * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
@@ -213,13 +231,13 @@ enum ab8500_version {
  * which is larger.
  */
 #define AB8500_NR_IRQS			112
-#define AB8505_NR_IRQS			136
-#define AB9540_NR_IRQS			136
+#define AB8505_NR_IRQS			153
+#define AB9540_NR_IRQS			153
 /* This is set to the roof of any AB8500 chip variant IRQ counts */
 #define AB8500_MAX_NR_IRQS		AB9540_NR_IRQS
 
 #define AB8500_NUM_IRQ_REGS		14
-#define AB9540_NUM_IRQ_REGS		17
+#define AB9540_NUM_IRQ_REGS		20
 
 /**
  * struct ab8500 - ab8500 internal structure
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (4 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 05/35] mfd: ab8500-core: APE Interrupts are not cleared Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-19 22:04   ` Arnd Bergmann
  2013-02-15 12:56 ` [PATCH 07/35] mfd: ab8500-debug: Print banks in hex Lee Jones
                   ` (28 subsequent siblings)
  34 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marcus Cooper <marcus.xm.cooper@stericsson.com>

On newer variants of the ab a version and revision value can be
read. This modification merges these two values to create a
chip id.

Signed-off-by: Marcus Cooper <marcus.xm.cooper@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
 drivers/mfd/ab8500-core.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 7c20728..678afd0 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1095,9 +1095,15 @@ static ssize_t show_chip_id(struct device *dev,
 				struct device_attribute *attr, char *buf)
 {
 	struct ab8500 *ab8500;
+	int chip_id = -EINVAL;
 
 	ab8500 = dev_get_drvdata(dev);
-	return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
+	if(ab8500) {
+		chip_id = ab8500->chip_id;
+		if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
+			chip_id = (ab8500->version << 8) | chip_id;
+	}
+	return sprintf(buf, "%#x\n", chip_id);
 }
 
 /*
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 07/35] mfd: ab8500-debug: Print banks in hex
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (5 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 08/35] mfd: ab8500-debug: Function to save all ABB registers to mem Lee Jones
                   ` (27 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mattias Wallin <mattias.wallin@stericsson.com>

This patch changes bank prints to use hex value.

Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Daniel WILLERUD <daniel.willerud@stericsson.com>
Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 8078a93..18ff86b 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -524,19 +524,19 @@ static int ab8500_registers_print(struct device *dev, u32 bank,
 			}
 
 			if (s) {
-				err = seq_printf(s, "  [%u/0x%02X]: 0x%02X\n",
+				err = seq_printf(s, "  [0x%02X/0x%02X]: 0x%02X\n",
 					bank, reg, value);
 				if (err < 0) {
 					dev_err(dev,
-					"seq_printf overflow bank=%d reg=%d\n",
+					"seq_printf overflow bank=0x%02X reg=0x%02X\n",
 						bank, reg);
 					/* Error is not returned here since
 					 * the output is wanted in any case */
 					return 0;
 				}
 			} else {
-				printk(KERN_INFO" [%u/0x%02X]: 0x%02X\n", bank,
-					reg, value);
+				printk(KERN_INFO" [0x%02X/0x%02X]: 0x%02X\n",
+					bank, reg, value);
 			}
 		}
 	}
@@ -550,7 +550,7 @@ static int ab8500_print_bank_registers(struct seq_file *s, void *p)
 
 	seq_printf(s, AB8500_NAME_STRING " register values:\n");
 
-	seq_printf(s, " bank %u:\n", bank);
+	seq_printf(s, " bank 0x%02X:\n", bank);
 
 	ab8500_registers_print(dev, bank, s);
 	return 0;
@@ -578,9 +578,9 @@ static int ab8500_print_all_banks(struct seq_file *s, void *p)
 	seq_printf(s, AB8500_NAME_STRING " register values:\n");
 
 	for (i = 1; i < AB8500_NUM_BANKS; i++) {
-		err = seq_printf(s, " bank %u:\n", i);
+		err = seq_printf(s, " bank 0x%02X:\n", i);
 		if (err < 0)
-			dev_err(dev, "seq_printf overflow, bank=%d\n", i);
+			dev_err(dev, "seq_printf overflow, bank=0x%02X\n", i);
 
 		ab8500_registers_print(dev, i, s);
 	}
@@ -595,7 +595,7 @@ void ab8500_dump_all_banks(struct device *dev)
 	printk(KERN_INFO"ab8500 register values:\n");
 
 	for (i = 1; i < AB8500_NUM_BANKS; i++) {
-		printk(KERN_INFO" bank %u:\n", i);
+		printk(KERN_INFO" bank 0x%02X:\n", i);
 		ab8500_registers_print(dev, i, NULL);
 	}
 }
@@ -629,7 +629,7 @@ static const struct file_operations ab8500_all_banks_fops = {
 
 static int ab8500_bank_print(struct seq_file *s, void *p)
 {
-	return seq_printf(s, "%d\n", debug_bank);
+	return seq_printf(s, "0x%02X\n", debug_bank);
 }
 
 static int ab8500_bank_open(struct inode *inode, struct file *file)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 08/35] mfd: ab8500-debug: Function to save all ABB registers to mem
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (6 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 07/35] mfd: ab8500-debug: Print banks in hex Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 09/35] mfd: ab8500-core: Add ADC support for ab8540 Lee Jones
                   ` (26 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Dump function that stores all readable ABB registers to a memory
areas where they can be accessed from dump file.

Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   50 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 18ff86b..250b77b 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -600,6 +600,56 @@ void ab8500_dump_all_banks(struct device *dev)
 	}
 }
 
+/* Space for 500 registers. */
+#define DUMP_MAX_REGS 700
+struct ab8500_register_dump
+{
+	u8 bank;
+	u8 reg;
+	u8 value;
+	int ret;
+} ab8500_complete_register_dump[DUMP_MAX_REGS];
+
+extern int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+
+/* This shall only be called upon kernel panic! */
+void ab8500_dump_all_banks_to_mem(void)
+{
+	int i, r = 0;
+	u8 bank;
+
+	pr_info("Saving all ABB registers at \"ab8500_complete_register_dump\" "
+		"for crash analyze.\n");
+
+	for (bank = 1; bank < AB8500_NUM_BANKS; bank++) {
+		for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
+			u8 reg;
+
+			for (reg = debug_ranges[bank].range[i].first;
+			     reg <= debug_ranges[bank].range[i].last;
+			     reg++) {
+				u8 value;
+				int err;
+
+				err = prcmu_abb_read(bank, reg, &value, 1);
+
+				ab8500_complete_register_dump[r].ret = err;
+				ab8500_complete_register_dump[r].bank = bank;
+				ab8500_complete_register_dump[r].reg = reg;
+				ab8500_complete_register_dump[r].value = value;
+
+				r++;
+
+				if (r >= DUMP_MAX_REGS) {
+					pr_err("%s: too many register to dump!\n",
+						__func__);
+					return;
+				}
+			}
+		}
+	}
+}
+
 static int ab8500_all_banks_open(struct inode *inode, struct file *file)
 {
 	struct seq_file *s;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 09/35] mfd: ab8500-core: Add ADC support for ab8540
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (7 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 08/35] mfd: ab8500-debug: Function to save all ABB registers to mem Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures Lee Jones
                   ` (25 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-core.c  |   74 +++++++++++++++++++++++++++++++++++---------
 drivers/mfd/ab8500-gpadc.c |   67 ++++++++++++++++++++++-----------------
 2 files changed, 98 insertions(+), 43 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 678afd0..ecf570f 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -604,6 +604,15 @@ static struct resource ab8500_gpadc_resources[] = {
 	},
 };
 
+static struct resource ab8540_gpadc_resources[] = {
+	{
+		.name	= "SW_CONV_END",
+		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
+		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
 static struct resource ab8500_rtc_resources[] = {
 	{
 		.name	= "60S",
@@ -954,12 +963,6 @@ static struct mfd_cell abx500_common_devs[] = {
 		.of_compatible = "stericsson,abx500-clk",
 	},
 	{
-		.name = "ab8500-gpadc",
-		.of_compatible = "stericsson,ab8500-gpadc",
-		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
-		.resources = ab8500_gpadc_resources,
-	},
-	{
 		.name = "ab8500-rtc",
 		.of_compatible = "stericsson,ab8500-rtc",
 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
@@ -1066,6 +1069,12 @@ static struct mfd_cell ab8500_devs[] = {
 		.name = "ab8500-codec",
 		.of_compatible = "stericsson,ab8500-codec",
 	},
+	{
+		.name = "ab8500-gpadc",
+		.of_compatible = "stericsson,ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
+		.resources = ab8500_gpadc_resources,
+	},
 };
 
 static struct mfd_cell ab9540_devs[] = {
@@ -1080,10 +1089,44 @@ static struct mfd_cell ab9540_devs[] = {
 	{
 		.name = "ab9540-codec",
 	},
+	{
+		.name = "ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
+		.resources = ab8500_gpadc_resources,
+	},
+	{
+		.name = "ab-iddet",
+		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
+		.resources = ab8505_iddet_resources,
+	},
 };
 
-/* Device list common to ab9540 and ab8505 */
-static struct mfd_cell ab9540_ab8505_devs[] = {
+/* Device list for ab8505  */
+static struct mfd_cell ab8505_devs[] = {
+	{
+		.name = "ab-iddet",
+		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
+		.resources = ab8505_iddet_resources,
+	},
+};
+
+static struct mfd_cell ab8540_devs[] = {
+	{
+		.name = "ab8500-gpio",
+	},
+	{
+		.name = "ab8540-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+	{
+		.name = "ab8540-codec",
+	},
+	{
+		.name = "ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8540_gpadc_resources),
+		.resources = ab8540_gpadc_resources,
+	},
 	{
 		.name = "ab-iddet",
 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
@@ -1416,6 +1459,14 @@ static int ab8500_probe(struct platform_device *pdev)
 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
 				ARRAY_SIZE(ab9540_devs), NULL,
 				ab8500->irq_base, ab8500->domain);
+	else if (is_ab8540(ab8500))
+		ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
+			      ARRAY_SIZE(ab8540_devs), NULL,
+			      ab8500->irq_base, ab8500->domain);
+	else if (is_ab8505(ab8500))
+		ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
+			      ARRAY_SIZE(ab8505_devs), NULL,
+			      ab8500->irq_base, ab8500->domain);
 	else
 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
 				ARRAY_SIZE(ab8500_devs), NULL,
@@ -1423,13 +1474,6 @@ static int ab8500_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	if (is_ab9540(ab8500) || is_ab8505(ab8500))
-		ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
-				ARRAY_SIZE(ab9540_ab8505_devs), NULL,
-				ab8500->irq_base, ab8500->domain);
-	if (ret)
-		return ret;
-
 	if (!no_bm) {
 		/* Add battery management devices */
 		ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 5942f2f..6b18975 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -314,6 +314,12 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 	if (!gpadc)
 		return -ENODEV;
 
+	/* check if convertion is supported */
+	if ((gpadc->irq_sw < 0) && (conv_type == ADC_SW))
+		return -ENOTSUPP;
+	if ((gpadc->irq_hw < 0) && (conv_type == ADC_HW))
+		return -ENOTSUPP;
+
 	mutex_lock(&gpadc->ab8500_gpadc_lock);
 	/* Enable VTVout LDO this is required for GPADC */
 	pm_runtime_get_sync(gpadc->dev);
@@ -766,20 +772,12 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	}
 
 	gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END");
-	if (gpadc->irq_sw < 0) {
-		dev_err(gpadc->dev, "failed to get platform irq-%d\n",
-			gpadc->irq_sw);
-		ret = gpadc->irq_sw;
-		goto fail;
-	}
+	if (gpadc->irq_sw < 0)
+		dev_err(gpadc->dev, "failed to get platform sw_conv_end irq\n");
 
 	gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END");
-	if (gpadc->irq_hw < 0) {
-		dev_err(gpadc->dev, "failed to get platform irq-%d\n",
-			gpadc->irq_hw);
-		ret = gpadc->irq_hw;
-		goto fail;
-	}
+	if (gpadc->irq_hw < 0)
+		dev_err(gpadc->dev, "failed to get platform hw_conv_end irq\n");
 
 	gpadc->dev = &pdev->dev;
 	gpadc->parent = dev_get_drvdata(pdev->dev.parent);
@@ -789,21 +787,30 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	init_completion(&gpadc->ab8500_gpadc_complete);
 
 	/* Register interrupts */
-	ret = request_threaded_irq(gpadc->irq_sw, NULL,
-		ab8500_bm_gpadcconvend_handler,
-		IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-sw", gpadc);
-	if (ret < 0) {
-		dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
-			gpadc->irq_sw);
-		goto fail;
+	if (gpadc->irq_sw >= 0) {
+		ret = request_threaded_irq(gpadc->irq_sw, NULL,
+			ab8500_bm_gpadcconvend_handler,
+			IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-sw",
+			gpadc);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"Failed to register interrupt irq: %d\n",
+				gpadc->irq_sw);
+			goto fail;
+		}
 	}
-	ret = request_threaded_irq(gpadc->irq_hw, NULL,
-		ab8500_bm_gpadcconvend_handler,
-		IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-hw", gpadc);
-	if (ret < 0) {
-		dev_err(gpadc->dev, "Failed to register interrupt, irq: %d\n",
-			gpadc->irq_hw);
-		goto fail;
+
+	if (gpadc->irq_hw >= 0) {
+		ret = request_threaded_irq(gpadc->irq_hw, NULL,
+			ab8500_bm_gpadcconvend_handler,
+			IRQF_NO_SUSPEND | IRQF_SHARED, "ab8500-gpadc-hw",
+			gpadc);
+		if (ret < 0) {
+			dev_err(gpadc->dev,
+				"Failed to register interrupt irq: %d\n",
+				gpadc->irq_hw);
+			goto fail_irq;
+		}
 	}
 
 	/* VTVout LDO used to power up ab8500-GPADC */
@@ -825,7 +832,9 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
 	ab8500_gpadc_read_calibration_data(gpadc);
 	list_add_tail(&gpadc->node, &ab8500_gpadc_list);
 	dev_dbg(gpadc->dev, "probe success\n");
+
 	return 0;
+
 fail_irq:
 	free_irq(gpadc->irq_sw, gpadc);
 	free_irq(gpadc->irq_hw, gpadc);
@@ -842,8 +851,10 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
 	/* remove this gpadc entry from the list */
 	list_del(&gpadc->node);
 	/* remove interrupt  - completion of Sw ADC conversion */
-	free_irq(gpadc->irq_sw, gpadc);
-	free_irq(gpadc->irq_hw, gpadc);
+	if (gpadc->irq_sw >= 0)
+		free_irq(gpadc->irq_sw, gpadc);
+	if (gpadc->irq_hw >= 0)
+		free_irq(gpadc->irq_hw, gpadc);
 
 	pm_runtime_get_sync(gpadc->dev);
 	pm_runtime_disable(gpadc->dev);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (8 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 09/35] mfd: ab8500-core: Add ADC support for ab8540 Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-19 22:07   ` Arnd Bergmann
  2013-02-15 12:56 ` [PATCH 11/35] mfd: ab8500-core: Add Interrupt support for ab8540 Lee Jones
                   ` (24 subsequent siblings)
  34 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Here we're separating Battery Management devices into their own
structure, removing the common device structure & redistribute them
amongst the individual platform structs and completing the population
of them.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-core.c |  257 +++++++++++++++++++++++++++++++++------------
 1 file changed, 189 insertions(+), 68 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index ecf570f..8af002c 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -604,7 +604,7 @@ static struct resource ab8500_gpadc_resources[] = {
 	},
 };
 
-static struct resource ab8540_gpadc_resources[] = {
+static struct resource ab8505_gpadc_resources[] = {
 	{
 		.name	= "SW_CONV_END",
 		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
@@ -941,7 +941,50 @@ static struct resource ab8500_temp_resources[] = {
 	},
 };
 
-static struct mfd_cell abx500_common_devs[] = {
+static struct mfd_cell ab8500_bm_devs[] = {
+	{
+		.name = "ab8500-charger",
+		.of_compatible = "stericsson,ab8500-charger",
+		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
+		.resources = ab8500_charger_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
+	},
+	{
+		.name = "ab8500-btemp",
+		.of_compatible = "stericsson,ab8500-btemp",
+		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
+		.resources = ab8500_btemp_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
+	},
+	{
+		.name = "ab8500-fg",
+		.of_compatible = "stericsson,ab8500-fg",
+		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
+		.resources = ab8500_fg_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
+	},
+	{
+		.name = "ab8500-chargalg",
+		.of_compatible = "stericsson,ab8500-chargalg",
+		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
+		.resources = ab8500_chargalg_resources,
+#ifndef CONFIG_OF
+		.platform_data = &ab8500_bm_data,
+		.pdata_size = sizeof(ab8500_bm_data),
+#endif
+	},
+};
+
+static struct mfd_cell ab8500_devs[] = {
 #ifdef CONFIG_DEBUG_FS
 	{
 		.name = "ab8500-debug",
@@ -963,6 +1006,11 @@ static struct mfd_cell abx500_common_devs[] = {
 		.of_compatible = "stericsson,abx500-clk",
 	},
 	{
+		.name = "ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
+		.resources = ab8500_gpadc_resources,
+	},
+	{
 		.name = "ab8500-rtc",
 		.of_compatible = "stericsson,ab8500-rtc",
 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
@@ -975,6 +1023,7 @@ static struct mfd_cell abx500_common_devs[] = {
 		.resources = ab8500_av_acc_detect_resources,
 	},
 	{
+
 		.name = "ab8500-poweron-key",
 		.of_compatible = "stericsson,ab8500-poweron-key",
 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
@@ -1004,80 +1053,72 @@ static struct mfd_cell abx500_common_devs[] = {
 		.of_compatible = "stericsson,ab8500-denc",
 	},
 	{
+		.name = "ab8500-gpio",
+		.of_compatible = "stericsson,ab8500-gpio",
+	},
+	{
 		.name = "ab8500-temp",
 		.of_compatible = "stericsson,ab8500-temp",
 		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
 		.resources = ab8500_temp_resources,
 	},
+	{
+		.name = "ab8500-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+	{
+		.name = "ab8500-codec",
+	},
 };
 
-static struct mfd_cell ab8500_bm_devs[] = {
+static struct mfd_cell ab9540_devs[] = {
+#ifdef CONFIG_DEBUG_FS
 	{
-		.name = "ab8500-charger",
-		.of_compatible = "stericsson,ab8500-charger",
-		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
-		.resources = ab8500_charger_resources,
-#ifndef CONFIG_OF
-		.platform_data = &ab8500_bm_data,
-		.pdata_size = sizeof(ab8500_bm_data),
+		.name = "ab8500-debug",
+		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
+		.resources = ab8500_debug_resources,
+	},
 #endif
+	{
+		.name = "ab8500-sysctrl",
 	},
 	{
-		.name = "ab8500-btemp",
-		.of_compatible = "stericsson,ab8500-btemp",
-		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
-		.resources = ab8500_btemp_resources,
-#ifndef CONFIG_OF
-		.platform_data = &ab8500_bm_data,
-		.pdata_size = sizeof(ab8500_bm_data),
-#endif
+		.name = "ab8500-regulator",
 	},
 	{
-		.name = "ab8500-fg",
-		.of_compatible = "stericsson,ab8500-fg",
-		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
-		.resources = ab8500_fg_resources,
-#ifndef CONFIG_OF
-		.platform_data = &ab8500_bm_data,
-		.pdata_size = sizeof(ab8500_bm_data),
-#endif
+		.name = "ab8500-gpadc",
+		.of_compatible = "stericsson,ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
+		.resources = ab8500_gpadc_resources,
 	},
 	{
-		.name = "ab8500-chargalg",
-		.of_compatible = "stericsson,ab8500-chargalg",
-		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
-		.resources = ab8500_chargalg_resources,
-#ifndef CONFIG_OF
-		.platform_data = &ab8500_bm_data,
-		.pdata_size = sizeof(ab8500_bm_data),
-#endif
+		.name = "ab8500-rtc",
+		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+		.resources = ab8500_rtc_resources,
 	},
-};
-
-static struct mfd_cell ab8500_devs[] = {
 	{
-		.name = "ab8500-gpio",
-		.of_compatible = "stericsson,ab8500-gpio",
+		.name = "ab8500-acc-det",
+		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+		.resources = ab8500_av_acc_detect_resources,
 	},
 	{
-		.name = "ab8500-usb",
-		.of_compatible = "stericsson,ab8500-usb",
-		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
-		.resources = ab8500_usb_resources,
+		.name = "ab8500-poweron-key",
+		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+		.resources = ab8500_poweronkey_db_resources,
 	},
 	{
-		.name = "ab8500-codec",
-		.of_compatible = "stericsson,ab8500-codec",
+		.name = "ab8500-pwm",
+		.id = 1,
 	},
 	{
-		.name = "ab8500-gpadc",
-		.of_compatible = "stericsson,ab8500-gpadc",
-		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
-		.resources = ab8500_gpadc_resources,
+		.name = "ab8500-leds",
+	},
+	{
+		.name = "abx500-temp",
+		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
+		.resources = ab8500_temp_resources,
 	},
-};
-
-static struct mfd_cell ab9540_devs[] = {
 	{
 		.name = "ab8500-gpio",
 	},
@@ -1090,11 +1131,6 @@ static struct mfd_cell ab9540_devs[] = {
 		.name = "ab9540-codec",
 	},
 	{
-		.name = "ab8500-gpadc",
-		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
-		.resources = ab8500_gpadc_resources,
-	},
-	{
 		.name = "ab-iddet",
 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
 		.resources = ab8505_iddet_resources,
@@ -1103,6 +1139,57 @@ static struct mfd_cell ab9540_devs[] = {
 
 /* Device list for ab8505  */
 static struct mfd_cell ab8505_devs[] = {
+#ifdef CONFIG_DEBUG_FS
+	{
+		.name = "ab8500-debug",
+		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
+		.resources = ab8500_debug_resources,
+	},
+#endif
+	{
+		.name = "ab8500-sysctrl",
+	},
+	{
+		.name = "ab8500-regulator",
+	},
+	{
+		.name = "ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
+		.resources = ab8505_gpadc_resources,
+	},
+	{
+		.name = "ab8500-rtc",
+		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+		.resources = ab8500_rtc_resources,
+	},
+	{
+		.name = "ab8500-acc-det",
+		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+		.resources = ab8500_av_acc_detect_resources,
+	},
+	{
+		.name = "ab8500-poweron-key",
+		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+		.resources = ab8500_poweronkey_db_resources,
+	},
+	{
+		.name = "ab8500-pwm",
+		.id = 1,
+	},
+	{
+		.name = "ab8500-leds",
+	},
+	{
+		.name = "ab8500-gpio",
+	},
+	{
+		.name = "ab8500-usb",
+		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
+		.resources = ab8500_usb_resources,
+	},
+	{
+		.name = "ab8500-codec",
+	},
 	{
 		.name = "ab-iddet",
 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
@@ -1111,6 +1198,51 @@ static struct mfd_cell ab8505_devs[] = {
 };
 
 static struct mfd_cell ab8540_devs[] = {
+#ifdef CONFIG_DEBUG_FS
+	{
+		.name = "ab8500-debug",
+		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
+		.resources = ab8500_debug_resources,
+	},
+#endif
+	{
+		.name = "ab8500-sysctrl",
+	},
+	{
+		.name = "ab8500-regulator",
+	},
+	{
+		.name = "ab8500-gpadc",
+		.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
+		.resources = ab8505_gpadc_resources,
+	},
+	{
+		.name = "ab8500-rtc",
+		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+		.resources = ab8500_rtc_resources,
+	},
+	{
+		.name = "ab8500-acc-det",
+		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
+		.resources = ab8500_av_acc_detect_resources,
+	},
+	{
+		.name = "ab8500-poweron-key",
+		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
+		.resources = ab8500_poweronkey_db_resources,
+	},
+	{
+		.name = "ab8500-pwm",
+		.id = 1,
+	},
+	{
+		.name = "ab8500-leds",
+	},
+	{
+		.name = "abx500-temp",
+		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
+		.resources = ab8500_temp_resources,
+	},
 	{
 		.name = "ab8500-gpio",
 	},
@@ -1123,11 +1255,6 @@ static struct mfd_cell ab8540_devs[] = {
 		.name = "ab8540-codec",
 	},
 	{
-		.name = "ab8500-gpadc",
-		.num_resources = ARRAY_SIZE(ab8540_gpadc_resources),
-		.resources = ab8540_gpadc_resources,
-	},
-	{
 		.name = "ab-iddet",
 		.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
 		.resources = ab8505_iddet_resources,
@@ -1449,12 +1576,6 @@ static int ab8500_probe(struct platform_device *pdev)
 			return ret;
 	}
 
-	ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
-			ARRAY_SIZE(abx500_common_devs), NULL,
-			ab8500->irq_base, ab8500->domain);
-	if (ret)
-		return ret;
-
 	if (is_ab9540(ab8500))
 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
 				ARRAY_SIZE(ab9540_devs), NULL,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 11/35] mfd: ab8500-core: Add Interrupt support for ab8540
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (9 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 12/35] mfd: ab8500-debug: Better error handling on crash Lee Jones
                   ` (23 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

ITSource/ITLatch 7, 8, 9 and 10 don't exist on AB8540. This patch
replaces them with '-1' in the interrupt list, and handles the '-1'
in the code accordingly.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-core.c         |   50 ++++++++++--
 include/linux/mfd/abx500/ab8500.h |  153 +++++++++++++++++++++++++++----------
 2 files changed, 154 insertions(+), 49 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 8af002c..e82cf73 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -102,8 +102,10 @@
 #define AB8500_IT_LATCHHIER1_REG	0x60
 #define AB8500_IT_LATCHHIER2_REG	0x61
 #define AB8500_IT_LATCHHIER3_REG	0x62
+#define AB8540_IT_LATCHHIER4_REG	0x63
 
 #define AB8500_IT_LATCHHIER_NUM		3
+#define AB8540_IT_LATCHHIER_NUM		4
 
 #define AB8500_REV_REG			0x80
 #define AB8500_IC_NAME_REG		0x82
@@ -135,6 +137,12 @@ static const int ab9540_irq_regoffset[AB9540_NUM_IRQ_REGS] = {
 	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23
 };
 
+/* AB8540 support */
+static const int ab8540_irq_regoffset[AB8540_NUM_IRQ_REGS] = {
+	0, 1, 2, 3, 4, -1, -1, -1, -1, 11, 18, 19, 20, 21, 12, 13, 24, 5, 22, 23,
+	25, 26, 27, 28, 29, 30, 31,
+};
+
 static const char ab8500_version_str[][7] = {
 	[AB8500_VERSION_AB8500] = "AB8500",
 	[AB8500_VERSION_AB8505] = "AB8505",
@@ -352,6 +360,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
 			is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
+		if (ab8500->irq_reg_offset[i] < 0)
+			continue;
+
 		ab8500->oldmask[i] = new;
 
 		reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
@@ -390,6 +401,18 @@ static struct irq_chip ab8500_irq_chip = {
 	.irq_unmask		= ab8500_irq_unmask,
 };
 
+static void update_latch_offset(u8 *offset, int i)
+{
+	/* Fix inconsistent ITFromLatch25 bit mapping... */
+	if (unlikely(*offset == 17))
+			*offset = 24;
+	/* Fix inconsistent ab8540 bit mapping... */
+	if (unlikely(*offset == 16))
+			*offset = 25;
+	if ((i==3) && (*offset >= 24))
+			*offset += 2;
+}
+
 static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
 					int latch_offset, u8 latch_val)
 {
@@ -428,9 +451,7 @@ static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
 		latch_bit = __ffs(hier_val);
 		latch_offset = (hier_offset << 3) + latch_bit;
 
-		/* Fix inconsistent ITFromLatch25 bit mapping... */
-		if (unlikely(latch_offset == 17))
-			latch_offset = 24;
+		update_latch_offset(&latch_offset, hier_offset);
 
 		status = get_register_interruptible(ab8500,
 				AB8500_INTERRUPT,
@@ -458,7 +479,7 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
 	dev_vdbg(ab8500->dev, "interrupt\n");
 
 	/*  Hierarchical interrupt version */
-	for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
+	for (i = 0; i < (ab8500->it_latchhier_num); i++) {
 		int status;
 		u8 hier_val;
 
@@ -511,6 +532,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
 		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
+		if (regoffset < 0)
+			continue;
+
 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
 			AB8500_IT_LATCH1_REG + regoffset, &value);
 		if (status < 0 || value == 0)
@@ -561,7 +585,9 @@ static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np)
 {
 	int num_irqs;
 
-	if (is_ab9540(ab8500))
+	if (is_ab8540(ab8500))
+		num_irqs = AB8540_NR_IRQS;
+	else if (is_ab9540(ab8500))
 		num_irqs = AB9540_NR_IRQS;
 	else if (is_ab8505(ab8500))
 		num_irqs = AB8505_NR_IRQS;
@@ -1482,13 +1508,20 @@ static int ab8500_probe(struct platform_device *pdev)
 			ab8500->chip_id >> 4,
 			ab8500->chip_id & 0x0F);
 
-	/* Configure AB8500 or AB9540 IRQ */
-	if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
+	/* Configure AB8540 */
+	if (is_ab8540(ab8500)) {
+		ab8500->mask_size = AB8540_NUM_IRQ_REGS;
+		ab8500->irq_reg_offset = ab8540_irq_regoffset;
+		ab8500->it_latchhier_num = AB8540_IT_LATCHHIER_NUM;
+	}/* Configure AB8500 or AB9540 IRQ */
+	else if (is_ab9540(ab8500) || is_ab8505(ab8500)) {
 		ab8500->mask_size = AB9540_NUM_IRQ_REGS;
 		ab8500->irq_reg_offset = ab9540_irq_regoffset;
+		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
 	} else {
 		ab8500->mask_size = AB8500_NUM_IRQ_REGS;
 		ab8500->irq_reg_offset = ab8500_irq_regoffset;
+		ab8500->it_latchhier_num = AB8500_IT_LATCHHIER_NUM;
 	}
 	ab8500->mask = devm_kzalloc(&pdev->dev, ab8500->mask_size, GFP_KERNEL);
 	if (!ab8500->mask)
@@ -1541,6 +1574,9 @@ static int ab8500_probe(struct platform_device *pdev)
 				is_ab8500_1p1_or_earlier(ab8500))
 			continue;
 
+		if (ab8500->irq_reg_offset[i] < 0)
+			continue;
+
 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
 			AB8500_IT_LATCH1_REG + ab8500->irq_reg_offset[i],
 			&value);
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index f24df87..f432cef 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -65,11 +65,11 @@ enum ab8500_version {
  * Values used to index into array ab8500_irq_regoffset[] defined in
  * drivers/mdf/ab8500-core.c
  */
-/* Definitions for AB8500 and AB9540 */
+/* Definitions for AB8500, AB9540 and AB8540 */
 /* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
 #define AB8500_INT_MAIN_EXT_CH_NOT_OK	0 /* not 8505/9540 */
-#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540 */
-#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540 */
+#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540/8540 */
+#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540/8540 */
 #define AB8500_INT_TEMP_WARM		3
 #define AB8500_INT_PON_KEY2DB_F		4
 #define AB8500_INT_PON_KEY2DB_R		5
@@ -77,18 +77,19 @@ enum ab8500_version {
 #define AB8500_INT_PON_KEY1DB_R		7
 /* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
 #define AB8500_INT_BATT_OVV		8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505 */
-#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505 */
+#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505/8540 */
+#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505/8540 */
 #define AB8500_INT_VBUS_DET_F		14
 #define AB8500_INT_VBUS_DET_R		15
 /* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
 #define AB8500_INT_VBUS_CH_DROP_END	16
 #define AB8500_INT_RTC_60S		17
 #define AB8500_INT_RTC_ALARM		18
+#define AB8540_INT_BIF_INT		19
 #define AB8500_INT_BAT_CTRL_INDB	20
 #define AB8500_INT_CH_WD_EXP		21
 #define AB8500_INT_VBUS_OVV		22
-#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540 */
+#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540/8540 */
 /* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
 #define AB8500_INT_CCN_CONV_ACC		24
 #define AB8500_INT_INT_AUD		25
@@ -99,7 +100,7 @@ enum ab8500_version {
 #define AB8500_INT_BUP_CHG_NOT_OK	30
 #define AB8500_INT_BUP_CHG_OK		31
 /* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
-#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505 */
+#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505/8540 */
 #define AB8500_INT_ACC_DETECT_1DB_F	33
 #define AB8500_INT_ACC_DETECT_1DB_R	34
 #define AB8500_INT_ACC_DETECT_22DB_F	35
@@ -108,23 +109,23 @@ enum ab8500_version {
 #define AB8500_INT_ACC_DETECT_21DB_R	38
 #define AB8500_INT_GP_SW_ADC_CONV_END	39
 /* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
-#define AB8500_INT_GPIO6R		40 /* not 8505/9540 */
-#define AB8500_INT_GPIO7R		41 /* not 8505/9540 */
-#define AB8500_INT_GPIO8R		42 /* not 8505/9540 */
-#define AB8500_INT_GPIO9R		43 /* not 8505/9540 */
-#define AB8500_INT_GPIO10R		44
-#define AB8500_INT_GPIO11R		45
-#define AB8500_INT_GPIO12R		46 /* not 8505 */
-#define AB8500_INT_GPIO13R		47
+#define AB8500_INT_GPIO6R		40 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO7R		41 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO8R		42 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO9R		43 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO10R		44 /* not 8540 */
+#define AB8500_INT_GPIO11R		45 /* not 8540 */
+#define AB8500_INT_GPIO12R		46 /* not 8505/8540 */
+#define AB8500_INT_GPIO13R		47 /* not 8540 */
 /* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
-#define AB8500_INT_GPIO24R		48 /* not 8505 */
-#define AB8500_INT_GPIO25R		49 /* not 8505 */
-#define AB8500_INT_GPIO36R		50 /* not 8505/9540 */
-#define AB8500_INT_GPIO37R		51 /* not 8505/9540 */
-#define AB8500_INT_GPIO38R		52 /* not 8505/9540 */
-#define AB8500_INT_GPIO39R		53 /* not 8505/9540 */
-#define AB8500_INT_GPIO40R		54
-#define AB8500_INT_GPIO41R		55
+#define AB8500_INT_GPIO24R		48 /* not 8505/8540 */
+#define AB8500_INT_GPIO25R		49 /* not 8505/8540 */
+#define AB8500_INT_GPIO36R		50 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO37R		51 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO38R		52 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO39R		53 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO40R		54 /* not 8540 */
+#define AB8500_INT_GPIO41R		55 /* not 8540 */
 /* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
 #define AB8500_INT_GPIO6F		56 /* not 8505/9540 */
 #define AB8500_INT_GPIO7F		57 /* not 8505/9540 */
@@ -135,14 +136,14 @@ enum ab8500_version {
 #define AB8500_INT_GPIO12F		62 /* not 8505 */
 #define AB8500_INT_GPIO13F		63
 /* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
-#define AB8500_INT_GPIO24F		64 /* not 8505 */
-#define AB8500_INT_GPIO25F		65 /* not 8505 */
-#define AB8500_INT_GPIO36F		66 /* not 8505/9540 */
-#define AB8500_INT_GPIO37F		67 /* not 8505/9540 */
-#define AB8500_INT_GPIO38F		68 /* not 8505/9540 */
-#define AB8500_INT_GPIO39F		69 /* not 8505/9540 */
-#define AB8500_INT_GPIO40F		70
-#define AB8500_INT_GPIO41F		71
+#define AB8500_INT_GPIO24F		64 /* not 8505/8540 */
+#define AB8500_INT_GPIO25F		65 /* not 8505/8540 */
+#define AB8500_INT_GPIO36F		66 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO37F		67 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO38F		68 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO39F		69 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO40F		70 /* not 8540 */
+#define AB8500_INT_GPIO41F		71 /* not 8540 */
 /* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
 #define AB8500_INT_ADP_SOURCE_ERROR	72
 #define AB8500_INT_ADP_SINK_ERROR	73
@@ -183,19 +184,19 @@ enum ab8500_version {
 
 /* Definitions for AB9540 / AB8505 */
 /* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
-#define AB9540_INT_GPIO50R		113
-#define AB9540_INT_GPIO51R		114 /* not 8505 */
-#define AB9540_INT_GPIO52R		115
-#define AB9540_INT_GPIO53R		116
-#define AB9540_INT_GPIO54R		117 /* not 8505 */
+#define AB9540_INT_GPIO50R		113 /* not 8540 */
+#define AB9540_INT_GPIO51R		114 /* not 8505/8540 */
+#define AB9540_INT_GPIO52R		115 /* not 8540 */
+#define AB9540_INT_GPIO53R		116 /* not 8540 */
+#define AB9540_INT_GPIO54R		117 /* not 8505/8540 */
 #define AB9540_INT_IEXT_CH_RF_BFN_R	118
 #define AB9540_INT_IEXT_CH_RF_BFN_F	119
 /* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
-#define AB9540_INT_GPIO50F		121
-#define AB9540_INT_GPIO51F		122 /* not 8505 */
-#define AB9540_INT_GPIO52F		123
-#define AB9540_INT_GPIO53F		124
-#define AB9540_INT_GPIO54F		125 /* not 8505 */
+#define AB9540_INT_GPIO50F		121 /* not 8540 */
+#define AB9540_INT_GPIO51F		122 /* not 8505/8540 */
+#define AB9540_INT_GPIO52F		123 /* not 8540 */
+#define AB9540_INT_GPIO53F		124 /* not 8540 */
+#define AB9540_INT_GPIO54F		125 /* not 8505/8540 */
 /* ab8500_irq_regoffset[16] -> IT[Source|Latch|Mask]25 */
 #define AB8505_INT_KEYSTUCK		128
 #define AB8505_INT_IKR			129
@@ -223,6 +224,71 @@ enum ab8500_version {
 /* ab8500_irq_regoffset[19] -> IT[Source|Latch|Mask]24 */
 #define AB8505_INT_NOPINT		152
 
+#define AB8505_INT_NOPINT		152
+/* ab8540_irq_regoffset[20] -> IT[Source|Latch|Mask]26 */
+#define AB8540_INT_IDPLUGDETCOMPF	160
+#define AB8540_INT_IDPLUGDETCOMPR	161
+#define AB8540_INT_FMDETCOMPLOF		162
+#define AB8540_INT_FMDETCOMPLOR		163
+#define AB8540_INT_FMDETCOMPHIF		164
+#define AB8540_INT_FMDETCOMPHIR		165
+#define AB8540_INT_ID5VDETCOMPF		166
+#define AB8540_INT_ID5VDETCOMPR		167
+/* ab8540_irq_regoffset[21] -> IT[Source|Latch|Mask]27 */
+#define AB8540_INT_GPIO43F		168
+#define AB8540_INT_GPIO43R		169
+#define AB8540_INT_GPIO44F		170
+#define AB8540_INT_GPIO44R		171
+#define AB8540_INT_KEYPOSDETCOMPF	172
+#define AB8540_INT_KEYPOSDETCOMPR	173
+#define AB8540_INT_KEYNEGDETCOMPF	174
+#define AB8540_INT_KEYNEGDETCOMPR	175
+/* ab8540_irq_regoffset[22] -> IT[Source|Latch|Mask]28 */
+#define AB8540_INT_GPIO1VBATF		176
+#define AB8540_INT_GPIO1VBATR		177
+#define AB8540_INT_GPIO2VBATF		178
+#define AB8540_INT_GPIO2VBATR		179
+#define AB8540_INT_GPIO3VBATF		180
+#define AB8540_INT_GPIO3VBATR		181
+#define AB8540_INT_GPIO4VBATF		182
+#define AB8540_INT_GPIO4VBATR		183
+/* ab8540_irq_regoffset[23] -> IT[Source|Latch|Mask]29 */
+#define AB8540_INT_SYSCLKREQ2F		184
+#define AB8540_INT_SYSCLKREQ2R		185
+#define AB8540_INT_SYSCLKREQ3F		186
+#define AB8540_INT_SYSCLKREQ3R		187
+#define AB8540_INT_SYSCLKREQ4F		188
+#define AB8540_INT_SYSCLKREQ4R		189
+#define AB8540_INT_SYSCLKREQ5F		190
+#define AB8540_INT_SYSCLKREQ5R		191
+/* ab8540_irq_regoffset[24] -> IT[Source|Latch|Mask]30 */
+#define AB8540_INT_PWMOUT1F		192
+#define AB8540_INT_PWMOUT1R		193
+#define AB8540_INT_PWMCTRL0F		194
+#define AB8540_INT_PWMCTRL0R		195
+#define AB8540_INT_PWMCTRL1F		196
+#define AB8540_INT_PWMCTRL1R		197
+#define AB8540_INT_SYSCLKREQ6F		198
+#define AB8540_INT_SYSCLKREQ6R		199
+/* ab8540_irq_regoffset[25] -> IT[Source|Latch|Mask]31 */
+#define AB8540_INT_PWMEXTVIBRA1F	200
+#define AB8540_INT_PWMEXTVIBRA1R	201
+#define AB8540_INT_PWMEXTVIBRA2F	202
+#define AB8540_INT_PWMEXTVIBRA2R	203
+#define AB8540_INT_PWMOUT2F		204
+#define AB8540_INT_PWMOUT2R		205
+#define AB8540_INT_PWMOUT3F		206
+#define AB8540_INT_PWMOUT3R		207
+/* ab8540_irq_regoffset[26] -> IT[Source|Latch|Mask]32 */
+#define AB8540_INT_ADDATA2F		208
+#define AB8540_INT_ADDATA2R		209
+#define AB8540_INT_DADATA2F		210
+#define AB8540_INT_DADATA2R		211
+#define AB8540_INT_FSYNC2F		212
+#define AB8540_INT_FSYNC2R		213
+#define AB8540_INT_BITCLK2F		214
+#define AB8540_INT_BITCLK2R		215
+
 /*
  * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
  * entire platform. This is a "compile time" constant so this must be set to
@@ -233,11 +299,13 @@ enum ab8500_version {
 #define AB8500_NR_IRQS			112
 #define AB8505_NR_IRQS			153
 #define AB9540_NR_IRQS			153
+#define AB8540_NR_IRQS			216
 /* This is set to the roof of any AB8500 chip variant IRQ counts */
-#define AB8500_MAX_NR_IRQS		AB9540_NR_IRQS
+#define AB8500_MAX_NR_IRQS		AB8540_NR_IRQS
 
 #define AB8500_NUM_IRQ_REGS		14
 #define AB9540_NUM_IRQ_REGS		20
+#define AB8540_NUM_IRQ_REGS		27
 
 /**
  * struct ab8500 - ab8500 internal structure
@@ -282,6 +350,7 @@ struct ab8500 {
 	u8 *oldmask;
 	int mask_size;
 	const int *irq_reg_offset;
+	int it_latchhier_num;
 };
 
 struct regulator_reg_init;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 12/35] mfd: ab8500-debug: Better error handling on crash
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (10 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 11/35] mfd: ab8500-core: Add Interrupt support for ab8540 Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 13/35] mfd: ab8500-debug: Add wake-up info Lee Jones
                   ` (22 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jonas Aaberg <jonas.aberg@stericsson.com>

Stop trying to read i2c registers if one fail.

Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 250b77b..8b15fc2 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -607,7 +607,6 @@ struct ab8500_register_dump
 	u8 bank;
 	u8 reg;
 	u8 value;
-	int ret;
 } ab8500_complete_register_dump[DUMP_MAX_REGS];
 
 extern int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
@@ -617,6 +616,7 @@ void ab8500_dump_all_banks_to_mem(void)
 {
 	int i, r = 0;
 	u8 bank;
+	int err = 0;
 
 	pr_info("Saving all ABB registers at \"ab8500_complete_register_dump\" "
 		"for crash analyze.\n");
@@ -629,11 +629,12 @@ void ab8500_dump_all_banks_to_mem(void)
 			     reg <= debug_ranges[bank].range[i].last;
 			     reg++) {
 				u8 value;
-				int err;
 
 				err = prcmu_abb_read(bank, reg, &value, 1);
 
-				ab8500_complete_register_dump[r].ret = err;
+				if (err < 0)
+					goto out;
+
 				ab8500_complete_register_dump[r].bank = bank;
 				ab8500_complete_register_dump[r].reg = reg;
 				ab8500_complete_register_dump[r].value = value;
@@ -643,11 +644,17 @@ void ab8500_dump_all_banks_to_mem(void)
 				if (r >= DUMP_MAX_REGS) {
 					pr_err("%s: too many register to dump!\n",
 						__func__);
-					return;
+					err = -EINVAL;
+					goto out;
 				}
 			}
 		}
 	}
+out:
+	if (err >= 0)
+		pr_info("Saved all ABB registers.\n");
+	else
+		pr_info("Failed to save all ABB registers.\n");
 }
 
 static int ab8500_all_banks_open(struct inode *inode, struct file *file)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 13/35] mfd: ab8500-debug: Add wake-up info
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (11 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 12/35] mfd: ab8500-debug: Better error handling on crash Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 14/35] mfd: ab8500-sysctrl: Error check clean up Lee Jones
                   ` (21 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jonas Aaberg <jonas.aberg@stericsson.com>

Add information regarding what ab interrupt that caused
a wake-up from suspend in <debugfs>/ab8500/interrupts.
Also print the name of the interrupts, not just the numbers.

Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Per FORLIN <per.forlin@stericsson.com>
Tested-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 8b15fc2..51b0e97 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -80,6 +80,7 @@
 #include <linux/interrupt.h>
 #include <linux/kobject.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500-gpadc.h>
@@ -802,22 +803,46 @@ static ssize_t ab8500_val_write(struct file *file,
  * Interrupt status
  */
 static u32 num_interrupts[AB8500_MAX_NR_IRQS];
+static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
 static int num_interrupt_lines;
 
+bool __attribute__((weak)) suspend_test_wake_cause_interrupt_is_mine(u32 my_int)
+{
+	return false;
+}
+
 void ab8500_debug_register_interrupt(int line)
 {
-	if (line < num_interrupt_lines)
+	if (line < num_interrupt_lines) {
 		num_interrupts[line]++;
+		if (suspend_test_wake_cause_interrupt_is_mine(IRQ_DB8500_AB8500))
+			num_wake_interrupts[line]++;
+	}
 }
 
 static int ab8500_interrupts_print(struct seq_file *s, void *p)
 {
 	int line;
 
-	seq_printf(s, "irq:  number of\n");
+	seq_printf(s, "name: number:  number of: wake:\n");
+
+	for (line = 0; line < num_interrupt_lines; line++) {
+		struct irq_desc *desc = irq_to_desc(line + irq_first);
+		struct irqaction *action = desc->action;
 
-	for (line = 0; line < num_interrupt_lines; line++)
-		seq_printf(s, "%3i:  %6i\n", line, num_interrupts[line]);
+		seq_printf(s, "%3i:  %6i %4i", line,
+			   num_interrupts[line],
+			   num_wake_interrupts[line]);
+
+		if (desc && desc->name)
+			seq_printf(s, "-%-8s", desc->name);
+		if (action) {
+			seq_printf(s, "  %s", action->name);
+			while ((action = action->next) != NULL)
+				seq_printf(s, ", %s", action->name);
+		}
+		seq_putc(s, '\n');
+	}
 
 	return 0;
 }
@@ -1869,7 +1894,7 @@ static int ab8500_debug_probe(struct platform_device *plf)
 		dev_err(&plf->dev, "Last irq not found, err %d\n",
 				irq_last);
 		ret = irq_last;
-                goto out_freeevent_name;
+		goto out_freeevent_name;
 	}
 
 	ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 14/35] mfd: ab8500-sysctrl: Error check clean up
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (12 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 13/35] mfd: ab8500-debug: Add wake-up info Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 15/35] mfd: ab8500-debugfs: Add tests for ab8540 based platform initialisations Lee Jones
                   ` (20 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Marcus Danielsson <marcus.danielsson@stericsson.com>

Add error checks to see if sysctrl was probed as it should.
If the sysctrl_dev is not set the return value is -EINVAL.

Signed-off-by: Marcus Danielsson <marcus.danielsson@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
Tested-by: Per FORLIN <per.forlin@stericsson.com>
---
 drivers/mfd/ab8500-sysctrl.c |   38 ++++++++++++++++++++++----------------
 1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 108fd86..ab6bfd3 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -28,6 +28,11 @@ void ab8500_power_off(void)
 	struct power_supply *psy;
 	int ret;
 
+	if (sysctrl_dev == NULL) {
+		pr_err("%s: sysctrl not initialized\n", __func__);
+		return;
+	}
+
 	/*
 	 * If we have a charger connected and we're powering off,
 	 * reboot into charge-only mode.
@@ -85,7 +90,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
 	u8 bank;
 
 	if (sysctrl_dev == NULL)
-		return -EAGAIN;
+		return -EINVAL;
 
 	bank = (reg >> 8);
 	if (!valid_bank(bank))
@@ -101,7 +106,7 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
 	u8 bank;
 
 	if (sysctrl_dev == NULL)
-		return -EAGAIN;
+		return -EINVAL;
 
 	bank = (reg >> 8);
 	if (!valid_bank(bank))
@@ -116,31 +121,32 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
 {
 	struct ab8500_platform_data *plat;
 	struct ab8500_sysctrl_platform_data *pdata;
+	int ret, i, j;
 
-	sysctrl_dev = &pdev->dev;
 	plat = dev_get_platdata(pdev->dev.parent);
+
+	if (!(plat && plat->sysctrl))
+		return -EINVAL;
+
 	if (plat->pm_power_off)
 		pm_power_off = ab8500_power_off;
 
 	pdata = plat->sysctrl;
 
-	if (pdata) {
-		int ret, i, j;
 
-		for (i = AB8500_SYSCLKREQ1RFCLKBUF;
-		     i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
-			j = i - AB8500_SYSCLKREQ1RFCLKBUF;
-			ret = ab8500_sysctrl_write(i, 0xff,
-						   pdata->initial_req_buf_config[j]);
-			dev_dbg(&pdev->dev,
+	for (i = AB8500_SYSCLKREQ1RFCLKBUF;
+	     i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
+		j = i - AB8500_SYSCLKREQ1RFCLKBUF;
+		ret = ab8500_sysctrl_write(i, 0xff,
+				pdata->initial_req_buf_config[j]);
+		dev_dbg(&pdev->dev,
 				"Setting SysClkReq%dRfClkBuf 0x%X\n",
 				j + 1,
 				pdata->initial_req_buf_config[j]);
-			if (ret < 0) {
-				dev_err(&pdev->dev,
-					"unable to set sysClkReq%dRfClkBuf: "
-					"%d\n", j + 1, ret);
-			}
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+				"unable to set sysClkReq%dRfClkBuf: "
+				"%d\n", j + 1, ret);
 		}
 	}
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 15/35] mfd: ab8500-debugfs: Add tests for ab8540 based platform initialisations
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (13 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 14/35] mfd: ab8500-sysctrl: Error check clean up Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 16/35] mfd: ab8500: Add more platform checks Lee Jones
                   ` (19 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Alexandre Torgue <alexandre.torgue@stericsson.com>

Signed-off-by: Alexandre Torgue <alexandre.torgue@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
Tested-by: Maxime COQUELIN <maxime.coquelin@stericsson.com>
---
 drivers/mfd/ab8500-core.c    |   11 +++++++----
 drivers/mfd/ab8500-debugfs.c |    2 ++
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index e82cf73..f5ceb2e 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1296,7 +1296,8 @@ static ssize_t show_chip_id(struct device *dev,
 	ab8500 = dev_get_drvdata(dev);
 	if(ab8500) {
 		chip_id = ab8500->chip_id;
-		if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
+		if ((is_ab8505(ab8500) || is_ab9540(ab8500)
+			|| is_ab8540(ab8500)) && ab8500->version != 0xFF)
 			chip_id = (ab8500->version << 8) | chip_id;
 	}
 	return sprintf(buf, "%#x\n", chip_id);
@@ -1597,7 +1598,7 @@ static int ab8500_probe(struct platform_device *pdev)
 
 	/*  Activate this feature only in ab9540 */
 	/*  till tests are done on ab8500 1p2 or later*/
-	if (is_ab9540(ab8500)) {
+	if (is_ab9540(ab8500) || is_ab8540(ab8500))
 		ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
 						ab8500_hierarchical_irq,
 						IRQF_ONESHOT | IRQF_NO_SUSPEND,
@@ -1640,7 +1641,8 @@ static int ab8500_probe(struct platform_device *pdev)
 			dev_err(ab8500->dev, "error adding bm devices\n");
 	}
 
-	if (is_ab9540(ab8500))
+	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
 		ret = sysfs_create_group(&ab8500->dev->kobj,
 					&ab9540_attr_group);
 	else
@@ -1656,7 +1658,8 @@ static int ab8500_remove(struct platform_device *pdev)
 {
 	struct ab8500 *ab8500 = platform_get_drvdata(pdev);
 
-	if (is_ab9540(ab8500))
+	if (((is_ab8505(ab8500) || is_ab9540(ab8500)) &&
+			ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500))
 		sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
 	else
 		sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 51b0e97..3eeab01 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -1942,6 +1942,8 @@ static int ab8500_debug_probe(struct platform_device *plf)
 		num_interrupt_lines = AB8505_NR_IRQS;
 	else if (is_ab9540(ab8500))
 		num_interrupt_lines = AB9540_NR_IRQS;
+	else if (is_ab8540(ab8500))
+		num_interrupt_lines = AB8540_NR_IRQS;
 
 	file = debugfs_create_file("interrupts", (S_IRUGO),
 	    ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 16/35] mfd: ab8500: Add more platform checks
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (14 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 15/35] mfd: ab8500-debugfs: Add tests for ab8540 based platform initialisations Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 17/35] mfd: ab8500: Introduce AB8540 cuts definition Lee Jones
                   ` (18 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Here we add the functionality to check for:

 - Earlier versions of the AB8505 than 2p0
 - Earlier versions of the AB9540 than 2p0

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/abx500/ab8500.h |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index f432cef..7e323fc 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -432,6 +432,16 @@ static inline int is_ab8500_2p0(struct ab8500 *ab)
 	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
 }
 
+static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
+{
+       return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
+static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
+{
+       return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
 #ifdef CONFIG_AB8500_DEBUG
 void ab8500_dump_all_banks(struct device *dev);
 void ab8500_debug_register_interrupt(int line);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 17/35] mfd: ab8500: Introduce AB8540 cuts definition
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (15 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 16/35] mfd: ab8500: Add more platform checks Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 18/35] mfd: ab8500-sysctrl: Update correct turn on status Lee Jones
                   ` (17 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: zhoubin <bin.zhou@stericsson.com>

Add AB8540 cuts definition and its associated helper functions.

Signed-off-by: zhoubin <bin.zhou@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Ying Bao JIA <yingbao.jia@stericsson.com>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Tested-by: Xiao Mei ZHANG <xiaomei.zhang@stericsson.com>
Tested-by: Maxime COQUELIN <maxime.coquelin@stericsson.com>
---
 include/linux/mfd/abx500/ab8500.h |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 7e323fc..06a8292 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -32,6 +32,7 @@ enum ab8500_version {
 #define AB8500_CUTEARLY	0x00
 #define AB8500_CUT1P0	0x10
 #define AB8500_CUT1P1	0x11
+#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
 #define AB8500_CUT2P0	0x20
 #define AB8500_CUT3P0	0x30
 #define AB8500_CUT3P3	0x33
@@ -442,6 +443,31 @@ static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
        return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
 }
 
+static inline int is_ab8540_1p0_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P0);
+}
+
+static inline int is_ab8540_1p1_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P1);
+}
+
+static inline int is_ab8540_1p2_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P2);
+}
+
+static inline int is_ab8540_2p0_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT2P0);
+}
+
+static inline int is_ab8540_2p0(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id == AB8500_CUT2P0);
+}
+
 #ifdef CONFIG_AB8500_DEBUG
 void ab8500_dump_all_banks(struct device *dev);
 void ab8500_debug_register_interrupt(int line);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 18/35] mfd: ab8500-sysctrl: Update correct turn on status
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (16 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 17/35] mfd: ab8500: Introduce AB8540 cuts definition Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 19/35] mfd: ab8500-debug: Add support for ab8505 and ab9540 Lee Jones
                   ` (16 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rajkumar Kasirajan <rajkumar.kasirajan@stericsson.com>

In L9540, turn_on_status register is not updated correctly if
the device is rebooted with AC/USB charger connected. Due to
this, the device boots android instead of entering into charge
only mode. Read the AC/USB status register to detect the charger
presence and update the turn on status manually.

Signed-off-by: Rajkumar Kasirajan <rajkumar.kasirajan@stericsson.com>
Signed-off-by: Per Forlin <per.forlin@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Rupesh KUMAR <rupesh.kumar@stericsson.com>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Tested-by: Rupesh KUMAR <rupesh.kumar@stericsson.com>
Tested-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
---
 drivers/mfd/ab8500-core.c         |   39 +++++++++++++++++++++++++++++++++++++
 drivers/mfd/ab8500-sysctrl.c      |    2 +-
 include/linux/mfd/abx500/ab8500.h |   11 +++++++++++
 3 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index f5ceb2e..bbbd6e4 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -113,6 +113,13 @@
 
 #define AB8500_TURN_ON_STATUS		0x00
 
+#define AB8500_CH_USBCH_STAT1_REG	0x02
+#define VBUS_DET_DBNC100		0x02
+#define VBUS_DET_DBNC1			0x01
+
+static DEFINE_SPINLOCK(on_stat_lock);
+static u8 turn_on_stat_mask = 0xFF;
+static u8 turn_on_stat_set;
 static bool no_bm; /* No battery management */
 module_param(no_bm, bool, S_IRUGO);
 
@@ -1329,6 +1336,15 @@ static ssize_t show_switch_off_status(struct device *dev,
 	return sprintf(buf, "%#x\n", value);
 }
 
+/* use mask and set to override the register turn_on_stat value */
+void ab8500_override_turn_on_stat(u8 mask, u8 set)
+{
+	spin_lock(&on_stat_lock);
+	turn_on_stat_mask = mask;
+	turn_on_stat_set = set;
+	spin_unlock(&on_stat_lock);
+}
+
 /*
  * ab8500 has turned on due to (TURN_ON_STATUS):
  * 0x01 PORnVbat
@@ -1352,6 +1368,20 @@ static ssize_t show_turn_on_status(struct device *dev,
 		AB8500_TURN_ON_STATUS, &value);
 	if (ret < 0)
 		return ret;
+
+	/*
+	 * In L9540, turn_on_status register is not updated correctly if
+	 * the device is rebooted with AC/USB charger connected. Due to
+	 * this, the device boots android instead of entering into charge
+	 * only mode. Read the AC/USB status register to detect the charger
+	 * presence and update the turn on status manually.
+	 */
+	if (is_ab9540(ab8500)) {
+		spin_lock(&on_stat_lock);
+		value = (value & turn_on_stat_mask) | turn_on_stat_set;
+		spin_unlock(&on_stat_lock);
+	}
+
 	return sprintf(buf, "%#x\n", value);
 }
 
@@ -1564,6 +1594,15 @@ static int ab8500_probe(struct platform_device *pdev)
 
 	if (plat && plat->init)
 		plat->init(ab8500);
+	if (is_ab9540(ab8500)) {
+		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
+			AB8500_CH_USBCH_STAT1_REG, &value);
+		if (ret < 0)
+			return ret;
+		if ((value & VBUS_DET_DBNC1) && (value & VBUS_DET_DBNC100))
+			ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
+						     AB8500_VBUS_DET);
+	}
 
 	/* Clear and mask all interrupts */
 	for (i = 0; i < ab8500->mask_size; i++) {
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index ab6bfd3..6ac63a0 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -21,7 +21,7 @@ void ab8500_power_off(void)
 {
 	sigset_t old;
 	sigset_t all;
-	static char *pss[] = {"ab8500_ac", "ab8500_usb"};
+	static char *pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
 	int i;
 	bool charger_present = false;
 	union power_supply_propval val;
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 06a8292..6748129 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -308,6 +308,15 @@ enum ab8500_version {
 #define AB9540_NUM_IRQ_REGS		20
 #define AB8540_NUM_IRQ_REGS		27
 
+/* Turn On Status Event */
+#define AB8500_POR_ON_VBAT		0x01
+#define AB8500_POW_KEY_1_ON		0x02
+#define AB8500_POW_KEY_2_ON		0x04
+#define AB8500_RTC_ALARM		0x08
+#define AB8500_MAIN_CH_DET		0x10
+#define AB8500_VBUS_DET			0x20
+#define AB8500_USB_ID_DET		0x40
+
 /**
  * struct ab8500 - ab8500 internal structure
  * @dev: parent device
@@ -468,6 +477,8 @@ static inline int is_ab8540_2p0(struct ab8500 *ab)
 	return is_ab8540(ab) && (ab->chip_id == AB8500_CUT2P0);
 }
 
+void ab8500_override_turn_on_stat(u8 mask, u8 set);
+
 #ifdef CONFIG_AB8500_DEBUG
 void ab8500_dump_all_banks(struct device *dev);
 void ab8500_debug_register_interrupt(int line);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 19/35] mfd: ab8500-debug: Add support for ab8505 and ab9540
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (17 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 18/35] mfd: ab8500-sysctrl: Update correct turn on status Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 20/35] mfd: ab8500-sysctrl: Add new reset function Lee Jones
                   ` (15 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Make it possible to dump all registers in ab8505 and ab9540.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-debugfs.c      |  383 +++++++++++++++++++++++++++++++++++--
 include/linux/mfd/abx500/ab8500.h |    1 +
 2 files changed, 373 insertions(+), 11 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 3eeab01..ef1bd89 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -155,7 +155,9 @@ static struct hwreg_cfg hwreg_cfg = {
 
 #define AB8500_REV_REG 0x80
 
-static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges *debug_ranges;
+
+struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
 	[0x0] = {
 		.num_ranges = 0,
 		.range = NULL,
@@ -359,7 +361,7 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
 			},
 			{
 				.first = 0xf5,
-				.last =	0xf6,
+				.last = 0xf6,
 			},
 		},
 	},
@@ -484,6 +486,365 @@ static struct ab8500_prcmu_ranges debug_ranges[AB8500_NUM_BANKS] = {
 	},
 };
 
+struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
+	[0x0] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_SYS_CTRL1_BLOCK] = {
+		.num_ranges = 5,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x04,
+			},
+			{
+				.first = 0x42,
+				.last = 0x42,
+			},
+			{
+				.first = 0x52,
+				.last = 0x52,
+			},
+			{
+				.first = 0x54,
+				.last = 0x57,
+			},
+			{
+				.first = 0x80,
+				.last = 0x83,
+			},
+		},
+	},
+	[AB8500_SYS_CTRL2_BLOCK] = {
+		.num_ranges = 5,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x0D,
+			},
+			{
+				.first = 0x0F,
+				.last = 0x17,
+			},
+			{
+				.first = 0x20,
+				.last = 0x20,
+			},
+			{
+				.first = 0x30,
+				.last = 0x30,
+			},
+			{
+				.first = 0x32,
+				.last = 0x3A,
+			},
+		},
+	},
+	[AB8500_REGU_CTRL1] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x00,
+			},
+			{
+				.first = 0x03,
+				.last = 0x11,
+			},
+			{
+				.first = 0x80,
+				.last = 0x86,
+			},
+		},
+	},
+	[AB8500_REGU_CTRL2] = {
+		.num_ranges = 6,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x06,
+			},
+			{
+				.first = 0x08,
+				.last = 0x15,
+			},
+			{
+				.first = 0x17,
+				.last = 0x19,
+			},
+			{
+				.first = 0x1B,
+				.last = 0x1D,
+			},
+			{
+				.first = 0x1F,
+				.last = 0x30,
+			},
+			{
+				.first = 0x40,
+				.last = 0x48,
+			},
+			/* 0x80-0x8B is SIM registers and should
+			 * not be accessed from here */
+		},
+	},
+	[AB8500_USB] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x80,
+				.last = 0x83,
+			},
+			{
+				.first = 0x87,
+				.last = 0x8A,
+			},
+			{
+				.first = 0x91,
+				.last = 0x94,
+			},
+		},
+	},
+	[AB8500_TVOUT] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_DBI] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_ECI_AV_ACC] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x80,
+				.last = 0x82,
+			},
+		},
+	},
+	[AB8500_RESERVED] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_GPADC] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x08,
+			},
+		},
+	},
+	[AB8500_CHARGER] = {
+		.num_ranges = 9,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x02,
+				.last = 0x03,
+			},
+			{
+				.first = 0x05,
+				.last = 0x05,
+			},
+			{
+				.first = 0x40,
+				.last = 0x44,
+			},
+			{
+				.first = 0x50,
+				.last = 0x57,
+			},
+			{
+				.first = 0x60,
+				.last = 0x60,
+			},
+			{
+				.first = 0xA0,
+				.last = 0xA7,
+			},
+			{
+				.first = 0xAF,
+				.last = 0xB2,
+			},
+			{
+				.first = 0xC0,
+				.last = 0xC2,
+			},
+			{
+				.first = 0xF5,
+				.last = 0xF5,
+			},
+		},
+	},
+	[AB8500_GAS_GAUGE] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x00,
+			},
+			{
+				.first = 0x07,
+				.last = 0x0A,
+			},
+			{
+				.first = 0x10,
+				.last = 0x14,
+			},
+		},
+	},
+	[AB8500_AUDIO] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x83,
+			},
+		},
+	},
+	[AB8500_INTERRUPT] = {
+		.num_ranges = 11,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x04,
+			},
+			{
+				.first = 0x06,
+				.last = 0x07,
+			},
+			{
+				.first = 0x09,
+				.last = 0x09,
+			},
+			{
+				.first = 0x0B,
+				.last = 0x0C,
+			},
+			{
+				.first = 0x12,
+				.last = 0x15,
+			},
+			{
+				.first = 0x18,
+				.last = 0x18,
+			},
+			/* Latch registers should not be read here */
+			{
+				.first = 0x40,
+				.last = 0x44,
+			},
+			{
+				.first = 0x46,
+				.last = 0x49,
+			},
+			{
+				.first = 0x4B,
+				.last = 0x4D,
+			},
+			{
+				.first = 0x52,
+				.last = 0x55,
+			},
+			{
+				.first = 0x58,
+				.last = 0x58,
+			},
+			/* LatchHier registers should not be read here */
+		},
+	},
+	[AB8500_RTC] = {
+		.num_ranges = 2,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x14,
+			},
+			{
+				.first = 0x16,
+				.last = 0x17,
+			},
+		},
+	},
+	[AB8500_MISC] = {
+		.num_ranges = 8,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x06,
+			},
+			{
+				.first = 0x10,
+				.last = 0x16,
+			},
+			{
+				.first = 0x20,
+				.last = 0x26,
+			},
+			{
+				.first = 0x30,
+				.last = 0x36,
+			},
+			{
+				.first = 0x40,
+				.last = 0x46,
+			},
+			{
+				.first = 0x50,
+				.last = 0x50,
+			},
+			{
+				.first = 0x60,
+				.last = 0x6B,
+			},
+			{
+				.first = 0x80,
+				.last = 0x82,
+			},
+		},
+	},
+	[AB8500_DEVELOPMENT] = {
+		.num_ranges = 2,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x00,
+			},
+			{
+				.first = 0x05,
+				.last = 0x05,
+			},
+		},
+	},
+	[AB8500_DEBUG] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x05,
+				.last = 0x07,
+			},
+		},
+	},
+	[AB8500_PROD_TEST] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_STE_TEST] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_OTP_EMUL] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x01,
+				.last = 0x15,
+			},
+		},
+	},
+};
+
 static irqreturn_t ab8500_debug_handler(int irq, void *data)
 {
 	char buf[16];
@@ -528,9 +889,6 @@ static int ab8500_registers_print(struct device *dev, u32 bank,
 				err = seq_printf(s, "  [0x%02X/0x%02X]: 0x%02X\n",
 					bank, reg, value);
 				if (err < 0) {
-					dev_err(dev,
-					"seq_printf overflow bank=0x%02X reg=0x%02X\n",
-						bank, reg);
 					/* Error is not returned here since
 					 * the output is wanted in any case */
 					return 0;
@@ -580,8 +938,6 @@ static int ab8500_print_all_banks(struct seq_file *s, void *p)
 
 	for (i = 1; i < AB8500_NUM_BANKS; i++) {
 		err = seq_printf(s, " bank 0x%02X:\n", i);
-		if (err < 0)
-			dev_err(dev, "seq_printf overflow, bank=0x%02X\n", i);
 
 		ab8500_registers_print(dev, i, s);
 	}
@@ -1936,14 +2292,19 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	if (!file)
 		goto err;
 
-	if (is_ab8500(ab8500))
+	if (is_ab8500(ab8500)) {
+		debug_ranges = ab8500_debug_ranges;
 		num_interrupt_lines = AB8500_NR_IRQS;
-	else if (is_ab8505(ab8500))
+	} else if (is_ab8505(ab8500)) {
+		debug_ranges = ab8505_debug_ranges;
 		num_interrupt_lines = AB8505_NR_IRQS;
-	else if (is_ab9540(ab8500))
+	} else if (is_ab9540(ab8500)) {
+		debug_ranges = ab8505_debug_ranges;
 		num_interrupt_lines = AB9540_NR_IRQS;
-	else if (is_ab8540(ab8500))
+	} else if (is_ab8540(ab8500)) {
+		debug_ranges = ab8505_debug_ranges;
 		num_interrupt_lines = AB8540_NR_IRQS;
+	}
 
 	file = debugfs_create_file("interrupts", (S_IRUGO),
 	    ab8500_dir, &plf->dev, &ab8500_interrupts_fops);
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 6748129..3e9131f 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -59,6 +59,7 @@ enum ab8500_version {
 #define AB8500_DEVELOPMENT	0x11
 #define AB8500_DEBUG		0x12
 #define AB8500_PROD_TEST	0x13
+#define AB8500_STE_TEST		0x14
 #define AB8500_OTP_EMUL		0x15
 
 /*
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 20/35] mfd: ab8500-sysctrl: Add new reset function
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (18 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 19/35] mfd: ab8500-debug: Add support for ab8505 and ab9540 Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 21/35] mfd: ab8500-gpadc: Add support for the AB8540 Lee Jones
                   ` (14 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Add a new reset function which uses the AB WD with 0 timeout.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-sysctrl.c              |   63 +++++++++++++++++++++++++++++
 include/linux/mfd/abx500/ab8500-sysctrl.h |    6 +++
 2 files changed, 69 insertions(+)

diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 6ac63a0..f43c42b 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -15,6 +15,12 @@
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/mfd/abx500/ab8500-sysctrl.h>
 
+/* RtcCtrl bits */
+#define AB8500_ALARM_MIN_LOW  0x08
+#define AB8500_ALARM_MIN_MID 0x09
+#define RTC_CTRL 0x0B
+#define RTC_ALARM_ENABLE 0x4
+
 static struct device *sysctrl_dev;
 
 void ab8500_power_off(void)
@@ -79,6 +85,63 @@ shutdown:
 	}
 }
 
+/*
+ * Use the AB WD to reset the platform. It will perform a hard
+ * reset instead of a soft reset. Write the reset reason to
+ * the AB before reset, which can be read upon restart.
+ */
+void ab8500_restart(char mode, const char *cmd)
+{
+	struct ab8500_platform_data *plat;
+	struct ab8500_sysctrl_platform_data *pdata;
+	u16 reason = 0;
+	u8 val;
+
+	if (sysctrl_dev == NULL) {
+		pr_err("%s: sysctrl not initialized\n", __func__);
+		return;
+	}
+
+	plat = dev_get_platdata(sysctrl_dev->parent);
+	pdata = plat->sysctrl;
+	if (pdata->reboot_reason_code)
+		reason = pdata->reboot_reason_code(cmd);
+	else
+		pr_warn("[%s] No reboot reason set. Default reason %d\n",
+			__func__, reason);
+
+	/*
+	 * Disable RTC alarm, just a precaution so that no alarm
+	 * is running when WD reset is executed.
+	 */
+	abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
+		RTC_CTRL , &val);
+	abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+		RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
+
+	/*
+	 * Android is not using the RTC alarm registers during reboot
+	 * so we borrow them for writing the reason of reset
+	 */
+
+	/* reason[8 LSB] */
+	val = reason & 0xFF;
+	abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+		AB8500_ALARM_MIN_LOW , val);
+
+	/* reason[8 MSB] */
+	val = (reason>>8) & 0xFF;
+	abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
+		AB8500_ALARM_MIN_MID , val);
+
+	/* Setting WD timeout to 0 */
+	ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
+
+	/* Setting the parameters to AB8500 WD*/
+	ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
+		AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
+}
+
 static inline bool valid_bank(u8 bank)
 {
 	return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
index ebf12e7..990bc93 100644
--- a/include/linux/mfd/abx500/ab8500-sysctrl.h
+++ b/include/linux/mfd/abx500/ab8500-sysctrl.h
@@ -12,6 +12,7 @@
 
 int ab8500_sysctrl_read(u16 reg, u8 *value);
 int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
+void ab8500_restart(char mode, const char *cmd);
 
 #else
 
@@ -40,6 +41,7 @@ static inline int ab8500_sysctrl_clear(u16 reg, u8 bits)
 /* Configuration data for SysClkReq1RfClkBuf - SysClkReq8RfClkBuf */
 struct ab8500_sysctrl_platform_data {
 	u8 initial_req_buf_config[8];
+	u16 (*reboot_reason_code)(const char *cmd);
 };
 
 /* Registers */
@@ -299,4 +301,8 @@ struct ab8500_sysctrl_platform_data {
 #define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_MASK 0xFF
 #define AB9540_SYSCLK12BUF4VALID_SYSCLK12BUF4VALID_SHIFT 0
 
+#define AB8500_ENABLE_WD 0x1
+#define AB8500_KICK_WD 0x2
+#define AB8500_WD_RESTART_ON_EXPIRE 0x10
+
 #endif /* __AB8500_SYSCTRL_H */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 21/35] mfd: ab8500-gpadc: Add support for the AB8540
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (19 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 20/35] mfd: ab8500-sysctrl: Add new reset function Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 22/35] mfd: ab8500-debug: " Lee Jones
                   ` (13 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

This patch enables the GPADC to work on AB8540 based platforms.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-gpadc.c              |  316 +++++++++++++++++++++++++++----
 include/linux/mfd/abx500/ab8500-gpadc.h |   43 +++--
 2 files changed, 305 insertions(+), 54 deletions(-)

diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 6b18975..f3712d8 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -37,6 +37,13 @@
 #define AB8500_GPADC_AUTODATAL_REG	0x07
 #define AB8500_GPADC_AUTODATAH_REG	0x08
 #define AB8500_GPADC_MUX_CTRL_REG	0x09
+#define AB8540_GPADC_MANDATA2L_REG	0x09
+#define AB8540_GPADC_MANDATA2H_REG	0x0A
+#define AB8540_GPADC_APEAAX_REG		0x10
+#define AB8540_GPADC_APEAAT_REG		0x11
+#define AB8540_GPADC_APEAAM_REG		0x12
+#define AB8540_GPADC_APEAAH_REG		0x13
+#define AB8540_GPADC_APEAAL_REG		0x14
 
 /*
  * OTP register offsets
@@ -49,6 +56,10 @@
 #define AB8500_GPADC_CAL_5		0x13
 #define AB8500_GPADC_CAL_6		0x14
 #define AB8500_GPADC_CAL_7		0x15
+/* New calibration for 8540 */
+#define AB8540_GPADC_OTP4_REG_7	0x38
+#define AB8540_GPADC_OTP4_REG_6	0x39
+#define AB8540_GPADC_OTP4_REG_5	0x3A
 
 /* gpadc constants */
 #define EN_VINTCORE12			0x04
@@ -67,6 +78,7 @@
 #define GPADC_BUSY			0x01
 #define EN_FALLING			0x10
 #define EN_TRIG_EDGE			0x02
+#define EN_VBIAS_XTAL_TEMP		0x02
 
 /* GPADC constants from AB8500 spec, UM0836 */
 #define ADC_RESOLUTION			1024
@@ -85,8 +97,21 @@
 #define ADC_CH_BKBAT_MIN		0
 #define ADC_CH_BKBAT_MAX		3200
 
+/* GPADC constants from AB8540 spec */
+#define ADC_CH_IBAT_MIN			(-6000) /* mA range measured by ADC for ibat*/
+#define ADC_CH_IBAT_MAX			6000
+#define ADC_CH_IBAT_MIN_V		(-60)	/* mV range measured by ADC for ibat*/
+#define ADC_CH_IBAT_MAX_V		60
+#define IBAT_VDROP_L			(-56)  /* mV */
+#define IBAT_VDROP_H			56
+
 /* This is used to not lose precision when dividing to get gain and offset */
-#define CALIB_SCALE			1000
+#define CALIB_SCALE		1000
+/*
+ * Number of bits shift used to not lose precision
+ * when dividing to get ibat gain.
+ */
+#define CALIB_SHIFT_IBAT	20
 
 /* Time in ms before disabling regulator */
 #define GPADC_AUDOSUSPEND_DELAY		1
@@ -97,6 +122,7 @@ enum cal_channels {
 	ADC_INPUT_VMAIN = 0,
 	ADC_INPUT_BTEMP,
 	ADC_INPUT_VBAT,
+	ADC_INPUT_IBAT,
 	NBR_CAL_INPUTS,
 };
 
@@ -107,8 +133,8 @@ enum cal_channels {
  * @offset:		Offset of the ADC channel
  */
 struct adc_cal_data {
-	u64 gain;
-	u64 offset;
+	s64 gain;
+	s64 offset;
 };
 
 /**
@@ -183,6 +209,7 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
 			gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE;
 		break;
 
+	case XTAL_TEMP:
 	case BAT_CTRL:
 	case BTEMP_BALL:
 	case ACC_DETECT1:
@@ -201,6 +228,7 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
 		break;
 
 	case MAIN_BAT_V:
+	case VBAT_TRUE_MEAS:
 		/* For some reason we don't have calibrated data */
 		if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) {
 			res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX -
@@ -244,6 +272,20 @@ int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel,
 			ADC_RESOLUTION;
 		break;
 
+	case IBAT_VIRTUAL_CHANNEL:
+		/* For some reason we don't have calibrated data */
+		if (!gpadc->cal_data[ADC_INPUT_IBAT].gain) {
+			res = ADC_CH_IBAT_MIN + (ADC_CH_IBAT_MAX -
+				ADC_CH_IBAT_MIN) * ad_value /
+				ADC_RESOLUTION;
+			break;
+		}
+		/* Here we can use the calibrated data */
+		res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_IBAT].gain +
+				gpadc->cal_data[ADC_INPUT_IBAT].offset)
+				>> CALIB_SHIFT_IBAT;
+		break;
+
 	default:
 		dev_err(gpadc->dev,
 			"unknown channel, not possible to convert\n");
@@ -307,9 +349,19 @@ EXPORT_SYMBOL(ab8500_gpadc_convert);
 int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type)
 {
+	int raw_data;
+	raw_data = ab8500_gpadc_double_read_raw(gpadc, channel,
+			avg_sample, trig_edge, trig_timer, conv_type, NULL);
+	return raw_data;
+}
+
+int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
+		int *ibat)
+{
 	int ret;
 	int looplimit = 0;
-	u8 val, low_data, high_data;
+	u8 val, low_data, high_data, low_data2, high_data2;
 
 	if (!gpadc)
 		return -ENODEV;
@@ -362,7 +414,6 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 	default:
 		val = channel | AVG_16;
 		break;
-
 	}
 
 	if (conv_type == ADC_HW)
@@ -386,8 +437,8 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
 			EN_FALLING, EN_FALLING);
-
 	}
+
 	switch (channel) {
 	case MAIN_CHARGER_C:
 	case USB_CHARGER_C:
@@ -404,6 +455,55 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 				EN_BUF | EN_ICHAR,
 				EN_BUF | EN_ICHAR);
 		break;
+
+	case XTAL_TEMP:
+		if (conv_type == ADC_HW)
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF  | EN_TRIG_EDGE,
+				EN_BUF  | EN_TRIG_EDGE);
+		else
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF ,
+				EN_BUF);
+		break;
+
+	case VBAT_TRUE_MEAS:
+		if (conv_type == ADC_HW)
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF  | EN_TRIG_EDGE,
+				EN_BUF  | EN_TRIG_EDGE);
+		else
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF ,
+				EN_BUF);
+		break;
+
+	case BAT_CTRL_AND_IBAT:
+	case VBAT_MEAS_AND_IBAT:
+	case VBAT_TRUE_MEAS_AND_IBAT:
+	case BAT_TEMP_AND_IBAT:
+		if (conv_type == ADC_HW)
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_TRIG_EDGE,
+				EN_TRIG_EDGE);
+		else
+			ret = abx500_mask_and_set_register_interruptible(
+				gpadc->dev,
+				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+				EN_BUF,
+				0);
+		break;
+
 	case BTEMP_BALL:
 		if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
 			if (conv_type == ADC_HW)
@@ -474,21 +574,19 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 	/* wait for completion of conversion */
 	if (conv_type == ADC_HW) {
 		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
-			2*HZ)) {
-				dev_err(gpadc->dev,
-					"timeout didn't receive"
-					" hw GPADC conv interrupt\n");
-				ret = -EINVAL;
-				goto out;
+				2 * HZ)) {
+			dev_err(gpadc->dev,
+				"timeout didn't receive hw GPADC conv interrupt\n");
+			ret = -EINVAL;
+			goto out;
 		}
 	} else {
 		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
-			msecs_to_jiffies(CONVERSION_TIME))) {
-				dev_err(gpadc->dev,
-					"timeout didn't receive"
-					" sw GPADC conv interrupt\n");
-				ret = -EINVAL;
-				goto out;
+				msecs_to_jiffies(CONVERSION_TIME))) {
+			dev_err(gpadc->dev,
+				"timeout didn't receive sw GPADC conv interrupt\n");
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 
@@ -526,6 +624,46 @@ int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 			goto out;
 		}
 	}
+	/* Check if double convertion is required */
+	if ((channel == BAT_CTRL_AND_IBAT) ||
+			(channel == VBAT_MEAS_AND_IBAT) ||
+			(channel == VBAT_TRUE_MEAS_AND_IBAT) ||
+			(channel == BAT_TEMP_AND_IBAT)) {
+
+		if (conv_type == ADC_HW) {
+			/* not supported */
+			ret = -ENOTSUPP;
+			dev_err(gpadc->dev,
+				"gpadc_conversion: only SW double conversion supported\n");
+			goto out;
+		} else {
+			/* Read the converted RAW data 2 */
+			ret = abx500_get_register_interruptible(gpadc->dev,
+				AB8500_GPADC, AB8540_GPADC_MANDATA2L_REG,
+				&low_data2);
+			if (ret < 0) {
+				dev_err(gpadc->dev,
+					"gpadc_conversion: read sw low data 2 failed\n");
+				goto out;
+			}
+
+			ret = abx500_get_register_interruptible(gpadc->dev,
+				AB8500_GPADC, AB8540_GPADC_MANDATA2H_REG,
+				&high_data2);
+			if (ret < 0) {
+				dev_err(gpadc->dev,
+					"gpadc_conversion: read sw high data 2 failed\n");
+				goto out;
+			}
+			if (ibat != NULL) {
+				*ibat = (high_data2 << 8) | low_data2;
+			} else {
+				dev_warn(gpadc->dev,
+					"gpadc_conversion: ibat not stored\n");
+			}
+
+		}
+	}
 
 	/* Disable GPADC */
 	ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
@@ -589,15 +727,27 @@ static int otp_cal_regs[] = {
 	AB8500_GPADC_CAL_7,
 };
 
+static int otp4_cal_regs[] = {
+	AB8540_GPADC_OTP4_REG_7,
+	AB8540_GPADC_OTP4_REG_6,
+	AB8540_GPADC_OTP4_REG_5,
+};
+
 static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 {
 	int i;
 	int ret[ARRAY_SIZE(otp_cal_regs)];
 	u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)];
-
+	int ret_otp4[ARRAY_SIZE(otp4_cal_regs)];
+	u8 gpadc_otp4[ARRAY_SIZE(otp4_cal_regs)];
 	int vmain_high, vmain_low;
 	int btemp_high, btemp_low;
 	int vbat_high, vbat_low;
+	int ibat_high, ibat_low;
+	s64 V_gain, V_offset, V2A_gain, V2A_offset;
+	struct ab8500 *ab8500;
+
+	ab8500 = gpadc->parent;
 
 	/* First we read all OTP registers and store the error code */
 	for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) {
@@ -617,7 +767,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 	 * bt_h/l = btemp_high/low
 	 * vb_h/l = vbat_high/low
 	 *
-	 * Data bits:
+	 * Data bits 8500/9540:
 	 * | 7	   | 6	   | 5	   | 4	   | 3	   | 2	   | 1	   | 0
 	 * |.......|.......|.......|.......|.......|.......|.......|.......
 	 * |						   | vm_h9 | vm_h8
@@ -635,6 +785,35 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 	 * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
 	 * |.......|.......|.......|.......|.......|.......|.......|.......
 	 *
+	 * Data bits 8540:
+	 * OTP2
+	 * | 7	   | 6	   | 5	   | 4	   | 3	   | 2	   | 1	   | 0
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * |
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | vm_h9 | vm_h8 | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 |
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 *
+	 * Data bits 8540:
+	 * OTP4
+	 * | 7	   | 6	   | 5	   | 4	   | 3	   | 2	   | 1	   | 0
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * |					   | ib_h9 | ib_h8 | ib_h7
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | ib_h6 | ib_h5 | ib_h4 | ib_h3 | ib_h2 | ib_h1 | ib_h0 | ib_l5
+	 * |.......|.......|.......|.......|.......|.......|.......|.......
+	 * | ib_l4 | ib_l3 | ib_l2 | ib_l1 | ib_l0 |
+	 *
 	 *
 	 * Ideal output ADC codes corresponding to injected input voltages
 	 * during manufacturing is:
@@ -647,38 +826,96 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 	 * vbat_low:   Vin = 2380mV  / ADC ideal code = 33
 	 */
 
-	/* Calculate gain and offset for VMAIN if all reads succeeded */
-	if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
-		vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
-			((gpadc_cal[1] & 0x3F) << 2) |
-			((gpadc_cal[2] & 0xC0) >> 6));
+	if (is_ab8540(ab8500)) {
+		/* Calculate gain and offset for VMAIN if all reads succeeded*/
+		if (!(ret[1] < 0 || ret[2] < 0)) {
+			vmain_high = (((gpadc_cal[1] & 0xFF) << 2) |
+				((gpadc_cal[2] & 0xC0) >> 6));
+			vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+			gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
+				(19500 - 315) / (vmain_high - vmain_low);
+			gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE *
+				19500 - (CALIB_SCALE * (19500 - 315) /
+				(vmain_high - vmain_low)) * vmain_high;
+		} else {
+		gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+		}
 
-		vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+		/* Read IBAT calibration Data */
+		for (i = 0; i < ARRAY_SIZE(otp4_cal_regs); i++) {
+			ret_otp4[i] = abx500_get_register_interruptible(
+					gpadc->dev, AB8500_OTP_EMUL,
+					otp4_cal_regs[i],  &gpadc_otp4[i]);
+			if (ret_otp4[i] < 0)
+				dev_err(gpadc->dev,
+					"%s: read otp4 reg 0x%02x failed\n",
+					__func__, otp4_cal_regs[i]);
+		}
 
-		gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
-			(19500 - 315) /	(vmain_high - vmain_low);
+		/* Calculate gain and offset for IBAT if all reads succeeded */
+		if (!(ret_otp4[0] < 0 || ret_otp4[1] < 0 || ret_otp4[2] < 0)) {
+			ibat_high = (((gpadc_otp4[0] & 0x07) << 7) |
+				((gpadc_otp4[1] & 0xFE) >> 1));
+			ibat_low = (((gpadc_otp4[1] & 0x01) << 5) |
+				((gpadc_otp4[2] & 0xF8) >> 3));
+
+			V_gain = ((IBAT_VDROP_H - IBAT_VDROP_L)
+				<< CALIB_SHIFT_IBAT) / (ibat_high - ibat_low);
+
+			V_offset = (IBAT_VDROP_H << CALIB_SHIFT_IBAT) -
+				(((IBAT_VDROP_H - IBAT_VDROP_L) <<
+				CALIB_SHIFT_IBAT) / (ibat_high - ibat_low))
+				* ibat_high;
+			/*
+			 * Result obtained is in mV (at a scale factor),
+			 * we need to calculate gain and offset to get mA
+			 */
+			V2A_gain = (ADC_CH_IBAT_MAX - ADC_CH_IBAT_MIN)/
+				(ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V);
+			V2A_offset = ((ADC_CH_IBAT_MAX_V * ADC_CH_IBAT_MIN -
+				ADC_CH_IBAT_MAX * ADC_CH_IBAT_MIN_V)
+				<< CALIB_SHIFT_IBAT)
+				/ (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V);
+
+			gpadc->cal_data[ADC_INPUT_IBAT].gain = V_gain * V2A_gain;
+			gpadc->cal_data[ADC_INPUT_IBAT].offset = V_offset *
+				V2A_gain + V2A_offset;
+		} else {
+			gpadc->cal_data[ADC_INPUT_IBAT].gain = 0;
+		}
 
-		gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * 19500 -
-			(CALIB_SCALE * (19500 - 315) /
-			 (vmain_high - vmain_low)) * vmain_high;
+		dev_dbg(gpadc->dev, "IBAT gain %llu offset %llu\n",
+			gpadc->cal_data[ADC_INPUT_IBAT].gain,
+			gpadc->cal_data[ADC_INPUT_IBAT].offset);
 	} else {
-		gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+		/* Calculate gain and offset for VMAIN if all reads succeeded */
+		if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) {
+			vmain_high = (((gpadc_cal[0] & 0x03) << 8) |
+				((gpadc_cal[1] & 0x3F) << 2) |
+				((gpadc_cal[2] & 0xC0) >> 6));
+			vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+
+			gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
+				(19500 - 315) / (vmain_high - vmain_low);
+
+			gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE *
+				19500 - (CALIB_SCALE * (19500 - 315) /
+				(vmain_high - vmain_low)) * vmain_high;
+		} else {
+			gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
+		}
 	}
-
 	/* Calculate gain and offset for BTEMP if all reads succeeded */
 	if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) {
 		btemp_high = (((gpadc_cal[2] & 0x01) << 9) |
-			(gpadc_cal[3] << 1) |
-			((gpadc_cal[4] & 0x80) >> 7));
-
+			(gpadc_cal[3] << 1) | ((gpadc_cal[4] & 0x80) >> 7));
 		btemp_low = ((gpadc_cal[4] & 0x7C) >> 2);
 
 		gpadc->cal_data[ADC_INPUT_BTEMP].gain =
 			CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low);
-
 		gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 -
-			(CALIB_SCALE * (1300 - 21) /
-			(btemp_high - btemp_low)) * btemp_high;
+			(CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low))
+			* btemp_high;
 	} else {
 		gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0;
 	}
@@ -690,7 +927,6 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 
 		gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE *
 			(4700 - 2380) /	(vbat_high - vbat_low);
-
 		gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 -
 			(CALIB_SCALE * (4700 - 2380) /
 			(vbat_high - vbat_low)) * vbat_high;
diff --git a/include/linux/mfd/abx500/ab8500-gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h
index 7694e7a..4131437 100644
--- a/include/linux/mfd/abx500/ab8500-gpadc.h
+++ b/include/linux/mfd/abx500/ab8500-gpadc.h
@@ -12,19 +12,32 @@
 
 /* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2
  * and ADCHwSel[4:0] in GPADCCtrl3 ) */
-#define BAT_CTRL	0x01
-#define BTEMP_BALL	0x02
-#define MAIN_CHARGER_V	0x03
-#define ACC_DETECT1	0x04
-#define ACC_DETECT2	0x05
-#define ADC_AUX1	0x06
-#define ADC_AUX2	0x07
-#define MAIN_BAT_V	0x08
-#define VBUS_V		0x09
-#define MAIN_CHARGER_C	0x0A
-#define USB_CHARGER_C	0x0B
-#define BK_BAT_V	0x0C
-#define DIE_TEMP	0x0D
+#define BAT_CTRL		0x01
+#define BTEMP_BALL		0x02
+#define MAIN_CHARGER_V		0x03
+#define ACC_DETECT1		0x04
+#define ACC_DETECT2		0x05
+#define ADC_AUX1		0x06
+#define ADC_AUX2		0x07
+#define MAIN_BAT_V		0x08
+#define VBUS_V			0x09
+#define MAIN_CHARGER_C		0x0A
+#define USB_CHARGER_C		0x0B
+#define BK_BAT_V		0x0C
+#define DIE_TEMP		0x0D
+#define USB_ID			0x0E
+#define XTAL_TEMP		0x12
+#define VBAT_TRUE_MEAS		0x13
+#define BAT_CTRL_AND_IBAT	0x1C
+#define VBAT_MEAS_AND_IBAT	0x1D
+#define VBAT_TRUE_MEAS_AND_IBAT	0x1E
+#define BAT_TEMP_AND_IBAT	0x1F
+
+/* Virtual channel used only for ibat convertion to ampere
+ * Battery current conversion (ibat) cannot be requested as a single conversion
+ *  but it is always in combination with other input requests
+ */
+#define IBAT_VIRTUAL_CHANNEL		0xFF
 
 #define SAMPLE_1        1
 #define SAMPLE_4        4
@@ -37,7 +50,6 @@
 #define ADC_SW				0
 #define ADC_HW				1
 
-
 struct ab8500_gpadc;
 
 struct ab8500_gpadc *ab8500_gpadc_get(char *name);
@@ -51,6 +63,9 @@ static inline int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
 
 int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
+int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
+		u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
+		int *ibat);
 int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
 		u8 channel, int ad_value);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 22/35] mfd: ab8500-debug: Add support for the AB8540
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (20 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 21/35] mfd: ab8500-gpadc: Add support for the AB8540 Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 23/35] mfd: ab8500-gpadc: Optimise GPADC driver Lee Jones
                   ` (12 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Alexandre Bourdiol <alexandre.bourdiol@stericsson.com>

Allow GPADC debug information to be shown when executing on an AB8540
based platform.

Signed-off-by: Alexandre Bourdiol <alexandre.bourdiol@stericsson.com>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c            |  286 ++++++++++++++++++++++++++++++-
 drivers/mfd/ab8500-gpadc.c              |   44 +++++
 include/linux/mfd/abx500/ab8500-gpadc.h |    3 +
 3 files changed, 332 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index ef1bd89..7173406 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -1632,6 +1632,254 @@ static const struct file_operations ab8500_gpadc_die_temp_fops = {
 	.owner = THIS_MODULE,
 };
 
+static int ab8540_gpadc_xtal_temp_print(struct seq_file *s, void *p)
+{
+	int xtal_temp_raw;
+	int xtal_temp_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	xtal_temp_raw = ab8500_gpadc_read_raw(gpadc, XTAL_TEMP,
+		avg_sample, trig_edge, trig_timer, conv_type);
+	xtal_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, XTAL_TEMP,
+		xtal_temp_raw);
+
+	return seq_printf(s, "%d,0x%X\n",
+			xtal_temp_convert, xtal_temp_raw);
+}
+
+static int ab8540_gpadc_xtal_temp_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8540_gpadc_xtal_temp_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_xtal_temp_fops = {
+	.open = ab8540_gpadc_xtal_temp_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_true_meas_print(struct seq_file *s, void *p)
+{
+	int vbat_true_meas_raw;
+	int vbat_true_meas_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	vbat_true_meas_raw = ab8500_gpadc_read_raw(gpadc, VBAT_TRUE_MEAS,
+		avg_sample, trig_edge, trig_timer, conv_type);
+	vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBAT_TRUE_MEAS,
+		vbat_true_meas_raw);
+
+	return seq_printf(s, "%d,0x%X\n",
+			vbat_true_meas_convert, vbat_true_meas_raw);
+}
+
+static int ab8540_gpadc_vbat_true_meas_open(struct inode *inode,
+		struct file *file)
+{
+	return single_open(file, ab8540_gpadc_vbat_true_meas_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_true_meas_fops = {
+	.open = ab8540_gpadc_vbat_true_meas_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_bat_ctrl_and_ibat_print(struct seq_file *s, void *p)
+{
+	int bat_ctrl_raw;
+	int bat_ctrl_convert;
+	int ibat_raw;
+	int ibat_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	bat_ctrl_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_CTRL_AND_IBAT,
+		avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+
+	bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, BAT_CTRL,
+		bat_ctrl_raw);
+	ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+		ibat_raw);
+
+	return seq_printf(s, "%d,0x%X\n"  "%d,0x%X\n",
+			bat_ctrl_convert, bat_ctrl_raw,
+			ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_bat_ctrl_and_ibat_open(struct inode *inode,
+		struct file *file)
+{
+	return single_open(file, ab8540_gpadc_bat_ctrl_and_ibat_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_bat_ctrl_and_ibat_fops = {
+	.open = ab8540_gpadc_bat_ctrl_and_ibat_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_meas_and_ibat_print(struct seq_file *s, void *p)
+{
+	int vbat_meas_raw;
+	int vbat_meas_convert;
+	int ibat_raw;
+	int ibat_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	vbat_meas_raw = ab8500_gpadc_double_read_raw(gpadc, VBAT_MEAS_AND_IBAT,
+		avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+	vbat_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
+		vbat_meas_raw);
+	ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+		ibat_raw);
+
+	return seq_printf(s, "%d,0x%X\n"  "%d,0x%X\n",
+			vbat_meas_convert, vbat_meas_raw,
+			ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_vbat_meas_and_ibat_open(struct inode *inode,
+		struct file *file)
+{
+	return single_open(file, ab8540_gpadc_vbat_meas_and_ibat_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_meas_and_ibat_fops = {
+	.open = ab8540_gpadc_vbat_meas_and_ibat_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_vbat_true_meas_and_ibat_print(struct seq_file *s, void *p)
+{
+	int vbat_true_meas_raw;
+	int vbat_true_meas_convert;
+	int ibat_raw;
+	int ibat_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	vbat_true_meas_raw = ab8500_gpadc_double_read_raw(gpadc,
+			VBAT_TRUE_MEAS_AND_IBAT, avg_sample, trig_edge,
+			trig_timer, conv_type, &ibat_raw);
+	vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc,
+			VBAT_TRUE_MEAS, vbat_true_meas_raw);
+	ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+		ibat_raw);
+
+	return seq_printf(s, "%d,0x%X\n"  "%d,0x%X\n",
+			vbat_true_meas_convert, vbat_true_meas_raw,
+			ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_vbat_true_meas_and_ibat_open(struct inode *inode,
+		struct file *file)
+{
+	return single_open(file, ab8540_gpadc_vbat_true_meas_and_ibat_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_vbat_true_meas_and_ibat_fops = {
+	.open = ab8540_gpadc_vbat_true_meas_and_ibat_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_bat_temp_and_ibat_print(struct seq_file *s, void *p)
+{
+	int bat_temp_raw;
+	int bat_temp_convert;
+	int ibat_raw;
+	int ibat_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	bat_temp_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_TEMP_AND_IBAT,
+		avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
+	bat_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
+		bat_temp_raw);
+	ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
+		ibat_raw);
+
+	return seq_printf(s, "%d,0x%X\n"  "%d,0x%X\n",
+			bat_temp_convert, bat_temp_raw,
+			ibat_convert, ibat_raw);
+}
+
+static int ab8540_gpadc_bat_temp_and_ibat_open(struct inode *inode,
+		struct file *file)
+{
+	return single_open(file, ab8540_gpadc_bat_temp_and_ibat_print,
+			inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_bat_temp_and_ibat_fops = {
+	.open = ab8540_gpadc_bat_temp_and_ibat_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int ab8540_gpadc_otp_cal_print(struct seq_file *s, void *p)
+{
+	struct ab8500_gpadc *gpadc;
+	u16 vmain_l, vmain_h, btemp_l, btemp_h;
+	u16 vbat_l, vbat_h, ibat_l, ibat_h;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	ab8540_gpadc_get_otp(gpadc, &vmain_l, &vmain_h, &btemp_l, &btemp_h,
+			&vbat_l, &vbat_h, &ibat_l, &ibat_h);
+	return seq_printf(s, "VMAIN_L:0x%X\n"
+			"VMAIN_H:0x%X\n"
+			"BTEMP_L:0x%X\n"
+			"BTEMP_H:0x%X\n"
+			"VBAT_L:0x%X\n"
+			"VBAT_H:0x%X\n"
+			"IBAT_L:0x%X\n"
+			"IBAT_H:0x%X\n"
+			,
+			vmain_l,
+			vmain_h,
+			btemp_l,
+			btemp_h,
+			vbat_l,
+			vbat_h,
+			ibat_l,
+			ibat_h);
+}
+
+static int ab8540_gpadc_otp_cal_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8540_gpadc_otp_cal_print, inode->i_private);
+}
+
+static const struct file_operations ab8540_gpadc_otp_calib_fops = {
+	.open = ab8540_gpadc_otp_cal_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p)
 {
 	return seq_printf(s, "%d\n", avg_sample);
@@ -2385,7 +2633,43 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
 	if (!file)
 		goto err;
-
+	if (is_ab8540(ab8500)) {
+		file = debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUGO),
+		    ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_xtal_temp_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUGO),
+		    ab8500_gpadc_dir, &plf->dev,
+		    &ab8540_gpadc_vbat_true_meas_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("batctrl_and_ibat",
+				(S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+				&plf->dev, &ab8540_gpadc_bat_ctrl_and_ibat_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("vbatmeas_and_ibat",
+				(S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+				&plf->dev,
+				&ab8540_gpadc_vbat_meas_and_ibat_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("vbattruemeas_and_ibat",
+				(S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+				&plf->dev,
+				&ab8540_gpadc_vbat_true_meas_and_ibat_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("battemp_and_ibat",
+				(S_IRUGO | S_IWUGO), ab8500_gpadc_dir,
+				&plf->dev, &ab8540_gpadc_bat_temp_and_ibat_fops);
+		if (!file)
+			goto err;
+		file = debugfs_create_file("otp_calib", (S_IRUGO | S_IWUGO),
+		    ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_otp_calib_fops);
+		if (!file)
+			goto err;
+	}
 	file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUGO),
 		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_avg_sample_fops);
 	if (!file)
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index f3712d8..e6fc511 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -135,6 +135,8 @@ enum cal_channels {
 struct adc_cal_data {
 	s64 gain;
 	s64 offset;
+	u16 otp_calib_hi;
+	u16 otp_calib_lo;
 };
 
 /**
@@ -832,6 +834,12 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 			vmain_high = (((gpadc_cal[1] & 0xFF) << 2) |
 				((gpadc_cal[2] & 0xC0) >> 6));
 			vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
+
+			gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi =
+				(u16)vmain_high;
+			gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo =
+				(u16)vmain_low;
+
 			gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
 				(19500 - 315) / (vmain_high - vmain_low);
 			gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE *
@@ -859,6 +867,11 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 			ibat_low = (((gpadc_otp4[1] & 0x01) << 5) |
 				((gpadc_otp4[2] & 0xF8) >> 3));
 
+			gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi =
+				(u16)ibat_high;
+			gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo =
+				(u16)ibat_low;
+
 			V_gain = ((IBAT_VDROP_H - IBAT_VDROP_L)
 				<< CALIB_SHIFT_IBAT) / (ibat_high - ibat_low);
 
@@ -895,6 +908,11 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 				((gpadc_cal[2] & 0xC0) >> 6));
 			vmain_low = ((gpadc_cal[2] & 0x3E) >> 1);
 
+			gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi =
+				(u16)vmain_high;
+			gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo =
+				(u16)vmain_low;
+
 			gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE *
 				(19500 - 315) / (vmain_high - vmain_low);
 
@@ -905,12 +923,16 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 			gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0;
 		}
 	}
+
 	/* Calculate gain and offset for BTEMP if all reads succeeded */
 	if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) {
 		btemp_high = (((gpadc_cal[2] & 0x01) << 9) |
 			(gpadc_cal[3] << 1) | ((gpadc_cal[4] & 0x80) >> 7));
 		btemp_low = ((gpadc_cal[4] & 0x7C) >> 2);
 
+		gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi = (u16)btemp_high;
+		gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo = (u16)btemp_low;
+
 		gpadc->cal_data[ADC_INPUT_BTEMP].gain =
 			CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low);
 		gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 -
@@ -925,6 +947,9 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
 		vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]);
 		vbat_low = ((gpadc_cal[6] & 0xFC) >> 2);
 
+		gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi = (u16)vbat_high;
+		gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo = (u16)vbat_low;
+
 		gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE *
 			(4700 - 2380) /	(vbat_high - vbat_low);
 		gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 -
@@ -1136,6 +1161,25 @@ static void __exit ab8500_gpadc_exit(void)
 	platform_driver_unregister(&ab8500_gpadc_driver);
 }
 
+/**
+ * ab8540_gpadc_get_otp() - returns OTP values
+ *
+ */
+void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
+			u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
+			u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h)
+{
+	*vmain_l = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo;
+	*vmain_h = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi;
+	*btemp_l = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo;
+	*btemp_h = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi;
+	*vbat_l = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo;
+	*vbat_h = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi;
+	*ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo;
+	*ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi;
+	return ;
+}
+
 subsys_initcall_sync(ab8500_gpadc_init);
 module_exit(ab8500_gpadc_exit);
 
diff --git a/include/linux/mfd/abx500/ab8500-gpadc.h b/include/linux/mfd/abx500/ab8500-gpadc.h
index 4131437..49ded00 100644
--- a/include/linux/mfd/abx500/ab8500-gpadc.h
+++ b/include/linux/mfd/abx500/ab8500-gpadc.h
@@ -68,5 +68,8 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 		int *ibat);
 int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
 		u8 channel, int ad_value);
+void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
+			u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
+			u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h);
 
 #endif /* _AB8500_GPADC_H */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 23/35] mfd: ab8500-gpadc: Optimise GPADC driver
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (21 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 22/35] mfd: ab8500-debug: " Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration Lee Jones
                   ` (11 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Optimise GPADC driver:
 * for code readability and maintenance by grouping similar cheking
 * for performance by grouping several writing to control register

Signed-off-by: Alexandre Bourdiol <alexandre.bourdiol@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
---
 drivers/mfd/ab8500-gpadc.c |  212 ++++++++++++--------------------------------
 1 file changed, 55 insertions(+), 157 deletions(-)

diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index e6fc511..4e668f0 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -363,7 +363,12 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 {
 	int ret;
 	int looplimit = 0;
+	unsigned long completion_timeout;
 	u8 val, low_data, high_data, low_data2, high_data2;
+	u8 val_reg1 = 0;
+	unsigned int delay_min = 0;
+	unsigned int delay_max = 0;
+	u8 data_low_addr, data_high_addr;
 
 	if (!gpadc)
 		return -ENODEV;
@@ -395,12 +400,7 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 	}
 
 	/* Enable GPADC */
-	ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
-		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_GPADC, EN_GPADC);
-	if (ret < 0) {
-		dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
-		goto out;
-	}
+	val_reg1 |= EN_GPADC;
 
 	/* Select the channel source and set average samples */
 	switch (avg_sample) {
@@ -418,9 +418,13 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 		break;
 	}
 
-	if (conv_type == ADC_HW)
+	if (conv_type == ADC_HW) {
 		ret = abx500_set_register_interruptible(gpadc->dev,
 				AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val);
+		val_reg1 |= EN_TRIG_EDGE;
+		if (trig_edge)
+			val_reg1 |= EN_FALLING;
+	}
 	else
 		ret = abx500_set_register_interruptible(gpadc->dev,
 				AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val);
@@ -435,123 +439,42 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 	 * charging current sense if it needed, ABB 3.0 needs some special
 	 * treatment too.
 	 */
-	if ((conv_type == ADC_HW) && (trig_edge)) {
-		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-			EN_FALLING, EN_FALLING);
-	}
-
 	switch (channel) {
 	case MAIN_CHARGER_C:
 	case USB_CHARGER_C:
-		if (conv_type == ADC_HW)
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF | EN_ICHAR | EN_TRIG_EDGE,
-				EN_BUF | EN_ICHAR | EN_TRIG_EDGE);
-		else
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF | EN_ICHAR,
-				EN_BUF | EN_ICHAR);
-		break;
-
-	case XTAL_TEMP:
-		if (conv_type == ADC_HW)
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF  | EN_TRIG_EDGE,
-				EN_BUF  | EN_TRIG_EDGE);
-		else
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF ,
-				EN_BUF);
-		break;
-
-	case VBAT_TRUE_MEAS:
-		if (conv_type == ADC_HW)
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF  | EN_TRIG_EDGE,
-				EN_BUF  | EN_TRIG_EDGE);
-		else
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF ,
-				EN_BUF);
-		break;
-
-	case BAT_CTRL_AND_IBAT:
-	case VBAT_MEAS_AND_IBAT:
-	case VBAT_TRUE_MEAS_AND_IBAT:
-	case BAT_TEMP_AND_IBAT:
-		if (conv_type == ADC_HW)
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_TRIG_EDGE,
-				EN_TRIG_EDGE);
-		else
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF,
-				0);
+		val_reg1 |= EN_BUF | EN_ICHAR;
 		break;
-
 	case BTEMP_BALL:
 		if (!is_ab8500_2p0_or_earlier(gpadc->parent)) {
-			if (conv_type == ADC_HW)
-				/* Turn on btemp pull-up on ABB 3.0 */
-				ret = abx500_mask_and_set_register_interruptible
-					(gpadc->dev,
-					AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-					EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE,
-					EN_BUF | BTEMP_PULL_UP | EN_TRIG_EDGE);
-			else
-				ret = abx500_mask_and_set_register_interruptible
-					(gpadc->dev,
-					AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-					EN_BUF | BTEMP_PULL_UP,
-					EN_BUF | BTEMP_PULL_UP);
-
-		 /*
-		  * Delay might be needed for ABB8500 cut 3.0, if not, remove
-		  * when hardware will be available
-		  */
-			usleep_range(1000, 1000);
+			val_reg1 |= EN_BUF | BTEMP_PULL_UP;
+			/*
+			* Delay might be needed for ABB8500 cut 3.0, if not,
+			* remove when hardware will be availible
+			*/
+			delay_min = 1000; /* Delay in micro seconds */
+			delay_max = 10000; /* large range to optimise sleep mode */
 			break;
 		}
 		/* Intentional fallthrough */
 	default:
-		if (conv_type == ADC_HW)
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
-				EN_BUF | EN_TRIG_EDGE,
-				EN_BUF | EN_TRIG_EDGE);
-		else
-			ret = abx500_mask_and_set_register_interruptible(
-				gpadc->dev,
-				AB8500_GPADC,
-				AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
+		val_reg1 |= EN_BUF;
 		break;
 	}
+
+	/* Write configuration to register */
+	ret = abx500_set_register_interruptible(gpadc->dev,
+		AB8500_GPADC, AB8500_GPADC_CTRL1_REG, val_reg1);
 	if (ret < 0) {
 		dev_err(gpadc->dev,
-			"gpadc_conversion: select falling edge failed\n");
+			"gpadc_conversion: set Control register failed\n");
 		goto out;
 	}
 
-	/* Set trigger delay timer */
+	if (delay_min != 0)
+		usleep_range(delay_min, delay_max);
+
 	if (conv_type == ADC_HW) {
+		/* Set trigger delay timer */
 		ret = abx500_set_register_interruptible(gpadc->dev,
 			AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer);
 		if (ret < 0) {
@@ -559,10 +482,11 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 				"gpadc_conversion: trig timer failed\n");
 			goto out;
 		}
-	}
-
-	/* Start SW conversion */
-	if (conv_type == ADC_SW) {
+		completion_timeout = 2 * HZ;
+		data_low_addr = AB8500_GPADC_AUTODATAL_REG;
+		data_high_addr = AB8500_GPADC_AUTODATAH_REG;
+	} else {
+		/* Start SW conversion */
 		ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
 			AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
 			ADC_SW_CONV, ADC_SW_CONV);
@@ -571,61 +495,35 @@ int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
 				"gpadc_conversion: start s/w conv failed\n");
 			goto out;
 		}
+		completion_timeout = msecs_to_jiffies(CONVERSION_TIME);
+		data_low_addr = AB8500_GPADC_MANDATAL_REG;
+		data_high_addr = AB8500_GPADC_MANDATAH_REG;
 	}
 
 	/* wait for completion of conversion */
-	if (conv_type == ADC_HW) {
-		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
-				2 * HZ)) {
-			dev_err(gpadc->dev,
-				"timeout didn't receive hw GPADC conv interrupt\n");
-			ret = -EINVAL;
-			goto out;
-		}
-	} else {
-		if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
-				msecs_to_jiffies(CONVERSION_TIME))) {
-			dev_err(gpadc->dev,
-				"timeout didn't receive sw GPADC conv interrupt\n");
-			ret = -EINVAL;
-			goto out;
-		}
+	if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete,
+			completion_timeout)) {
+		dev_err(gpadc->dev,
+			"timeout didn't receive GPADC conv interrupt\n");
+		ret = -EINVAL;
+		goto out;
 	}
 
 	/* Read the converted RAW data */
-	if (conv_type == ADC_HW) {
-		ret = abx500_get_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_AUTODATAL_REG, &low_data);
-		if (ret < 0) {
-			dev_err(gpadc->dev,
-				"gpadc_conversion: read hw low data failed\n");
-			goto out;
-		}
-
-		ret = abx500_get_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_AUTODATAH_REG, &high_data);
-		if (ret < 0) {
-			dev_err(gpadc->dev,
-				"gpadc_conversion: read hw high data failed\n");
-			goto out;
-		}
-	} else {
-		ret = abx500_get_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_MANDATAL_REG, &low_data);
-		if (ret < 0) {
-			dev_err(gpadc->dev,
-				"gpadc_conversion: read sw low data failed\n");
-			goto out;
-		}
+	ret = abx500_get_register_interruptible(gpadc->dev,
+			AB8500_GPADC, data_low_addr, &low_data);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n");
+		goto out;
+	}
 
-		ret = abx500_get_register_interruptible(gpadc->dev,
-			AB8500_GPADC, AB8500_GPADC_MANDATAH_REG, &high_data);
-		if (ret < 0) {
-			dev_err(gpadc->dev,
-				"gpadc_conversion: read sw high data failed\n");
-			goto out;
-		}
+	ret = abx500_get_register_interruptible(gpadc->dev,
+		AB8500_GPADC, data_high_addr, &high_data);
+	if (ret < 0) {
+		dev_err(gpadc->dev, "gpadc_conversion: read high data failed\n");
+		goto out;
 	}
+
 	/* Check if double convertion is required */
 	if ((channel == BAT_CTRL_AND_IBAT) ||
 			(channel == VBAT_MEAS_AND_IBAT) ||
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (22 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 23/35] mfd: ab8500-gpadc: Optimise GPADC driver Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-25 14:33   ` Arnd Bergmann
  2013-02-15 12:56 ` [PATCH 25/35] mfd: ab8500-core: Add additional resources to ab8505_iddet_resources Lee Jones
                   ` (10 subsequent siblings)
  34 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

A recent patch saw the device.h include being removed from some other
include files and replaced with a 'struct device' declaration instead.
However, neither the include nor the declaration is actually required.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/abx500.h |    2 --
 1 file changed, 2 deletions(-)

diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index bd480b2..cb3288b 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -13,8 +13,6 @@
 
 #include <linux/regulator/machine.h>
 
-struct device;
-
 #ifndef MFD_ABX500_H
 #define MFD_ABX500_H
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 25/35] mfd: ab8500-core: Add additional resources to ab8505_iddet_resources
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (23 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 26/35] mfd: ab8500-sysctrl: AB8505 doesn't have SYSCLKREQ5..8 Lee Jones
                   ` (9 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

Add VBUS_DET_R, VBUS_DET_F IRQ, ID_DET_PLUGR and ID_DET_PLUGF IRQ
information to ab8505_iddet_resources. These are required to get
interrupts for AB8505 cut-2.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-core.c         |   24 ++++++++++++++++++++++++
 include/linux/mfd/abx500/ab8500.h |    2 ++
 2 files changed, 26 insertions(+)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index bbbd6e4..17187c3 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -963,6 +963,30 @@ static struct resource ab8505_iddet_resources[] = {
 		.end   = AB8505_INT_KEYSTUCK,
 		.flags = IORESOURCE_IRQ,
 	},
+	{
+		.name = "VBUS_DET_R",
+		.start = AB8500_INT_VBUS_DET_R,
+		.end = AB8500_INT_VBUS_DET_R,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "VBUS_DET_F",
+		.start = AB8500_INT_VBUS_DET_F,
+		.end = AB8500_INT_VBUS_DET_F,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "ID_DET_PLUGR",
+		.start = AB8500_INT_ID_DET_PLUGR,
+		.end = AB8500_INT_ID_DET_PLUGR,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "ID_DET_PLUGF",
+		.start = AB8500_INT_ID_DET_PLUGF,
+		.end = AB8500_INT_ID_DET_PLUGF,
+		.flags = IORESOURCE_IRQ,
+	},
 };
 
 static struct resource ab8500_temp_resources[] = {
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 3e9131f..46418f3 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -163,12 +163,14 @@ enum ab8500_version {
 #define AB8500_INT_SRP_DETECT		88
 #define AB8500_INT_USB_CHARGER_NOT_OKR	89
 #define AB8500_INT_ID_WAKEUP_R		90
+#define AB8500_INT_ID_DET_PLUGR		91 /* 8505/9540 cut2.0 */
 #define AB8500_INT_ID_DET_R1R		92
 #define AB8500_INT_ID_DET_R2R		93
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R4R		95
 /* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
 #define AB8500_INT_ID_WAKEUP_F		96 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_PLUGF		97 /* 8505/9540 cut2.0 */
 #define AB8500_INT_ID_DET_R1F		98 /* not 8505/9540 */
 #define AB8500_INT_ID_DET_R2F		99 /* not 8505/9540 */
 #define AB8500_INT_ID_DET_R3F		100 /* not 8505/9540 */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 26/35] mfd: ab8500-sysctrl: AB8505 doesn't have SYSCLKREQ5..8
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (24 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 25/35] mfd: ab8500-core: Add additional resources to ab8505_iddet_resources Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 27/35] mfd: ab8500-debugfs: Dump sim registers Lee Jones
                   ` (8 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rabin Vincent <rabin.vincent@stericsson.com>

So we're removing support for it.

Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Tested-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
---
 drivers/mfd/ab8500-sysctrl.c |   37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index f43c42b..272479c 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -182,9 +182,9 @@ EXPORT_SYMBOL(ab8500_sysctrl_write);
 
 static int ab8500_sysctrl_probe(struct platform_device *pdev)
 {
+	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
 	struct ab8500_platform_data *plat;
 	struct ab8500_sysctrl_platform_data *pdata;
-	int ret, i, j;
 
 	plat = dev_get_platdata(pdev->dev.parent);
 
@@ -196,20 +196,27 @@ static int ab8500_sysctrl_probe(struct platform_device *pdev)
 
 	pdata = plat->sysctrl;
 
-
-	for (i = AB8500_SYSCLKREQ1RFCLKBUF;
-	     i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
-		j = i - AB8500_SYSCLKREQ1RFCLKBUF;
-		ret = ab8500_sysctrl_write(i, 0xff,
-				pdata->initial_req_buf_config[j]);
-		dev_dbg(&pdev->dev,
-				"Setting SysClkReq%dRfClkBuf 0x%X\n",
-				j + 1,
-				pdata->initial_req_buf_config[j]);
-		if (ret < 0) {
-			dev_err(&pdev->dev,
-				"unable to set sysClkReq%dRfClkBuf: "
-				"%d\n", j + 1, ret);
+	if (pdata) {
+		int last, ret, i, j;
+
+		if (is_ab8505(ab8500))
+			last = AB8500_SYSCLKREQ4RFCLKBUF;
+		else
+			last = AB8500_SYSCLKREQ8RFCLKBUF;
+
+		for (i = AB8500_SYSCLKREQ1RFCLKBUF; i <= last; i++) {
+			j = i - AB8500_SYSCLKREQ1RFCLKBUF;
+			ret = ab8500_sysctrl_write(i, 0xff,
+					pdata->initial_req_buf_config[j]);
+			dev_dbg(&pdev->dev,
+					"Setting SysClkReq%dRfClkBuf 0x%X\n",
+					j + 1,
+					pdata->initial_req_buf_config[j]);
+			if (ret < 0) {
+				dev_err(&pdev->dev,
+					"unable to set sysClkReq%dRfClkBuf: "
+					"%d\n", j + 1, ret);
+			}
 		}
 	}
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 27/35] mfd: ab8500-debugfs: Dump sim registers
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (25 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 26/35] mfd: ab8500-sysctrl: AB8505 doesn't have SYSCLKREQ5..8 Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:56 ` [PATCH 28/35] mfd: ab8500-debug: Add ADC input channel usb_id in debugfs Lee Jones
                   ` (7 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mattias Wallin <mattias.wallin@stericsson.com>

This patch allows to dump the SIM registers from debugfs. It will
temporary change the config to allow APE side to read the SIM registers.
Note that this read can cause problem on modem side since the modem
can't read these registers while the operation is ongoing.

Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   78 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 7173406..a301f10 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -1243,6 +1243,79 @@ static int ab8500_hwreg_open(struct inode *inode, struct file *file)
 	return single_open(file, ab8500_hwreg_print, inode->i_private);
 }
 
+#define AB8500_SUPPLY_CONTROL_CONFIG_1 0x01
+#define AB8500_SUPPLY_CONTROL_REG 0x00
+#define AB8500_FIRST_SIM_REG 0x80
+#define AB8500_LAST_SIM_REG 0x8B
+#define AB8505_LAST_SIM_REG 0x8C
+
+static int ab8500_print_modem_registers(struct seq_file *s, void *p)
+{
+	struct device *dev = s->private;
+	struct ab8500 *ab8500;
+	int err;
+	u8 value;
+	u8 orig_value;
+	u32 bank = AB8500_REGU_CTRL2;
+	u32 last_sim_reg = AB8500_LAST_SIM_REG;
+	u32 reg;
+
+	ab8500 = dev_get_drvdata(dev->parent);
+	dev_warn(dev, "WARNING! This operation can interfer with modem side\n"
+		"and should only be done with care\n");
+
+	err = abx500_get_register_interruptible(dev,
+		AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, &orig_value);
+	if (err < 0) {
+		dev_err(dev, "ab->read fail %d\n", err);
+		return err;
+	}
+	/* Config 1 will allow APE side to read SIM registers */
+	err = abx500_set_register_interruptible(dev,
+		AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG,
+		AB8500_SUPPLY_CONTROL_CONFIG_1);
+	if (err < 0) {
+		dev_err(dev, "ab->write fail %d\n", err);
+		return err;
+	}
+
+	seq_printf(s, " bank 0x%02X:\n", bank);
+
+	if (is_ab9540(ab8500) || is_ab8505(ab8500))
+		last_sim_reg = AB8505_LAST_SIM_REG;
+
+	for (reg = AB8500_FIRST_SIM_REG; reg <= last_sim_reg; reg++) {
+		err = abx500_get_register_interruptible(dev,
+			bank, reg, &value);
+		if (err < 0) {
+			dev_err(dev, "ab->read fail %d\n", err);
+			return err;
+		}
+		err = seq_printf(s, "  [0x%02X/0x%02X]: 0x%02X\n",
+			bank, reg, value);
+	}
+	err = abx500_set_register_interruptible(dev,
+		AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, orig_value);
+	if (err < 0) {
+		dev_err(dev, "ab->write fail %d\n", err);
+		return err;
+	}
+	return 0;
+}
+
+static int ab8500_modem_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_print_modem_registers, inode->i_private);
+}
+
+static const struct file_operations ab8500_modem_fops = {
+	.open = ab8500_modem_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p)
 {
 	int bat_ctrl_raw;
@@ -2569,6 +2642,11 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	if (!file)
 		goto err;
 
+	file = debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUGO),
+	    ab8500_dir, &plf->dev, &ab8500_modem_fops);
+	if (!file)
+		goto err;
+
 	file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
 	if (!file)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 28/35] mfd: ab8500-debug: Add ADC input channel usb_id in debugfs
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (26 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 27/35] mfd: ab8500-debugfs: Dump sim registers Lee Jones
@ 2013-02-15 12:56 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 29/35] mfd: ab8500-core: Show turn on status at boot Lee Jones
                   ` (6 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:56 UTC (permalink / raw)
  To: linux-arm-kernel

From: Yang QU <yang.qu@stericsson.com>

Signed-off-by: Yang QU <yang.qu@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Alexandre BOURDIOL <alexandre.bourdiol@stericsson.com>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Reviewed-by: Mattias WALLIN <mattias.wallin@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index a301f10..ae8660a 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -1705,6 +1705,35 @@ static const struct file_operations ab8500_gpadc_die_temp_fops = {
 	.owner = THIS_MODULE,
 };
 
+static int ab8500_gpadc_usb_id_print(struct seq_file *s, void *p)
+{
+	int usb_id_raw;
+	int usb_id_convert;
+	struct ab8500_gpadc *gpadc;
+
+	gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
+	usb_id_raw = ab8500_gpadc_read_raw(gpadc, USB_ID,
+		avg_sample, trig_edge, trig_timer, conv_type);
+	usb_id_convert = ab8500_gpadc_ad_to_voltage(gpadc, USB_ID,
+		usb_id_raw);
+
+	return seq_printf(s, "%d,0x%X\n",
+			usb_id_convert, usb_id_raw);
+}
+
+static int ab8500_gpadc_usb_id_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, ab8500_gpadc_usb_id_print, inode->i_private);
+}
+
+static const struct file_operations ab8500_gpadc_usb_id_fops = {
+	.open = ab8500_gpadc_usb_id_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 static int ab8540_gpadc_xtal_temp_print(struct seq_file *s, void *p)
 {
 	int xtal_temp_raw;
@@ -2711,6 +2740,12 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
 	if (!file)
 		goto err;
+
+	file = debugfs_create_file("usb_id", (S_IRUGO | S_IWUGO),
+	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_id_fops);
+	if (!file)
+		goto err;
+
 	if (is_ab8540(ab8500)) {
 		file = debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUGO),
 		    ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_xtal_temp_fops);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 29/35] mfd: ab8500-core: Show turn on status at boot
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (27 preceding siblings ...)
  2013-02-15 12:56 ` [PATCH 28/35] mfd: ab8500-debug: Add ADC input channel usb_id in debugfs Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 30/35] mfd: ab8500-debugfs: Change AB8500 debug permissions Lee Jones
                   ` (5 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mattias Wallin <mattias.wallin@stericsson.com>

Several states can be detected when a device is initially turned on.
This patch displays these states in the log. If none of the states
are true, then we report that too.

Signed-off-by: Mattias Wallin <mattias.wallin@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Marcus COOPER <marcus.xm.cooper@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
 drivers/mfd/ab8500-core.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 17187c3..153e71e 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1502,6 +1502,15 @@ static int ab8500_probe(struct platform_device *pdev)
 		"Battery level lower than power on reset threshold",
 		"Power on key 1 pressed longer than 10 seconds",
 		"DB8500 thermal shutdown"};
+	static char *turn_on_status[] = {
+		"Battery rising (Vbat)",
+		"Power On Key 1 dbF",
+		"Power On Key 2 dbF",
+		"RTC Alarm",
+		"Main Charger Detect",
+		"Vbus Detect (USB)",
+		"USB ID Detect",
+		"UART Factory Mode Detect"};
 	struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
 	const struct platform_device_id *platid = platform_get_device_id(pdev);
 	enum ab8500_version version = AB8500_VERSION_UNDEFINED;
@@ -1615,9 +1624,26 @@ static int ab8500_probe(struct platform_device *pdev)
 	} else {
 		printk(KERN_CONT " None\n");
 	}
+	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
+		AB8500_TURN_ON_STATUS, &value);
+	if (ret < 0)
+		return ret;
+	dev_info(ab8500->dev, "turn on reason(s) (%#x): ", value);
+
+	if (value) {
+		for (i = 0; i < ARRAY_SIZE(turn_on_status); i++) {
+			if (value & 1)
+				printk("\"%s\" ", turn_on_status[i]);
+			value = value >> 1;
+		}
+		printk("\n");
+	} else {
+		printk("None\n");
+	}
 
 	if (plat && plat->init)
 		plat->init(ab8500);
+
 	if (is_ab9540(ab8500)) {
 		ret = get_register_interruptible(ab8500, AB8500_CHARGER,
 			AB8500_CH_USBCH_STAT1_REG, &value);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 30/35] mfd: ab8500-debugfs: Change AB8500 debug permissions
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (28 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 29/35] mfd: ab8500-core: Show turn on status at boot Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 31/35] mfd: ab8500-debug: Add register map for ab8540 Lee Jones
                   ` (4 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Mattias Thor?n <mattias.thoren@stericsson.com>

Enable group write permissions for ab8500 debug MFD driver.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-debugfs.c |   56 +++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index ae8660a..148cbd2 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -2622,22 +2622,22 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_bank_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("register-address", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_address_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("register-value", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_val_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_subscribe_fops);
 	if (!file)
 		goto err;
@@ -2661,97 +2661,97 @@ static int ab8500_debug_probe(struct platform_device *plf)
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_hwreg_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_dir, &plf->dev, &ab8500_modem_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bat_ctrl_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_btemp_ball_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_v_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect1_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_acc_detect2_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux1_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_aux2_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_bat_v_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_vbus_v_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_main_charger_c_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_charger_c_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_bk_bat_v_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR),
+	file = debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_die_temp_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("usb_id", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP),
 	    ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_usb_id_fops);
 	if (!file)
 		goto err;
 
 	if (is_ab8540(ab8500)) {
-		file = debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUGO),
+		file = debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
 		    ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_xtal_temp_fops);
 		if (!file)
 			goto err;
-		file = debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUGO),
+		file = debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP),
 		    ab8500_gpadc_dir, &plf->dev,
 		    &ab8540_gpadc_vbat_true_meas_fops);
 		if (!file)
@@ -2778,27 +2778,27 @@ static int ab8500_debug_probe(struct platform_device *plf)
 				&plf->dev, &ab8540_gpadc_bat_temp_and_ibat_fops);
 		if (!file)
 			goto err;
-		file = debugfs_create_file("otp_calib", (S_IRUGO | S_IWUGO),
+		file = debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP),
 		    ab8500_gpadc_dir, &plf->dev, &ab8540_gpadc_otp_calib_fops);
 		if (!file)
 			goto err;
 	}
-	file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP),
 		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_avg_sample_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("trig_edge", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP),
 		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_edge_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("trig_timer", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP),
 		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_trig_timer_fops);
 	if (!file)
 		goto err;
 
-	file = debugfs_create_file("conv_type", (S_IRUGO | S_IWUGO),
+	file = debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP),
 		ab8500_gpadc_dir, &plf->dev, &ab8500_gpadc_conv_type_fops);
 	if (!file)
 		goto err;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 31/35] mfd: ab8500-debug: Add register map for ab8540.
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (29 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 30/35] mfd: ab8500-debugfs: Change AB8500 debug permissions Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 32/35] mfd: ab8500-core: Add abx500-clk as an mfd child device Lee Jones
                   ` (3 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

Required to read out correct debug information from the AB chip.

Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/ab8500-debugfs.c      |  422 ++++++++++++++++++++++++++++++++++++-
 include/linux/mfd/abx500/ab8500.h |    1 +
 2 files changed, 420 insertions(+), 3 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 148cbd2..b5af8be 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -845,6 +845,422 @@ struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
 	},
 };
 
+struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = {
+	[AB8500_M_FSM_RANK] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x0B,
+			},
+		},
+	},
+	[AB8500_SYS_CTRL1_BLOCK] = {
+		.num_ranges = 6,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x04,
+			},
+			{
+				.first = 0x42,
+				.last = 0x42,
+			},
+			{
+				.first = 0x50,
+				.last = 0x54,
+			},
+			{
+				.first = 0x57,
+				.last = 0x57,
+			},
+			{
+				.first = 0x80,
+				.last = 0x83,
+			},
+			{
+				.first = 0x90,
+				.last = 0x90,
+			},
+		},
+	},
+	[AB8500_SYS_CTRL2_BLOCK] = {
+		.num_ranges = 5,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x0D,
+			},
+			{
+				.first = 0x0F,
+				.last = 0x10,
+			},
+			{
+				.first = 0x20,
+				.last = 0x21,
+			},
+			{
+				.first = 0x32,
+				.last = 0x3C,
+			},
+			{
+				.first = 0x40,
+				.last = 0x42,
+			},
+		},
+	},
+	[AB8500_REGU_CTRL1] = {
+		.num_ranges = 4,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x03,
+				.last = 0x15,
+			},
+			{
+				.first = 0x20,
+				.last = 0x20,
+			},
+			{
+				.first = 0x80,
+				.last = 0x85,
+			},
+			{
+				.first = 0x87,
+				.last = 0x88,
+			},
+		},
+	},
+	[AB8500_REGU_CTRL2] = {
+		.num_ranges = 8,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x06,
+			},
+			{
+				.first = 0x08,
+				.last = 0x15,
+			},
+			{
+				.first = 0x17,
+				.last = 0x19,
+			},
+			{
+				.first = 0x1B,
+				.last = 0x1D,
+			},
+			{
+				.first = 0x1F,
+				.last = 0x2F,
+			},
+			{
+				.first = 0x31,
+				.last = 0x3A,
+			},
+			{
+				.first = 0x43,
+				.last = 0x44,
+			},
+			{
+				.first = 0x48,
+				.last = 0x49,
+			},
+		},
+	},
+	[AB8500_USB] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x80,
+				.last = 0x83,
+			},
+			{
+				.first = 0x87,
+				.last = 0x8A,
+			},
+			{
+				.first = 0x91,
+				.last = 0x94,
+			},
+		},
+	},
+	[AB8500_TVOUT] = {
+		.num_ranges = 0,
+		.range = NULL
+	},
+	[AB8500_DBI] = {
+		.num_ranges = 4,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x07,
+			},
+			{
+				.first = 0x10,
+				.last = 0x11,
+			},
+			{
+				.first = 0x20,
+				.last = 0x21,
+			},
+			{
+				.first = 0x30,
+				.last = 0x43,
+			},
+		},
+	},
+	[AB8500_ECI_AV_ACC] = {
+		.num_ranges = 2,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x03,
+			},
+			{
+				.first = 0x80,
+				.last = 0x82,
+			},
+		},
+	},
+	[AB8500_RESERVED] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_GPADC] = {
+		.num_ranges = 4,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x01,
+			},
+			{
+				.first = 0x04,
+				.last = 0x06,
+			},
+			{
+				.first = 0x09,
+				.last = 0x0A,
+			},
+			{
+				.first = 0x10,
+				.last = 0x14,
+			},
+		},
+	},
+	[AB8500_CHARGER] = {
+		.num_ranges = 10,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x00,
+			},
+			{
+				.first = 0x02,
+				.last = 0x05,
+			},
+			{
+				.first = 0x40,
+				.last = 0x44,
+			},
+			{
+				.first = 0x50,
+				.last = 0x57,
+			},
+			{
+				.first = 0x60,
+				.last = 0x60,
+			},
+			{
+				.first = 0x70,
+				.last = 0x70,
+			},
+			{
+				.first = 0xA0,
+				.last = 0xA9,
+			},
+			{
+				.first = 0xAF,
+				.last = 0xB2,
+			},
+			{
+				.first = 0xC0,
+				.last = 0xC6,
+			},
+			{
+				.first = 0xF5,
+				.last = 0xF5,
+			},
+		},
+	},
+	[AB8500_GAS_GAUGE] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x00,
+			},
+			{
+				.first = 0x07,
+				.last = 0x0A,
+			},
+			{
+				.first = 0x10,
+				.last = 0x14,
+			},
+		},
+	},
+	[AB8500_AUDIO] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x9f,
+			},
+		},
+	},
+	[AB8500_INTERRUPT] = {
+		.num_ranges = 6,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x05,
+			},
+			{
+				.first = 0x0B,
+				.last = 0x0D,
+			},
+			{
+				.first = 0x12,
+				.last = 0x20,
+			},
+			/* Latch registers should not be read here */
+			{
+				.first = 0x40,
+				.last = 0x45,
+			},
+			{
+				.first = 0x4B,
+				.last = 0x4D,
+			},
+			{
+				.first = 0x52,
+				.last = 0x60,
+			},
+			/* LatchHier registers should not be read here */
+		},
+	},
+	[AB8500_RTC] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x07,
+			},
+			{
+				.first = 0x0B,
+				.last = 0x18,
+			},
+			{
+				.first = 0x20,
+				.last = 0x25,
+			},
+		},
+	},
+	[AB8500_MISC] = {
+		.num_ranges = 9,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x06,
+			},
+			{
+				.first = 0x10,
+				.last = 0x16,
+			},
+			{
+				.first = 0x20,
+				.last = 0x26,
+			},
+			{
+				.first = 0x30,
+				.last = 0x36,
+			},
+			{
+				.first = 0x40,
+				.last = 0x49,
+			},
+			{
+				.first = 0x50,
+				.last = 0x50,
+			},
+			{
+				.first = 0x60,
+				.last = 0x6B,
+			},
+			{
+				.first = 0x70,
+				.last = 0x74,
+			},
+			{
+				.first = 0x80,
+				.last = 0x82,
+			},
+		},
+	},
+	[AB8500_DEVELOPMENT] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x01,
+			},
+			{
+				.first = 0x06,
+				.last = 0x06,
+			},
+			{
+				.first = 0x10,
+				.last = 0x21,
+			},
+		},
+	},
+	[AB8500_DEBUG] = {
+		.num_ranges = 3,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x01,
+				.last = 0x0C,
+			},
+			{
+				.first = 0x0E,
+				.last = 0x11,
+			},
+			{
+				.first = 0x80,
+				.last = 0x81,
+			},
+		},
+	},
+	[AB8500_PROD_TEST] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_STE_TEST] = {
+		.num_ranges = 0,
+		.range = NULL,
+	},
+	[AB8500_OTP_EMUL] = {
+		.num_ranges = 1,
+		.range = (struct ab8500_reg_range[]) {
+			{
+				.first = 0x00,
+				.last = 0x3F,
+			},
+		},
+	},
+};
+
+
 static irqreturn_t ab8500_debug_handler(int irq, void *data)
 {
 	char buf[16];
@@ -936,7 +1352,7 @@ static int ab8500_print_all_banks(struct seq_file *s, void *p)
 
 	seq_printf(s, AB8500_NAME_STRING " register values:\n");
 
-	for (i = 1; i < AB8500_NUM_BANKS; i++) {
+	for (i = 0; i < AB8500_NUM_BANKS; i++) {
 		err = seq_printf(s, " bank 0x%02X:\n", i);
 
 		ab8500_registers_print(dev, i, s);
@@ -978,7 +1394,7 @@ void ab8500_dump_all_banks_to_mem(void)
 	pr_info("Saving all ABB registers@\"ab8500_complete_register_dump\" "
 		"for crash analyze.\n");
 
-	for (bank = 1; bank < AB8500_NUM_BANKS; bank++) {
+	for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
 		for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
 			u8 reg;
 
@@ -2652,7 +3068,7 @@ static int ab8500_debug_probe(struct platform_device *plf)
 		debug_ranges = ab8505_debug_ranges;
 		num_interrupt_lines = AB9540_NR_IRQS;
 	} else if (is_ab8540(ab8500)) {
-		debug_ranges = ab8505_debug_ranges;
+		debug_ranges = ab8540_debug_ranges;
 		num_interrupt_lines = AB8540_NR_IRQS;
 	}
 
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 46418f3..2b7ac84 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -40,6 +40,7 @@ enum ab8500_version {
 /*
  * AB8500 bank addresses
  */
+#define AB8500_M_FSM_RANK	0x0
 #define AB8500_SYS_CTRL1_BLOCK	0x1
 #define AB8500_SYS_CTRL2_BLOCK	0x2
 #define AB8500_REGU_CTRL1	0x3
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 32/35] mfd: ab8500-core: Add abx500-clk as an mfd child device
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (30 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 31/35] mfd: ab8500-debug: Add register map for ab8540 Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 33/35] mfd: ab8500-debug: Add explicit dependencies Lee Jones
                   ` (2 subsequent siblings)
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Ulf Hansson <ulf.hansson@stericsson.com>

Hierarchically, the abx500-clk shall be considered as a child of the
ab8500 core. The abx500-clk is intiated at arch init and thus the clks
will be available when clients needs them.

Signed-off-by: Ulf Hansson <ulf.hansson@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
Reviewed-by: Patrice CHOTARD <patrice.chotard@stericsson.com>
Reviewed-by: Gabriel FERNANDEZ <gabriel.fernandez@stericsson.com>
Reviewed-by: Philippe BEGNIC <philippe.begnic@stericsson.com>
---
 drivers/mfd/ab8500-core.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 153e71e..2716c6c 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -1144,6 +1144,10 @@ static struct mfd_cell ab9540_devs[] = {
 		.name = "ab8500-regulator",
 	},
 	{
+		.name = "abx500-clk",
+		.of_compatible = "stericsson,abx500-clk",
+	},
+	{
 		.name = "ab8500-gpadc",
 		.of_compatible = "stericsson,ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
@@ -1210,6 +1214,10 @@ static struct mfd_cell ab8505_devs[] = {
 		.name = "ab8500-regulator",
 	},
 	{
+		.name = "abx500-clk",
+		.of_compatible = "stericsson,abx500-clk",
+	},
+	{
 		.name = "ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
 		.resources = ab8505_gpadc_resources,
@@ -1269,6 +1277,10 @@ static struct mfd_cell ab8540_devs[] = {
 		.name = "ab8500-regulator",
 	},
 	{
+		.name = "abx500-clk",
+		.of_compatible = "stericsson,abx500-clk",
+	},
+	{
 		.name = "ab8500-gpadc",
 		.num_resources = ARRAY_SIZE(ab8505_gpadc_resources),
 		.resources = ab8505_gpadc_resources,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 33/35] mfd: ab8500-debug: Add explicit dependencies
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (31 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 32/35] mfd: ab8500-core: Add abx500-clk as an mfd child device Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 34/35] mfd: ab8500-debug: Convert to kstrtoul_from_user Lee Jones
  2013-02-15 12:57 ` [PATCH 35/35] mfd: ab8500-core: Hierarchical interrupt registers Lee Jones
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Linus Walleij <linus.walleij@stericsson.com>

As I am working on SPARSE_IRQ a number of implicit resource
grabs in the kernel become evident. For example, some includes
like <linux/irqs.h> would implicitly include <mach/irqs.h>
and then from there <mach/db8500-regs.h>.

In many cases it is masking the fact that drivers do not
properly use resources to pass their dependencies, base
addresses etc. So write explicit #include statements with
TODO items to have this fixed the proper way to all drivers
doing this.

Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index b5af8be..37f595d 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -90,6 +90,9 @@
 #include <linux/ctype.h>
 #endif
 
+/* TODO: this file should not reference IRQ_DB8500_AB8500! */
+#include <mach/irqs.h>
+
 static u32 debug_bank;
 static u32 debug_address;
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 34/35] mfd: ab8500-debug: Convert to kstrtoul_from_user
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (32 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 33/35] mfd: ab8500-debug: Add explicit dependencies Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  2013-02-15 12:57 ` [PATCH 35/35] mfd: ab8500-core: Hierarchical interrupt registers Lee Jones
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: srinidhi kasagar <srinidhi.kasagar@stericsson.com>

Use kstrtoul_from_user for getting an unsigned long from userspace
which is less error prone.

Signed-off-by: srinidhi kasagar <srinidhi.kasagar@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
---
 drivers/mfd/ab8500-debugfs.c |  100 +++++++++++++-----------------------------
 1 file changed, 30 insertions(+), 70 deletions(-)

diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 37f595d..8fdc3b1 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -1478,7 +1478,6 @@ static ssize_t ab8500_bank_write(struct file *file,
 	unsigned long user_bank;
 	int err;
 
-	/* Get userspace string and assure termination */
 	err = kstrtoul_from_user(user_buf, count, 0, &user_bank);
 	if (err)
 		return err;
@@ -1511,7 +1510,6 @@ static ssize_t ab8500_address_write(struct file *file,
 	unsigned long user_address;
 	int err;
 
-	/* Get userspace string and assure termination */
 	err = kstrtoul_from_user(user_buf, count, 0, &user_address);
 	if (err)
 		return err;
@@ -1521,6 +1519,7 @@ static ssize_t ab8500_address_write(struct file *file,
 		return -EINVAL;
 	}
 	debug_address = user_address;
+
 	return count;
 }
 
@@ -1555,7 +1554,6 @@ static ssize_t ab8500_val_write(struct file *file,
 	unsigned long user_val;
 	int err;
 
-	/* Get userspace string and assure termination */
 	err = kstrtoul_from_user(user_buf, count, 0, &user_val);
 	if (err)
 		return err;
@@ -2417,20 +2415,13 @@ static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
 	size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_avg_sample;
 	int err;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_avg_sample);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_avg_sample);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4)
 			|| (user_avg_sample == SAMPLE_8)
 			|| (user_avg_sample == SAMPLE_16)) {
@@ -2440,7 +2431,8 @@ static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
 			"should be egal to 1, 4, 8 or 16\n");
 		return -EINVAL;
 	}
-	return buf_size;
+
+	return count;
 }
 
 static const struct file_operations ab8500_gpadc_avg_sample_fops = {
@@ -2468,20 +2460,13 @@ static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
 	size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_trig_edge;
 	int err;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_trig_edge);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_trig_edge);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if ((user_trig_edge == RISING_EDGE)
 			|| (user_trig_edge == FALLING_EDGE)) {
 		trig_edge = (u8) user_trig_edge;
@@ -2491,7 +2476,8 @@ static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
 			"Enter 1. Falling edge\n");
 		return -EINVAL;
 	}
-	return buf_size;
+
+	return count;
 }
 
 static const struct file_operations ab8500_gpadc_trig_edge_fops = {
@@ -2519,20 +2505,13 @@ static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
 	size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_trig_timer;
 	int err;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_trig_timer);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_trig_timer);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if ((user_trig_timer >= 0) && (user_trig_timer <= 255)) {
 		trig_timer = (u8) user_trig_timer;
 	} else {
@@ -2540,7 +2519,8 @@ static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
 			"should be beetween 0 to 255\n");
 		return -EINVAL;
 	}
-	return buf_size;
+
+	return count;
 }
 
 static const struct file_operations ab8500_gpadc_trig_timer_fops = {
@@ -2568,20 +2548,13 @@ static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
 	size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_conv_type;
 	int err;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf) - 1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_conv_type);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_conv_type);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if ((user_conv_type == ADC_SW)
 			|| (user_conv_type == ADC_HW)) {
 		conv_type = (u8) user_conv_type;
@@ -2591,7 +2564,8 @@ static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
 			"Enter 1. ADC HW conversion\n");
 		return -EINVAL;
 	}
-	return buf_size;
+
+	return count;
 }
 
 static const struct file_operations ab8500_gpadc_conv_type_fops = {
@@ -2808,21 +2782,14 @@ static ssize_t ab8500_subscribe_write(struct file *file,
 				      size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_val;
 	int err;
 	unsigned int irq_index;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_val);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_val);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if (user_val < irq_first) {
 		dev_err(dev, "debugfs error input < %d\n", irq_first);
 		return -EINVAL;
@@ -2842,7 +2809,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
 	 */
 	dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
 		GFP_KERNEL);
-	event_name[irq_index] = kmalloc(buf_size, GFP_KERNEL);
+	event_name[irq_index] = kmalloc(count, GFP_KERNEL);
 	sprintf(event_name[irq_index], "%lu", user_val);
 	dev_attr[irq_index]->show = show_irq;
 	dev_attr[irq_index]->store = NULL;
@@ -2864,7 +2831,7 @@ static ssize_t ab8500_subscribe_write(struct file *file,
 		return err;
 	}
 
-	return buf_size;
+	return count;
 }
 
 static ssize_t ab8500_unsubscribe_write(struct file *file,
@@ -2872,21 +2839,14 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct device *dev = ((struct seq_file *)(file->private_data))->private;
-	char buf[32];
-	int buf_size;
 	unsigned long user_val;
 	int err;
 	unsigned int irq_index;
 
-	/* Get userspace string and assure termination */
-	buf_size = min(count, (sizeof(buf)-1));
-	if (copy_from_user(buf, user_buf, buf_size))
-		return -EFAULT;
-	buf[buf_size] = 0;
-
-	err = strict_strtoul(buf, 0, &user_val);
+	err = kstrtoul_from_user(user_buf, count, 0, &user_val);
 	if (err)
-		return -EINVAL;
+		return err;
+
 	if (user_val < irq_first) {
 		dev_err(dev, "debugfs error input < %d\n", irq_first);
 		return -EINVAL;
@@ -2911,7 +2871,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
 	kfree(event_name[irq_index]);
 	kfree(dev_attr[irq_index]);
 
-	return buf_size;
+	return count;
 }
 
 /*
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 35/35] mfd: ab8500-core: Hierarchical interrupt registers
  2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
                   ` (33 preceding siblings ...)
  2013-02-15 12:57 ` [PATCH 34/35] mfd: ab8500-debug: Convert to kstrtoul_from_user Lee Jones
@ 2013-02-15 12:57 ` Lee Jones
  34 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-15 12:57 UTC (permalink / raw)
  To: linux-arm-kernel

From: Dariusz Szymczak <dariusz.xd.szymczak@stericsson.com>

Make use of the hierarchical interrupt rergister called
ITLatchHier1 - 3 also for the 8500 platform (currently the
hierarchical interrupt registers are used only for the 8540
and 9540 platforms). This will make the interrupt routing
go faster since fewer i2c reads need to made in the most
common cases.

Signed-off-by: Dariusz Szymczak <dariusz.xd.szymczak@stericsson.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Reviewed-by: Mian Yousaf KAUKAB <mian.yousaf.kaukab@stericsson.com>
---
 drivers/mfd/ab8500-core.c |   82 ++++-----------------------------------------
 1 file changed, 6 insertions(+), 76 deletions(-)

diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 2716c6c..fd87e0a 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -502,66 +502,6 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
-/**
- * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
- *
- * @ab8500: ab8500_irq controller to operate on.
- * @irq: index of the interrupt requested in the chip IRQs
- *
- * Useful for drivers to request their own IRQs.
- */
-static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq)
-{
-	if (!ab8500)
-		return -EINVAL;
-
-	return irq_create_mapping(ab8500->domain, irq);
-}
-
-static irqreturn_t ab8500_irq(int irq, void *dev)
-{
-	struct ab8500 *ab8500 = dev;
-	int i;
-
-	dev_vdbg(ab8500->dev, "interrupt\n");
-
-	atomic_inc(&ab8500->transfer_ongoing);
-
-	for (i = 0; i < ab8500->mask_size; i++) {
-		int regoffset = ab8500->irq_reg_offset[i];
-		int status;
-		u8 value;
-
-		/*
-		 * Interrupt register 12 doesn't exist prior to AB8500 version
-		 * 2.0
-		 */
-		if (regoffset == 11 && is_ab8500_1p1_or_earlier(ab8500))
-			continue;
-
-		if (regoffset < 0)
-			continue;
-
-		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
-			AB8500_IT_LATCH1_REG + regoffset, &value);
-		if (status < 0 || value == 0)
-			continue;
-
-		do {
-			int bit = __ffs(value);
-			int line = i * 8 + bit;
-			int virq = ab8500_irq_get_virq(ab8500, line);
-
-			handle_nested_irq(virq);
-			ab8500_debug_register_interrupt(line);
-			value &= ~(1 << bit);
-
-		} while (value);
-	}
-	atomic_dec(&ab8500->transfer_ongoing);
-	return IRQ_HANDLED;
-}
-
 static int ab8500_irq_map(struct irq_domain *d, unsigned int virq,
 				irq_hw_number_t hwirq)
 {
@@ -1697,22 +1637,12 @@ static int ab8500_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	/*  Activate this feature only in ab9540 */
-	/*  till tests are done on ab8500 1p2 or later*/
-	if (is_ab9540(ab8500) || is_ab8540(ab8500))
-		ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
-						ab8500_hierarchical_irq,
-						IRQF_ONESHOT | IRQF_NO_SUSPEND,
-						"ab8500", ab8500);
-	}
-	else {
-		ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
-						ab8500_irq,
-						IRQF_ONESHOT | IRQF_NO_SUSPEND,
-						"ab8500", ab8500);
-		if (ret)
-			return ret;
-	}
+	ret = devm_request_threaded_irq(&pdev->dev, ab8500->irq, NULL,
+			ab8500_hierarchical_irq,
+			IRQF_ONESHOT | IRQF_NO_SUSPEND,
+			"ab8500", ab8500);
+	if (ret)
+		return ret;
 
 	if (is_ab9540(ab8500))
 		ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 54+ messages in thread

* [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification
  2013-02-15 12:56 ` [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification Lee Jones
@ 2013-02-19 22:04   ` Arnd Bergmann
  2013-02-20  8:13     ` Lee Jones
  0 siblings, 1 reply; 54+ messages in thread
From: Arnd Bergmann @ 2013-02-19 22:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 15 February 2013, Lee Jones wrote:
>         struct ab8500 *ab8500;
> +       int chip_id = -EINVAL;
>
>         ab8500 = dev_get_drvdata(dev);
> -       return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
> +       if(ab8500) {
> +               chip_id = ab8500->chip_id;
> +               if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
> +                       chip_id = (ab8500->version << 8) | chip_id;
> +       }
> +       return sprintf(buf, "%#x\n", chip_id);
>  }

What's the use of printing "ffffffea" for unknown versions here?

	Arnd

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures
  2013-02-15 12:56 ` [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures Lee Jones
@ 2013-02-19 22:07   ` Arnd Bergmann
  2013-02-20  8:09     ` Lee Jones
  0 siblings, 1 reply; 54+ messages in thread
From: Arnd Bergmann @ 2013-02-19 22:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 15 February 2013, Lee Jones wrote:
> +       {
> +               .name = "ab8500-charger",
> +               .of_compatible = "stericsson,ab8500-charger",
> +               .num_resources = ARRAY_SIZE(ab8500_charger_resources),
> +               .resources = ab8500_charger_resources,
> +#ifndef CONFIG_OF
> +               .platform_data = &ab8500_bm_data,
> +               .pdata_size = sizeof(ab8500_bm_data),
> +#endif
> +       },

Is this #ifdef correct? I would have expected "#ifdef CONFIG_ATAGS" here.

	Arnd

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures
  2013-02-19 22:07   ` Arnd Bergmann
@ 2013-02-20  8:09     ` Lee Jones
  0 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-20  8:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 19 Feb 2013, Arnd Bergmann wrote:

> On Friday 15 February 2013, Lee Jones wrote:
> > +       {
> > +               .name = "ab8500-charger",
> > +               .of_compatible = "stericsson,ab8500-charger",
> > +               .num_resources = ARRAY_SIZE(ab8500_charger_resources),
> > +               .resources = ab8500_charger_resources,
> > +#ifndef CONFIG_OF
> > +               .platform_data = &ab8500_bm_data,
> > +               .pdata_size = sizeof(ab8500_bm_data),
> > +#endif
> > +       },
> 
> Is this #ifdef correct? I would have expected "#ifdef CONFIG_ATAGS"
> here.

No, it's not correct. See: 23a04f9f40f2b32ee593b768483105b1c776814d

I will fixup when the branched is rebased post-merge.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification
  2013-02-19 22:04   ` Arnd Bergmann
@ 2013-02-20  8:13     ` Lee Jones
  2013-02-20  8:53       ` Marcus Cooper
  0 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-20  8:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 19 Feb 2013, Arnd Bergmann wrote:

> On Friday 15 February 2013, Lee Jones wrote:
> >         struct ab8500 *ab8500;
> > +       int chip_id = -EINVAL;
> >
> >         ab8500 = dev_get_drvdata(dev);
> > -       return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
> > +       if(ab8500) {
> > +               chip_id = ab8500->chip_id;
> > +               if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
> > +                       chip_id = (ab8500->version << 8) | chip_id;
> > +       }
> > +       return sprintf(buf, "%#x\n", chip_id);
> >  }
> 
> What's the use of printing "ffffffea" for unknown versions here?

You mean instead of -EINVAL? No idea, Marcus?

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification
  2013-02-20  8:13     ` Lee Jones
@ 2013-02-20  8:53       ` Marcus Cooper
  2013-02-20 10:43         ` Lee Jones
  0 siblings, 1 reply; 54+ messages in thread
From: Marcus Cooper @ 2013-02-20  8:53 UTC (permalink / raw)
  To: linux-arm-kernel

On 20 February 2013 09:13, Lee Jones <lee.jones@linaro.org> wrote:
> On Tue, 19 Feb 2013, Arnd Bergmann wrote:
>
>> On Friday 15 February 2013, Lee Jones wrote:
>> >         struct ab8500 *ab8500;
>> > +       int chip_id = -EINVAL;
>> >
>> >         ab8500 = dev_get_drvdata(dev);
>> > -       return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
>> > +       if(ab8500) {
>> > +               chip_id = ab8500->chip_id;
>> > +               if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
>> > +                       chip_id = (ab8500->version << 8) | chip_id;
>> > +       }
>> > +       return sprintf(buf, "%#x\n", chip_id);
>> >  }
>>
>> What's the use of printing "ffffffea" for unknown versions here?
>
> You mean instead of -EINVAL? No idea, Marcus?
>
Looks like I'm guilty of just making the minimal changes. Arnd is
right though, getting ffffffea(-EINVAL) back is pretty useless.
I'll have to check user land to see what is using this. Maybe not
printing and returning 0 should be the correct behaviour
when an unknown version is found.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification
  2013-02-20  8:53       ` Marcus Cooper
@ 2013-02-20 10:43         ` Lee Jones
  0 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-20 10:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 20 Feb 2013, Marcus Cooper wrote:

> On 20 February 2013 09:13, Lee Jones <lee.jones@linaro.org> wrote:
> > On Tue, 19 Feb 2013, Arnd Bergmann wrote:
> >
> >> On Friday 15 February 2013, Lee Jones wrote:
> >> >         struct ab8500 *ab8500;
> >> > +       int chip_id = -EINVAL;
> >> >
> >> >         ab8500 = dev_get_drvdata(dev);
> >> > -       return sprintf(buf, "%#x\n", ab8500 ? ab8500->chip_id : -EINVAL);
> >> > +       if(ab8500) {
> >> > +               chip_id = ab8500->chip_id;
> >> > +               if((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->version != 0xFF)
> >> > +                       chip_id = (ab8500->version << 8) | chip_id;
> >> > +       }
> >> > +       return sprintf(buf, "%#x\n", chip_id);
> >> >  }
> >>
> >> What's the use of printing "ffffffea" for unknown versions here?
> >
> > You mean instead of -EINVAL? No idea, Marcus?
> >
> Looks like I'm guilty of just making the minimal changes. Arnd is
> right though, getting ffffffea(-EINVAL) back is pretty useless.
> I'll have to check user land to see what is using this.

Yes, it would be useful to know how it's parsed.

Thanks Marcus.

> Maybe not
> printing and returning 0 should be the correct behaviour
> when an unknown version is found.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-15 12:56 ` [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume Lee Jones
@ 2013-02-20 13:19   ` Mark Brown
  2013-02-21 22:45     ` Ulf Hansson
  0 siblings, 1 reply; 54+ messages in thread
From: Mark Brown @ 2013-02-20 13:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 15, 2013 at 12:56:32PM +0000, Lee Jones wrote:

> +static int ab8500_gpadc_suspend(struct device *dev)
> +{
> +	struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
> +
> +	mutex_lock(&gpadc->ab8500_gpadc_lock);
> +
> +	pm_runtime_get_sync(dev);
> +
> +	regulator_disable(gpadc->regu);
> +	return 0;
> +}

This doesn't look especially sane...  You're doing a runtime get, taking
the lock without releasing it and disabling the regulator.  This is
*very* odd, both the changelog and the code need to explain what's going
on and why it's safe in a lot more detail here.

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing
  2013-02-15 12:56 ` [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing Lee Jones
@ 2013-02-20 13:23   ` Mark Brown
  2013-02-20 16:38     ` Lee Jones
  0 siblings, 1 reply; 54+ messages in thread
From: Mark Brown @ 2013-02-20 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 15, 2013 at 12:56:33PM +0000, Lee Jones wrote:

> +	if (gpadc->regu)
> +		regulator_disable(gpadc->regu);

No explanation for this in the changelog and missing error handling like
this is pretty much always terrible style.  Why are we doing this?

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing
  2013-02-20 13:23   ` Mark Brown
@ 2013-02-20 16:38     ` Lee Jones
  0 siblings, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-20 16:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, 20 Feb 2013, Mark Brown wrote:

> On Fri, Feb 15, 2013 at 12:56:33PM +0000, Lee Jones wrote:
> 
> > +	if (gpadc->regu)
> > +		regulator_disable(gpadc->regu);
> 
> No explanation for this in the changelog and missing error handling like
> this is pretty much always terrible style.  Why are we doing this?

No idea, and Jonas is on parental leave.

Perhaps one of the other guys have an explanation?

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-20 13:19   ` Mark Brown
@ 2013-02-21 22:45     ` Ulf Hansson
  2013-02-22  7:55       ` Lee Jones
  2013-02-22 10:38       ` Mark Brown
  0 siblings, 2 replies; 54+ messages in thread
From: Ulf Hansson @ 2013-02-21 22:45 UTC (permalink / raw)
  To: linux-arm-kernel

On 20 February 2013 14:19, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Fri, Feb 15, 2013 at 12:56:32PM +0000, Lee Jones wrote:
>
>> +static int ab8500_gpadc_suspend(struct device *dev)
>> +{
>> +     struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
>> +
>> +     mutex_lock(&gpadc->ab8500_gpadc_lock);
>> +
>> +     pm_runtime_get_sync(dev);
>> +
>> +     regulator_disable(gpadc->regu);
>> +     return 0;
>> +}
>
> This doesn't look especially sane...  You're doing a runtime get, taking
> the lock without releasing it and disabling the regulator.  This is
> *very* odd, both the changelog and the code need to explain what's going
> on and why it's safe in a lot more detail here.

You need to do pm_runtime_get_sync to be able to make sure resources
(which seems to be only the regulator) are safe to switch off. To my
understanding this is a generic way to use for being able to switch
off resources at a device suspend when runtime pm is used in
conjunction.

Regarding the mutex, I can't tell the reason behind it. It seems
strange but not sure.

> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

Kind regards
Ulf Hansson

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-21 22:45     ` Ulf Hansson
@ 2013-02-22  7:55       ` Lee Jones
  2013-02-22 10:38       ` Mark Brown
  1 sibling, 0 replies; 54+ messages in thread
From: Lee Jones @ 2013-02-22  7:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, 21 Feb 2013, Ulf Hansson wrote:

> On 20 February 2013 14:19, Mark Brown
> <broonie@opensource.wolfsonmicro.com> wrote:
> > On Fri, Feb 15, 2013 at 12:56:32PM +0000, Lee Jones wrote:
> >
> >> +static int ab8500_gpadc_suspend(struct device *dev)
> >> +{
> >> +     struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
> >> +
> >> +     mutex_lock(&gpadc->ab8500_gpadc_lock);
> >> +
> >> +     pm_runtime_get_sync(dev);
> >> +
> >> +     regulator_disable(gpadc->regu);
> >> +     return 0;
> >> +}
> >
> > This doesn't look especially sane...  You're doing a runtime get, taking
> > the lock without releasing it and disabling the regulator.  This is
> > *very* odd, both the changelog and the code need to explain what's going
> > on and why it's safe in a lot more detail here.
> 
> You need to do pm_runtime_get_sync to be able to make sure resources
> (which seems to be only the regulator) are safe to switch off. To my
> understanding this is a generic way to use for being able to switch
> off resources at a device suspend when runtime pm is used in
> conjunction.
> 
> Regarding the mutex, I can't tell the reason behind it. It seems
> strange but not sure.

Daniel, any thoughts?

I'm happy to fixup, once I have the full story.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-21 22:45     ` Ulf Hansson
  2013-02-22  7:55       ` Lee Jones
@ 2013-02-22 10:38       ` Mark Brown
  2013-02-25  9:27         ` Ulf Hansson
  1 sibling, 1 reply; 54+ messages in thread
From: Mark Brown @ 2013-02-22 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 21, 2013 at 11:45:08PM +0100, Ulf Hansson wrote:
> On 20 February 2013 14:19, Mark Brown

> > This doesn't look especially sane...  You're doing a runtime get, taking
> > the lock without releasing it and disabling the regulator.  This is
> > *very* odd, both the changelog and the code need to explain what's going
> > on and why it's safe in a lot more detail here.

> You need to do pm_runtime_get_sync to be able to make sure resources
> (which seems to be only the regulator) are safe to switch off. To my
> understanding this is a generic way to use for being able to switch
> off resources at a device suspend when runtime pm is used in
> conjunction.

Are you sure this actually does what you think it does, especially when
run on modern kernels?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130222/12b22173/attachment-0001.sig>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-22 10:38       ` Mark Brown
@ 2013-02-25  9:27         ` Ulf Hansson
  2013-02-25 13:51           ` Mark Brown
  0 siblings, 1 reply; 54+ messages in thread
From: Ulf Hansson @ 2013-02-25  9:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 22 February 2013 11:38, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Thu, Feb 21, 2013 at 11:45:08PM +0100, Ulf Hansson wrote:
>> On 20 February 2013 14:19, Mark Brown
>
>> > This doesn't look especially sane...  You're doing a runtime get, taking
>> > the lock without releasing it and disabling the regulator.  This is
>> > *very* odd, both the changelog and the code need to explain what's going
>> > on and why it's safe in a lot more detail here.
>
>> You need to do pm_runtime_get_sync to be able to make sure resources
>> (which seems to be only the regulator) are safe to switch off. To my
>> understanding this is a generic way to use for being able to switch
>> off resources at a device suspend when runtime pm is used in
>> conjunction.
>
> Are you sure this actually does what you think it does, especially when
> run on modern kernels?

Not sure, what you are thinking of more precisely here. Runtime pm has
been in the kernel for quite some time now.

Anyway, to make it a bit clearer, we switch the regulator on/off at
the runtime suspend/resume callbacks. We want to take similar actions
in device suspend/resume.
To accomplish this a pm_runtime_get_sync is done in suspend and vice
verse in resume, otherwise you can not safely handle the regulator.

Kind regards
Ulf Hansson

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-25  9:27         ` Ulf Hansson
@ 2013-02-25 13:51           ` Mark Brown
  2013-02-25 14:52             ` Ulf Hansson
  0 siblings, 1 reply; 54+ messages in thread
From: Mark Brown @ 2013-02-25 13:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Feb 25, 2013 at 10:27:36AM +0100, Ulf Hansson wrote:
> On 22 February 2013 11:38, Mark Brown

> > Are you sure this actually does what you think it does, especially when
> > run on modern kernels?

> Not sure, what you are thinking of more precisely here. Runtime pm has
> been in the kernel for quite some time now.

Yes, thanks - I was aware of that.  The integration between runtime and
system PM has been an area that's had some development though.

> Anyway, to make it a bit clearer, we switch the regulator on/off at
> the runtime suspend/resume callbacks. We want to take similar actions
> in device suspend/resume.
> To accomplish this a pm_runtime_get_sync is done in suspend and vice
> verse in resume, otherwise you can not safely handle the regulator.

Are you absolutely positive that with modern kernels your get actually
resumes the device?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130225/9527c3a7/attachment.sig>

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration
  2013-02-15 12:56 ` [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration Lee Jones
@ 2013-02-25 14:33   ` Arnd Bergmann
  2013-02-25 14:49     ` Lee Jones
  0 siblings, 1 reply; 54+ messages in thread
From: Arnd Bergmann @ 2013-02-25 14:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday 15 February 2013, Lee Jones wrote:
> A recent patch saw the device.h include being removed from some other
> include files and replaced with a 'struct device' declaration instead.
> However, neither the include nor the declaration is actually required.
> 
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> ---
>  include/linux/mfd/abx500.h |    2 --
>  1 file changed, 2 deletions(-)

In my copy of the file, we the declaration


int ab8500_bm_of_probe(struct device *dev,
                       struct device_node *np,
                       struct abx500_bm_data *bm);



and others that use 'struct device'. C99 requires that a struct is declared
in advance  before you use it in a function declaration.

	Arnd

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration
  2013-02-25 14:33   ` Arnd Bergmann
@ 2013-02-25 14:49     ` Lee Jones
  2013-02-25 16:27       ` Arnd Bergmann
  0 siblings, 1 reply; 54+ messages in thread
From: Lee Jones @ 2013-02-25 14:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, 25 Feb 2013, Arnd Bergmann wrote:

> On Friday 15 February 2013, Lee Jones wrote:
> > A recent patch saw the device.h include being removed from some other
> > include files and replaced with a 'struct device' declaration instead.
> > However, neither the include nor the declaration is actually required.
> > 
> > Signed-off-by: Lee Jones <lee.jones@linaro.org>
> > ---
> >  include/linux/mfd/abx500.h |    2 --
> >  1 file changed, 2 deletions(-)
> 
> In my copy of the file, we the declaration
> 
> 
> int ab8500_bm_of_probe(struct device *dev,
>                        struct device_node *np,
>                        struct abx500_bm_data *bm);
> 
> 
> 
> and others that use 'struct device'. C99 requires that a struct is declared
> in advance  before you use it in a function declaration.

Hmm... I wonder why it doesn't complain then?

I'll remove the patch.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume
  2013-02-25 13:51           ` Mark Brown
@ 2013-02-25 14:52             ` Ulf Hansson
  0 siblings, 0 replies; 54+ messages in thread
From: Ulf Hansson @ 2013-02-25 14:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 25 February 2013 14:51, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Feb 25, 2013 at 10:27:36AM +0100, Ulf Hansson wrote:
>> On 22 February 2013 11:38, Mark Brown
>
>> > Are you sure this actually does what you think it does, especially when
>> > run on modern kernels?
>
>> Not sure, what you are thinking of more precisely here. Runtime pm has
>> been in the kernel for quite some time now.
>
> Yes, thanks - I was aware of that.  The integration between runtime and
> system PM has been an area that's had some development though.
>
>> Anyway, to make it a bit clearer, we switch the regulator on/off at
>> the runtime suspend/resume callbacks. We want to take similar actions
>> in device suspend/resume.
>> To accomplish this a pm_runtime_get_sync is done in suspend and vice
>> verse in resume, otherwise you can not safely handle the regulator.
>
> Are you absolutely positive that with modern kernels your get actually
> resumes the device?

Yes, runtime resume is always ok, But you can not runtime suspend the
device, since the device suspend layer prevent this with a
pm_runtime_get_noresume before calling the device suspend callback.

Kind regards
Ulf Hansson

^ permalink raw reply	[flat|nested] 54+ messages in thread

* [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration
  2013-02-25 14:49     ` Lee Jones
@ 2013-02-25 16:27       ` Arnd Bergmann
  0 siblings, 0 replies; 54+ messages in thread
From: Arnd Bergmann @ 2013-02-25 16:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday 25 February 2013, Lee Jones wrote:
> > and others that use 'struct device'. C99 requires that a struct is declared
> > in advance  before you use it in a function declaration.
> 
> Hmm... I wonder why it doesn't complain then?
> 
> I'll remove the patch.

It's only a problem if the file is included before any other header declares
'struct device'. It may well be that this currently never happens, but it's
better to be safe and have a header that can be included in any order:
relying on a specific inclusion order can easily break with 'make randconfig'
turning off specific features that you did not know you relied on.

	Arnd

^ permalink raw reply	[flat|nested] 54+ messages in thread

end of thread, other threads:[~2013-02-25 16:27 UTC | newest]

Thread overview: 54+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-15 12:56 [PATCH 00/35] mfd: ab8500: Internal development push Lee Jones
2013-02-15 12:56 ` [PATCH 01/35] mfd: ab8500-gpadc: Implemented suspend/resume Lee Jones
2013-02-20 13:19   ` Mark Brown
2013-02-21 22:45     ` Ulf Hansson
2013-02-22  7:55       ` Lee Jones
2013-02-22 10:38       ` Mark Brown
2013-02-25  9:27         ` Ulf Hansson
2013-02-25 13:51           ` Mark Brown
2013-02-25 14:52             ` Ulf Hansson
2013-02-15 12:56 ` [PATCH 02/35] mfd: ab8500-gpadc: Allow tvout regulator to be missing Lee Jones
2013-02-20 13:23   ` Mark Brown
2013-02-20 16:38     ` Lee Jones
2013-02-15 12:56 ` [PATCH 03/35] mfd: ab8500-gpadc: Reread on failure Lee Jones
2013-02-15 12:56 ` [PATCH 04/35] mfd: ab8500-gpadc: Add gpadc hw conversion Lee Jones
2013-02-15 12:56 ` [PATCH 05/35] mfd: ab8500-core: APE Interrupts are not cleared Lee Jones
2013-02-15 12:56 ` [PATCH 06/35] mfd: ab8500-core: Sysfs chip id modification Lee Jones
2013-02-19 22:04   ` Arnd Bergmann
2013-02-20  8:13     ` Lee Jones
2013-02-20  8:53       ` Marcus Cooper
2013-02-20 10:43         ` Lee Jones
2013-02-15 12:56 ` [PATCH 07/35] mfd: ab8500-debug: Print banks in hex Lee Jones
2013-02-15 12:56 ` [PATCH 08/35] mfd: ab8500-debug: Function to save all ABB registers to mem Lee Jones
2013-02-15 12:56 ` [PATCH 09/35] mfd: ab8500-core: Add ADC support for ab8540 Lee Jones
2013-02-15 12:56 ` [PATCH 10/35] mfd: ab8500-core: Rework MFD sub-device initialisation structures Lee Jones
2013-02-19 22:07   ` Arnd Bergmann
2013-02-20  8:09     ` Lee Jones
2013-02-15 12:56 ` [PATCH 11/35] mfd: ab8500-core: Add Interrupt support for ab8540 Lee Jones
2013-02-15 12:56 ` [PATCH 12/35] mfd: ab8500-debug: Better error handling on crash Lee Jones
2013-02-15 12:56 ` [PATCH 13/35] mfd: ab8500-debug: Add wake-up info Lee Jones
2013-02-15 12:56 ` [PATCH 14/35] mfd: ab8500-sysctrl: Error check clean up Lee Jones
2013-02-15 12:56 ` [PATCH 15/35] mfd: ab8500-debugfs: Add tests for ab8540 based platform initialisations Lee Jones
2013-02-15 12:56 ` [PATCH 16/35] mfd: ab8500: Add more platform checks Lee Jones
2013-02-15 12:56 ` [PATCH 17/35] mfd: ab8500: Introduce AB8540 cuts definition Lee Jones
2013-02-15 12:56 ` [PATCH 18/35] mfd: ab8500-sysctrl: Update correct turn on status Lee Jones
2013-02-15 12:56 ` [PATCH 19/35] mfd: ab8500-debug: Add support for ab8505 and ab9540 Lee Jones
2013-02-15 12:56 ` [PATCH 20/35] mfd: ab8500-sysctrl: Add new reset function Lee Jones
2013-02-15 12:56 ` [PATCH 21/35] mfd: ab8500-gpadc: Add support for the AB8540 Lee Jones
2013-02-15 12:56 ` [PATCH 22/35] mfd: ab8500-debug: " Lee Jones
2013-02-15 12:56 ` [PATCH 23/35] mfd: ab8500-gpadc: Optimise GPADC driver Lee Jones
2013-02-15 12:56 ` [PATCH 24/35] mfd: ab8500: Remove unnecessary 'struct device' declaration Lee Jones
2013-02-25 14:33   ` Arnd Bergmann
2013-02-25 14:49     ` Lee Jones
2013-02-25 16:27       ` Arnd Bergmann
2013-02-15 12:56 ` [PATCH 25/35] mfd: ab8500-core: Add additional resources to ab8505_iddet_resources Lee Jones
2013-02-15 12:56 ` [PATCH 26/35] mfd: ab8500-sysctrl: AB8505 doesn't have SYSCLKREQ5..8 Lee Jones
2013-02-15 12:56 ` [PATCH 27/35] mfd: ab8500-debugfs: Dump sim registers Lee Jones
2013-02-15 12:56 ` [PATCH 28/35] mfd: ab8500-debug: Add ADC input channel usb_id in debugfs Lee Jones
2013-02-15 12:57 ` [PATCH 29/35] mfd: ab8500-core: Show turn on status at boot Lee Jones
2013-02-15 12:57 ` [PATCH 30/35] mfd: ab8500-debugfs: Change AB8500 debug permissions Lee Jones
2013-02-15 12:57 ` [PATCH 31/35] mfd: ab8500-debug: Add register map for ab8540 Lee Jones
2013-02-15 12:57 ` [PATCH 32/35] mfd: ab8500-core: Add abx500-clk as an mfd child device Lee Jones
2013-02-15 12:57 ` [PATCH 33/35] mfd: ab8500-debug: Add explicit dependencies Lee Jones
2013-02-15 12:57 ` [PATCH 34/35] mfd: ab8500-debug: Convert to kstrtoul_from_user Lee Jones
2013-02-15 12:57 ` [PATCH 35/35] mfd: ab8500-core: Hierarchical interrupt registers Lee Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).