[PATCH 06/10] fix-rfkill-on-bt-platform-drvdata-vs-drvdata.patch

Andy Green andy at openmoko.com
Mon Dec 1 02:25:38 CET 2008


Hum seems the rfkill stuff was broken somewhere along the line,
some of it thinks the rfkill pointer is in the pdev private data
and some gets confused about the bt_data pointer being in dev
private data... this patch cleans it out so the rfkill pointer
is held in the bt_data struct, which is created for gta01 or 02
now.

Before these changes it will blow up on resume due to dereferencing
the wrong pointer to the wrong thing.

Signed-off-by: Andy Green <andy at openmoko.com>
---

 arch/arm/plat-s3c24xx/neo1973_pm_bt.c |  115 ++++++++++++++++-----------------
 1 files changed, 57 insertions(+), 58 deletions(-)

diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
index 894651a..217fcf0 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
@@ -36,6 +36,8 @@
 
 struct gta01_pm_bt_data {
 	struct regulator *regulator;
+	struct rfkill *rfkill;
+	int pre_resume_state;
 };
 
 static ssize_t bt_read(struct device *dev, struct device_attribute *attr,
@@ -72,11 +74,35 @@ static ssize_t bt_read(struct device *dev, struct device_attribute *attr,
 	}
 }
 
+static void __gta02_pm_bt_toggle_radio(struct device *dev, unsigned int on)
+{
+	struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
+
+	dev_info(dev, "__gta02_pm_bt_toggle_radio %d\n", on);
+
+	if (machine_is_neo1973_gta02()) {
+
+		bt_data = dev_get_drvdata(dev);
+
+		neo1973_gpb_setpin(GTA02_GPIO_BT_EN, !on);
+
+		if (on) {
+			if (!regulator_is_enabled(bt_data->regulator))
+				regulator_enable(bt_data->regulator);
+		} else {
+			if (regulator_is_enabled(bt_data->regulator))
+				regulator_disable(bt_data->regulator);
+		}
+
+		neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on);
+	}
+}
+
+
 static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
 {
 	struct device *dev = data;
 	unsigned long on = (state == RFKILL_STATE_ON);
-	struct gta01_pm_bt_data *bt_data;
 
 	if (machine_is_neo1973_gta01()) {
 		/* if we are powering up, assert reset, then power,
@@ -90,25 +116,8 @@ static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
 		pcf50606_onoff_set(pcf50606_global,
 				   PCF50606_REGULATOR_D1REG, on);
 		neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on);
-	} else if (machine_is_neo1973_gta02()) {
-		if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN) == on)
-			return 0;
-			
-		bt_data = dev_get_drvdata(dev);
-		BUG_ON(!bt_data || !bt_data->regulator);
-
-		neo1973_gpb_setpin(GTA02_GPIO_BT_EN, !on);
-			
-		if (on) {
-			if (!regulator_is_enabled(bt_data->regulator))
-				regulator_enable(bt_data->regulator);
-		} else {
-			if (regulator_is_enabled(bt_data->regulator))
-					regulator_disable(bt_data->regulator);
-		}
-
-		neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on);
-	}
+	} else if (machine_is_neo1973_gta02())
+		__gta02_pm_bt_toggle_radio(dev, on);
 
 	return 0;
 }
@@ -117,15 +126,12 @@ static ssize_t bt_write(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
 	unsigned long on = simple_strtoul(buf, NULL, 10);
-	unsigned int vol;
-	struct gta01_pm_bt_data *bt_data;
-	struct regulator *regulator;
+	struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
 
 	if (!strcmp(attr->attr.name, "power_on")) {
-		struct rfkill *rfkill = dev_get_drvdata(dev);
 		enum rfkill_state state = on ? RFKILL_STATE_ON : RFKILL_STATE_OFF;
 		bt_rfkill_toggle_radio(dev, state);
-		rfkill->state = state;
+		bt_data->rfkill->state = state;
 
 		if (machine_is_neo1973_gta01()) {
 			/* if we are powering up, assert reset, then power,
@@ -139,29 +145,9 @@ static ssize_t bt_write(struct device *dev, struct device_attribute *attr,
 			pcf50606_onoff_set(pcf50606_global,
 					   PCF50606_REGULATOR_D1REG, on);
 			neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on);
-		} else if (machine_is_neo1973_gta02()) {
-			if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN) == on)
-				return count;
-			
-			bt_data = dev_get_drvdata(dev);
-			BUG_ON(!bt_data || !bt_data->regulator);
-			regulator = bt_data->regulator;
-
-			neo1973_gpb_setpin(GTA02_GPIO_BT_EN, !on);
-			
-			if (on) {
-				if (!regulator_is_enabled(regulator))
-					regulator_enable(regulator);
-			} else {
-				if (regulator_is_enabled(regulator))
-						regulator_disable(regulator);
-			}
-
-			vol = regulator_get_voltage(regulator);
+		} else if (machine_is_neo1973_gta02())
+			__gta02_pm_bt_toggle_radio(dev, on);
 
-			dev_info(dev, "GTA02 Set PCF50633 LDO4 = %d\n", vol);
-			neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on);
-		}
 	} else if (!strcmp(attr->attr.name, "reset")) {
 		/* reset is low-active, so we need to invert */
 		if (machine_is_neo1973_gta01()) {
@@ -180,18 +166,29 @@ static DEVICE_ATTR(reset, 0644, bt_read, bt_write);
 #ifdef CONFIG_PM
 static int gta01_bt_suspend(struct platform_device *pdev, pm_message_t state)
 {
+	struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
+
 	dev_dbg(&pdev->dev, DRVMSG ": suspending\n");
-	/* FIXME: The PMU should save the PMU status, and the GPIO code should
-	 * preserve the GPIO level, so there shouldn't be anything left to do
-	 * for us, should there? */
+
+	if (machine_is_neo1973_gta02()) {
+		bt_data->pre_resume_state =
+					  s3c2410_gpio_getpin(GTA02_GPIO_BT_EN);
+		__gta02_pm_bt_toggle_radio(&pdev->dev, 0);
+	}
 
 	return 0;
 }
 
 static int gta01_bt_resume(struct platform_device *pdev)
 {
+	struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
 	dev_dbg(&pdev->dev, DRVMSG ": resuming\n");
 
+	if (machine_is_neo1973_gta02()) {
+		__gta02_pm_bt_toggle_radio(&pdev->dev,
+						     bt_data->pre_resume_state);
+	}
+
 	return 0;
 }
 #else
@@ -219,6 +216,8 @@ static int __init gta01_bt_probe(struct platform_device *pdev)
 
 	dev_info(&pdev->dev, DRVMSG ": starting\n");
 
+	bt_data = kzalloc(sizeof(*bt_data), GFP_KERNEL);
+
 	if (machine_is_neo1973_gta01()) {
 		/* we make sure that the voltage is off */
 		pcf50606_onoff_set(pcf50606_global,
@@ -231,7 +230,6 @@ static int __init gta01_bt_probe(struct platform_device *pdev)
 		if (IS_ERR(regulator))
 			return -ENODEV;
 
-		bt_data = kmalloc(sizeof(*bt_data), GFP_KERNEL);
 		bt_data->regulator = regulator;
 		dev_set_drvdata(&pdev->dev, bt_data);
 
@@ -264,24 +262,23 @@ static int __init gta01_bt_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	platform_set_drvdata(pdev, rfkill);
+	bt_data->rfkill = rfkill;
 
 	return sysfs_create_group(&pdev->dev.kobj, &gta01_bt_attr_group);
 }
 
 static int gta01_bt_remove(struct platform_device *pdev)
 {
-	struct rfkill *rfkill = platform_get_drvdata(pdev);
-
-	struct gta01_pm_bt_data *bt_data;
+	struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
 	struct regulator *regulator;
 
 	sysfs_remove_group(&pdev->dev.kobj, &gta01_bt_attr_group);
 
-	rfkill_unregister(rfkill);
-	rfkill_free(rfkill);
+	if (bt_data->rfkill) {
+		rfkill_unregister(bt_data->rfkill);
+		rfkill_free(bt_data->rfkill);
+	}
 
-	bt_data = dev_get_drvdata(&pdev->dev);
 	if (!bt_data || !bt_data->regulator)
 		return 0;
 
@@ -292,6 +289,8 @@ static int gta01_bt_remove(struct platform_device *pdev)
 		regulator_disable(regulator);
 
 	regulator_put(regulator);
+
+	kfree(bt_data);
 	
 	return 0;
 }




More information about the openmoko-kernel mailing list