Skip to contentSkip to conversation

Fix issues around twl4030-gpio used as a module

PATCH New Rajendra Nayak 2 participants 12 messages Feb 24, 2012 – Mar 1, 2012

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover Fix issues around twl4030-gpio used as a module

Hi Tony,

This series is based on top of 'hsmmc' branch in linux-omap on top of commit '0e91c8ddf0e0932da59ec1d116e34049791b0e73' as requested by you.

This mainly splits omap_hsmmc_late_init() into omap_hsmmc_deferred_add() and omap_hsmmc_deferred_del() and adds .teardown hooks in all omap3 boards to handle issues around multiple twl4030-gpio module insmod/unbind/bind as reported by Russell.

In the process this series adds an api to unregister an omap_device, makes mmc driver work with hotpluggable devices and also removes 'deferred' flag for a few mmc devices on some boards which are not really dependent on twl4030-gpio for card detect as reported by Igor.

I have tested this series on omap3 beagle, with twl4030-gpio built in, as well as twl4030-gpio built as a module and by doing multiple insmod/unbind/bind sequence. I have tested card-detect to work fine on beagle too.

regards,
Rajendra

Rajendra Nayak (6):
ARM: OMAP: omap_device: Add omap_device_unregister()
mmc: omap_hsmmc: Make the driver support hotpluggable devices
mmc: omap_hsmmc: If probe fails, give our error messages
ARM: OMAP3: Make only mmc devices using gpio_cd as deferred
ARM: OMAP3: Modify omap_hsmmc_late_init to handle deleting mmc
devices
ARM: OMAP3: Use .teardown of twl4030-gpio to clean board requests

 arch/arm/mach-omap2/board-3430sdp.c           |   15 ++++-
 arch/arm/mach-omap2/board-cm-t35.c            |   15 ++++-
 arch/arm/mach-omap2/board-devkit8000.c        |   15 ++++-
 arch/arm/mach-omap2/board-igep0020.c          |   18 ++++-
 arch/arm/mach-omap2/board-ldp.c               |   13 ++++
 arch/arm/mach-omap2/board-omap3beagle.c       |   17 ++++-
 arch/arm/mach-omap2/board-omap3evm.c          |   16 ++++-
 arch/arm/mach-omap2/board-omap3pandora.c      |   14 +++-
 arch/arm/mach-omap2/board-omap3stalker.c      |   16 ++++-
 arch/arm/mach-omap2/board-omap3touchbook.c    |   15 ++++-
 arch/arm/mach-omap2/board-overo.c             |   11 +++-
 arch/arm/mach-omap2/board-rx51-peripherals.c  |   11 +++
 arch/arm/mach-omap2/board-zoom-peripherals.c  |   14 +++-
 arch/arm/mach-omap2/hsmmc.c                   |   93 ++++++++++++-------------
 arch/arm/mach-omap2/hsmmc.h                   |    9 ++-
 arch/arm/plat-omap/include/plat/omap_device.h |    1 +
 arch/arm/plat-omap/omap_device.c              |   20 +++++-
 drivers/mmc/host/omap_hsmmc.c                 |   11 ++--
 18 files changed, 249 insertions(+), 75 deletions(-)
#1 lore raw

PATCH 1/6 ARM: OMAP: omap_device: Add omap_device_unregister()

Add support to unregister an omap_device using
omap_device_unregister api.

While here, also fix the kerneldoc comments for
omap_device_register.

---
 arch/arm/plat-omap/include/plat/omap_device.h |    1 +
 arch/arm/plat-omap/omap_device.c              |   20 ++++++++++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)
arch/arm/plat-omap/include/plat/omap_device.h +1 -0
index 05f7615..ce0dc86 100644
@@ -106,6 +106,7 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
 				      int pm_lats_cnt);
 void omap_device_delete(struct omap_device *od);
 int omap_device_register(struct platform_device *pdev);
+void omap_device_unregister(struct platform_device *pdev);
 
 void __iomem *omap_device_get_rt_va(struct omap_device *od);
 struct device *omap_device_get_by_hwmod_name(const char *oh_name);
arch/arm/plat-omap/omap_device.c +18 -2
index 2d00ab0..27aa02d 100644
@@ -808,8 +808,8 @@ static struct dev_pm_domain omap_device_pm_domain = {
  * @od: struct omap_device * to register
  *
  * Register the omap_device structure.  This currently just calls
- * platform_device_register() on the underlying platform_device.
- * Returns the return value of platform_device_register().
+ * platform_device_add() on the underlying platform_device.
+ * Returns the return value of platform_device_add().
  */
 int omap_device_register(struct platform_device *pdev)
 {
@@ -820,6 +820,22 @@ int omap_device_register(struct platform_device *pdev)
 	return platform_device_add(pdev);
 }
 
+/**
+ * omap_device_unregister - unregister an omap_device with one omap_hwmod
+ * @od: struct omap_device * to unregister
+ *
+ * Unregister the omap_device structure.  This currently just calls
+ * platform_device_del() on the underlying platform_device.
+ * No return value.
+ */
+void omap_device_unregister(struct platform_device *pdev)
+{
+	pr_debug("omap_device: %s: unregistering\n", pdev->name);
+
+	pdev->dev.parent = &omap_device_parent;
+	pdev->dev.pm_domain = &omap_device_pm_domain;
+	platform_device_del(pdev);
+}
 
 /* Public functions for use by device drivers through struct platform_data */
 
Signature · 1 line
1.7.1
#2 lore raw

PATCH 2/6 mmc: omap_hsmmc: Make the driver support hotpluggable devices

In reply to Rajendra Nayak

Make the hsmmc driver register the driver using platform_driver_register() so it can support hotpluggable devices.

This is needed, for instance, in case of OMAP3, wherein some of the mmc devices might get added and removed dynamically based on dependent modules like twl4030-gpio.

---
 drivers/mmc/host/omap_hsmmc.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
drivers/mmc/host/omap_hsmmc.c +3 -2
index fd0c661..21b8afa 100644
@@ -1847,7 +1847,7 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 
 #endif
 
-static int __init omap_hsmmc_probe(struct platform_device *pdev)
+static int omap_hsmmc_probe(struct platform_device *pdev)
 {
 	struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
 	struct mmc_host *mmc;
@@ -2264,6 +2264,7 @@ static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
 };
 
 static struct platform_driver omap_hsmmc_driver = {
+	.probe		= omap_hsmmc_probe,
 	.remove		= omap_hsmmc_remove,
 	.driver		= {
 		.name = DRIVER_NAME,
@@ -2275,7 +2276,7 @@ static struct platform_driver omap_hsmmc_driver = {
 static int __init omap_hsmmc_init(void)
 {
 	/* Register the MMC driver */
-	return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe);
+	return platform_driver_register(&omap_hsmmc_driver);
 }
 
 static void __exit omap_hsmmc_cleanup(void)
Signature · 1 line
1.7.1
#3 lore raw

PATCH 3/6 mmc: omap_hsmmc: If probe fails, give out error messages

In reply to Rajendra Nayak

Giving out debug messages even in case of probe failure seems not very useful. Make them error messages instead.

---
 drivers/mmc/host/omap_hsmmc.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/mmc/host/omap_hsmmc.c +3 -3
index 21b8afa..653ffee 100644
@@ -2008,13 +2008,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 	ret = request_irq(host->irq, omap_hsmmc_irq, 0,
 			mmc_hostname(mmc), host);
 	if (ret) {
-		dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+		dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
 		goto err_irq;
 	}
 
 	if (pdata->init != NULL) {
 		if (pdata->init(&pdev->dev) != 0) {
-			dev_dbg(mmc_dev(host->mmc),
+			dev_err(mmc_dev(host->mmc),
 				"Unable to configure MMC IRQs\n");
 			goto err_irq_cd_init;
 		}
@@ -2037,7 +2037,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 					   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
 					   mmc_hostname(mmc), host);
 		if (ret) {
-			dev_dbg(mmc_dev(host->mmc),
+			dev_err(mmc_dev(host->mmc),
 				"Unable to grab MMC CD IRQ\n");
 			goto err_irq_cd;
 		}
Signature · 1 line
1.7.1
#4 lore raw

PATCH 4/6 ARM: OMAP3: Mark only those mmc devices which use gpio_cd, as deferred

In reply to Rajendra Nayak

mmc devices which actually do not depend on twl4030-gpio for gpio_cd should not be maked as deferred.

Also on overo, since none of the mmc devices need to be deferred, get rid of omap_hsmmc_late_init() altogether.

---
 arch/arm/mach-omap2/board-cm-t35.c           |    1 -
 arch/arm/mach-omap2/board-igep0020.c         |    1 -
 arch/arm/mach-omap2/board-omap3evm.c         |    1 -
 arch/arm/mach-omap2/board-omap3pandora.c     |    1 -
 arch/arm/mach-omap2/board-overo.c            |    4 ----
 arch/arm/mach-omap2/board-zoom-peripherals.c |    2 --
 6 files changed, 0 insertions(+), 10 deletions(-)
arch/arm/mach-omap2/board-cm-t35.c +0 -1
index 8eaed63..49e6405 100644
@@ -422,7 +422,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.ocr_mask	= 0x00100000,	/* 3.3V */
-		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
arch/arm/mach-omap2/board-igep0020.c +0 -1
index ac1de09..e558800 100644
@@ -303,7 +303,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
-		.deferred	= true,
 	},
 #endif
 	{}      /* Terminator */
arch/arm/mach-omap2/board-omap3evm.c +0 -1
index 0f9a983..6b77ad9 100644
@@ -327,7 +327,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= -EINVAL,
 		.gpio_cd	= -EINVAL,
 		.nonremovable	= true,
-		.deferred	= true,
 	},
 #endif
 	{}	/* Terminator */
arch/arm/mach-omap2/board-omap3pandora.c +0 -1
index 84c83c8..ace466b 100644
@@ -290,7 +290,6 @@ static struct omap2_hsmmc_info omap3pandora_mmc[] = {
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
 		.init_card	= pandora_wl1251_init_card,
-		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
arch/arm/mach-omap2/board-overo.c +0 -4
index 1fc5f7a..668533e 100644
@@ -301,7 +301,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.caps		= MMC_CAP_4_BIT_DATA,
 		.gpio_cd	= -EINVAL,
 		.gpio_wp	= -EINVAL,
-		.deferred	= true,
 	},
 	{
 		.mmc		= 2,
@@ -310,7 +309,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= -EINVAL,
 		.transceiver	= true,
 		.ocr_mask	= 0x00100000,	/* 3.3V */
-		.deferred	= true,
 	},
 	{}	/* Terminator */
 };
@@ -409,8 +407,6 @@ static inline void __init overo_init_keys(void) { return; }
 static int overo_twl_gpio_setup(struct device *dev,
 		unsigned gpio, unsigned ngpio)
 {
-	omap_hsmmc_late_init(mmc);
-
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
 	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
 	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
arch/arm/mach-omap2/board-zoom-peripherals.c +0 -2
index 82a0f7c..3d39cdb 100644
@@ -215,7 +215,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= -EINVAL,
 		.nonremovable	= true,
 		.power_saving	= true,
-		.deferred	= true,
 	},
 	{
 		.name		= "wl1271",
@@ -224,7 +223,6 @@ static struct omap2_hsmmc_info mmc[] = {
 		.gpio_wp	= -EINVAL,
 		.gpio_cd	= -EINVAL,
 		.nonremovable	= true,
-		.deferred	= true,
 	},
 	{}      /* Terminator */
 };
Signature · 1 line
1.7.1
maintainer
#5 lore raw

PATCH 4/6 ARM: OMAP3: Mark only those mmc devices which use gpio_cd, as deferred

Quoted 8 lines · Rajendra Nayak

mmc devices which actually do not depend on twl4030-gpio for gpio_cd should not be maked as deferred.

Also on overo, since none of the mmc devices need to be deferred, get rid of omap_hsmmc_late_init() altogether.

Thanks, I'll fold this into the original patch with your SOB so we avoid the extra churn.

Regards,

Tony

#6 lore raw

PATCH 4/6 ARM: OMAP3: Mark only those mmc devices which use gpio_cd, as deferred

Quoted 4 lines · Tony Lindgren
Quoted 3 lines · Rajendra Nayak

mmc devices which actually do not depend on twl4030-gpio for gpio_cd should not be maked as deferred.

Quoted 8 lines
Quoted 5 lines

Also on overo, since none of the mmc devices need to be deferred, get rid of omap_hsmmc_late_init() altogether.

Thanks, I'll fold this into the original patch with your SOB so we avoid the extra churn.

okay, thanks.

Quoted 4 lines

Regards,

Tony

#7 lore raw

PATCH 5/6 ARM: OMAP3: Modify omap_hsmmc_late_init to handle deleting mmc devices

In reply to Rajendra Nayak

omap_hsmmc_late_init() adds deferred (if any) mmc devices which are dependent on twl4030-gpio device to be available.
If twl4030-gpio is built as a module and inserted and deleted multiple times, the mmc devices also should be added and deleted accordingly. Split omap_hsmmc_late_init() into omap_hsmmc_deferred_add() and omap_hsmmc_deferred_del() to handle this.
The .setup board hook for twl4030-gpio handles the runtime adding on deferred mmc devices. Similarly a .teardown board hook for twl4030-gpio should handle the runtime deletion by calling omap_hsmmc_deferred_del(). This is done for all existing omap3 boards in subsequent patches.

---
 arch/arm/mach-omap2/board-3430sdp.c          |    2 +-
 arch/arm/mach-omap2/board-cm-t35.c           |    2 +-
 arch/arm/mach-omap2/board-devkit8000.c       |    2 +-
 arch/arm/mach-omap2/board-igep0020.c         |    2 +-
 arch/arm/mach-omap2/board-omap3beagle.c      |    2 +-
 arch/arm/mach-omap2/board-omap3evm.c         |    2 +-
 arch/arm/mach-omap2/board-omap3pandora.c     |    2 +-
 arch/arm/mach-omap2/board-omap3stalker.c     |    2 +-
 arch/arm/mach-omap2/board-omap3touchbook.c   |    2 +-
 arch/arm/mach-omap2/board-zoom-peripherals.c |    2 +-
 arch/arm/mach-omap2/hsmmc.c                  |   93 ++++++++++++--------------
 arch/arm/mach-omap2/hsmmc.h                  |    9 ++-
 12 files changed, 61 insertions(+), 61 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +1 -1
index da75f23..2eef653 100644
@@ -251,7 +251,7 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
 	 */
 	mmc[0].gpio_cd = gpio + 0;
 	mmc[1].gpio_cd = gpio + 1;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
 	gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
arch/arm/mach-omap2/board-cm-t35.c +1 -1
index 49e6405..28e7117 100644
@@ -471,7 +471,7 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	return 0;
 }
arch/arm/mach-omap2/board-devkit8000.c +1 -1
index 11cd2a8..373ba75 100644
@@ -229,7 +229,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
 	gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
arch/arm/mach-omap2/board-igep0020.c +1 -1
index e558800..fb94fdc 100644
@@ -403,7 +403,7 @@ static int igep_twl_gpio_setup(struct device *dev,
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
 #if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
arch/arm/mach-omap2/board-omap3beagle.c +1 -1
index 7be8d65..2ec7bae 100644
@@ -276,7 +276,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
 	mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp;
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/*
 	 * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
arch/arm/mach-omap2/board-omap3evm.c +1 -1
index 6b77ad9..47a9159 100644
@@ -363,7 +363,7 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/*
 	 * Most GPIOs are for USB OTG.  Some are mostly sent to
arch/arm/mach-omap2/board-omap3pandora.c +1 -1
index ace466b..faea4c8 100644
@@ -302,7 +302,7 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
 	/* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */
 	omap3pandora_mmc[0].gpio_cd = gpio + 0;
 	omap3pandora_mmc[1].gpio_cd = gpio + 1;
-	omap_hsmmc_late_init(omap3pandora_mmc);
+	omap_hsmmc_deferred_add(omap3pandora_mmc);
 
 	/* gpio + 13 drives 32kHz buffer for wifi module */
 	gpio_32khz = gpio + 13;
arch/arm/mach-omap2/board-omap3stalker.c +1 -1
index 6410043..1cad225 100644
@@ -284,7 +284,7 @@ omap3stalker_twl_gpio_setup(struct device *dev,
 {
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/*
 	 * Most GPIOs are for USB OTG.  Some are mostly sent to
arch/arm/mach-omap2/board-omap3touchbook.c +1 -1
index 8842e04..932ac8e 100644
@@ -120,7 +120,7 @@ static int touchbook_twl_gpio_setup(struct device *dev,
 {
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	/* REVISIT: need ehci-omap hooks for external VBUS
 	 * power switch and overcurrent detect
arch/arm/mach-omap2/board-zoom-peripherals.c +1 -1
index 3d39cdb..1c200ee 100644
@@ -234,7 +234,7 @@ static int zoom_twl_gpio_setup(struct device *dev,
 
 	/* gpio + 0 is "mmc0_cd" (input/IRQ) */
 	mmc[0].gpio_cd = gpio + 0;
-	omap_hsmmc_late_init(mmc);
+	omap_hsmmc_deferred_add(mmc);
 
 	ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
 			       "lcd enable");
arch/arm/mach-omap2/hsmmc.c +44 -49

140 lines not on this page · raw message

arch/arm/mach-omap2/hsmmc.h +7 -2
index 07831cc..2c1c580 100644
@@ -31,12 +31,14 @@ struct omap2_hsmmc_info {
 	void (*remux)(struct device *dev, int slot, int power_on);
 	/* init some special card */
 	void (*init_card)(struct mmc_card *card);
+	struct omap_mmc_platform_data *mmc_data;
 };
 
 #if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
 
 void omap_hsmmc_init(struct omap2_hsmmc_info *);
-void omap_hsmmc_late_init(struct omap2_hsmmc_info *);
+void omap_hsmmc_deferred_add(struct omap2_hsmmc_info *);
+void omap_hsmmc_deferred_del(struct omap2_hsmmc_info *);
 
 #else
 
@@ -44,8 +46,11 @@ static inline void omap_hsmmc_init(struct omap2_hsmmc_info *info)
 {
 }
 
-static inline void omap_hsmmc_late_init(struct omap2_hsmmc_info *info)
+static inline void omap_hsmmc_deferred_add(struct omap2_hsmmc_info *info)
 {
 }
 
+static inline void omap_hsmmc_deferred_del(struct omap2_hsmmc_info *info)
+{
+}
 #endif
Signature · 1 line
1.7.1
maintainer
#8 lore raw

PATCH 5/6 ARM: OMAP3: Modify omap_hsmmc_late_init to handle deleting mmc devices

Hi,

Quoted 10 lines · Rajendra Nayak

omap_hsmmc_late_init() adds deferred (if any) mmc devices which are dependent on twl4030-gpio device to be available.
If twl4030-gpio is built as a module and inserted and deleted multiple times, the mmc devices also should be added and deleted accordingly. Split omap_hsmmc_late_init() into omap_hsmmc_deferred_add() and omap_hsmmc_deferred_del() to handle this.
The .setup board hook for twl4030-gpio handles the runtime adding on deferred mmc devices. Similarly a .teardown board hook for twl4030-gpio should handle the runtime deletion by calling omap_hsmmc_deferred_del(). This is done for all existing omap3 boards in subsequent patches.

This gets complex.. But I think I've found a simpler way where we can use the twl gpio offsets and let the drivers take care of the rest. I'll post some patches hopefully on Monday.

Regards,

Tony

#9 lore raw

PATCH 5/6 ARM: OMAP3: Modify omap_hsmmc_late_init to handle deleting mmc devices

Quoted 14 lines · Tony Lindgren

Hi,

Quoted 10 lines · Rajendra Nayak

omap_hsmmc_late_init() adds deferred (if any) mmc devices which are dependent on twl4030-gpio device to be available.
If twl4030-gpio is built as a module and inserted and deleted multiple times, the mmc devices also should be added and deleted accordingly. Split omap_hsmmc_late_init() into omap_hsmmc_deferred_add() and omap_hsmmc_deferred_del() to handle this.
The .setup board hook for twl4030-gpio handles the runtime adding on deferred mmc devices. Similarly a .teardown board hook for twl4030-gpio should handle the runtime deletion by calling omap_hsmmc_deferred_del(). This is done for all existing omap3 boards in subsequent patches.

Quoted 3 lines

This gets complex.. But I think I've found a simpler way where we can use the twl gpio offsets and let the drivers take care of the rest. I'll post some patches hopefully on Monday.

I agree it gets complex. If you have a simpler way to handle this, that would be great.

regards,
Rajendra

Quoted 4 lines

Regards,

Tony

maintainer
#10 lore raw

PATCH 5/6 ARM: OMAP3: Modify omap_hsmmc_late_init to handle deleting mmc devices

Quoted 15 lines · Rajendra Nayak
Quoted 14 lines · Tony Lindgren

Hi,

Quoted 10 lines · Rajendra Nayak

omap_hsmmc_late_init() adds deferred (if any) mmc devices which are dependent on twl4030-gpio device to be available.
If twl4030-gpio is built as a module and inserted and deleted multiple times, the mmc devices also should be added and deleted accordingly. Split omap_hsmmc_late_init() into omap_hsmmc_deferred_add() and omap_hsmmc_deferred_del() to handle this.
The .setup board hook for twl4030-gpio handles the runtime adding on deferred mmc devices. Similarly a .teardown board hook for twl4030-gpio should handle the runtime deletion by calling omap_hsmmc_deferred_del(). This is done for all existing omap3 boards in subsequent patches.

Quoted 6 lines
Quoted 3 lines

This gets complex.. But I think I've found a simpler way where we can use the twl gpio offsets and let the drivers take care of the rest. I'll post some patches hopefully on Monday.

I agree it gets complex. If you have a simpler way to handle this, that would be great.

Posted now, sorry it too a bit longer, I got distracted with other stuff. The thread is "[PATCH 0/4] Start getting rid of pdata callbacks with gpio_find_by_chip_name()". Some further testing would be appreciated.

Regards,

Tony

#11 lore raw

PATCH 6/6 ARM: OMAP3: Use .teardown of twl4030-gpio to clean board requests

In reply to Rajendra Nayak

All OMAP3 boards which register a .setup function with twl4030 gpio driver do not seem to have a .teardown hook implemented. .setup mainly requests a few gpios and also in most cases does a omap_hsmmc_deferred_add(). Have a .teardown do a gpio_free() and of the requested gpios and also do a omap_hsmmc_deferred_del(). This helps in case the twl4030 gpio driver is built as a module and added and removed multiple times. Without the .teardown a multiple insmod/rmmod can result in gpio request failues and also WARN messages stating addition of already registered mmc devices.

---
 arch/arm/mach-omap2/board-3430sdp.c          |   13 +++++++++++++
 arch/arm/mach-omap2/board-cm-t35.c           |   12 ++++++++++++
 arch/arm/mach-omap2/board-devkit8000.c       |   13 +++++++++++++
 arch/arm/mach-omap2/board-igep0020.c         |   15 +++++++++++++++
 arch/arm/mach-omap2/board-ldp.c              |   13 +++++++++++++
 arch/arm/mach-omap2/board-omap3beagle.c      |   15 +++++++++++++++
 arch/arm/mach-omap2/board-omap3evm.c         |   13 +++++++++++++
 arch/arm/mach-omap2/board-omap3pandora.c     |   11 +++++++++++
 arch/arm/mach-omap2/board-omap3stalker.c     |   14 ++++++++++++++
 arch/arm/mach-omap2/board-omap3touchbook.c   |   13 +++++++++++++
 arch/arm/mach-omap2/board-rx51-peripherals.c |   11 +++++++++++
 arch/arm/mach-omap2/board-zoom-peripherals.c |   10 ++++++++++
 12 files changed, 153 insertions(+), 0 deletions(-)
arch/arm/mach-omap2/board-3430sdp.c +13 -0
index 2eef653..e5afbdd 100644
@@ -262,6 +262,18 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int sdp3430_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
+	gpio_free(gpio + 7);
+	/* gpio + 15 is "sub_lcd_nRST" (output) */
+	gpio_free(gpio + 15);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -269,6 +281,7 @@ static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
 	.pulldowns	= BIT(2) | BIT(6) | BIT(8) | BIT(13)
 				| BIT(16) | BIT(17),
 	.setup		= sdp3430_twl_gpio_setup,
+	.teardown	= sdp3430_twl_gpio_teardown,
 };
 
 /* regulator consumer mappings */
arch/arm/mach-omap2/board-cm-t35.c +12 -0
index 28e7117..953824b 100644
@@ -476,11 +476,23 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
 	return 0;
 }
 
+static int cm_t35_twl_gpio_teardown(struct device *dev, unsigned gpio,
+				 unsigned ngpio)
+{
+	int wlan_rst = gpio + 2;
+
+	omap_hsmmc_deferred_del(mmc);
+	gpio_free(wlan_rst);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data cm_t35_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.setup          = cm_t35_twl_gpio_setup,
+	.teardown	= cm_t35_twl_gpio_teardown,
 };
 
 static struct twl4030_platform_data cm_t35_twldata = {
arch/arm/mach-omap2/board-devkit8000.c +13 -0
index 373ba75..fe93cbc 100644
@@ -255,6 +255,18 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int devkit8000_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */
+	gpio_free(gpio + TWL4030_GPIO_MAX + 0);
+	/* gpio + 7 is "DVI_PD" (out, active low) */
+	gpio_free(gpio + 7);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -263,6 +275,7 @@ static struct twl4030_gpio_platform_data devkit8000_gpio_data = {
 	.pulldowns	= BIT(1) | BIT(2) | BIT(6) | BIT(8) | BIT(13)
 				| BIT(15) | BIT(16) | BIT(17),
 	.setup		= devkit8000_twl_gpio_setup,
+	.teardown	= devkit8000_twl_gpio_teardown,
 };
 
 static struct regulator_consumer_supply devkit8000_vpll1_supplies[] = {
arch/arm/mach-omap2/board-igep0020.c +15 -0
index fb94fdc..5d47932 100644
@@ -436,12 +436,27 @@ static int igep_twl_gpio_setup(struct device *dev,
 	return 0;
 };
 
+static int igep_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
+	gpio_free(gpio + TWL4030_GPIO_MAX + 1);
+	if (machine_is_igep0030())
+		return 0;
+
+	gpio_free_array(igep2_twl_gpios, ARRAY_SIZE(igep2_twl_gpios));
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data igep_twl4030_gpio_pdata = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.use_leds	= true,
 	.setup		= igep_twl_gpio_setup,
+	.teardown	= igep_twl_gpio_teardown,
 };
 
 static int igep2_enable_dvi(struct omap_dss_device *dssdev)
arch/arm/mach-omap2/board-ldp.c +13 -0
index b5bc9b2..b41add4 100644
@@ -274,11 +274,24 @@ static int ldp_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio)
 	return 0;
 }
 
+static int ldp_twl_gpio_teardown(struct device *dev, unsigned gpio,
+							 unsigned ngpio)
+{
+	struct gpio gpios[] = {
+		{gpio + 7 , GPIOF_OUT_INIT_LOW, "LCD ENABLE"},
+		{gpio + 15, GPIOF_OUT_INIT_LOW, "LCD BACKLIGHT"},
+	};
+	gpio_free_array(gpios, ARRAY_SIZE(gpios));
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data ldp_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.setup		= ldp_twl_gpio_setup,
+	.teardown	= ldp_twl_gpio_teardown,
 };
 
 static struct regulator_consumer_supply ldp_vmmc1_supply[] = {
arch/arm/mach-omap2/board-omap3beagle.c +15 -0
index 2ec7bae..cbfe87e 100644
@@ -320,6 +320,20 @@ static int beagle_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int beagle_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* gpio + 1 is used for differently on beagle and beagle-Xm boards */
+	gpio_free(gpio + 1);
+	if (cpu_is_omap3630())
+		/* gpio + 2 is used only on Xm */
+		gpio_free(gpio + 2);
+	gpio_free(gpio + TWL4030_GPIO_MAX);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data beagle_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -329,6 +343,7 @@ static struct twl4030_gpio_platform_data beagle_gpio_data = {
 	.pulldowns	= BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
 				| BIT(15) | BIT(16) | BIT(17),
 	.setup		= beagle_twl_gpio_setup,
+	.teardown	= beagle_twl_gpio_teardown,
 };
 
 /* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */
arch/arm/mach-omap2/board-omap3evm.c +13 -0
index 47a9159..ae7e921 100644
@@ -388,12 +388,25 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int omap3evm_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* gpio + TWL4030_GPIO_MAX used for ledA, LCD Backlight control */
+	gpio_free(gpio + TWL4030_GPIO_MAX);
+	/* gpio + 7 used for DVI Enable */
+	gpio_free(gpio + 7);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.use_leds	= true,
 	.setup		= omap3evm_twl_gpio_setup,
+	.teardown	= omap3evm_twl_gpio_teardown,
 };
 
 static uint32_t board_keymap[] = {
arch/arm/mach-omap2/board-omap3pandora.c +11 -0
index faea4c8..9637bbb 100644
@@ -315,11 +315,22 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int omap3pandora_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(omap3pandora_mmc);
+	/* gpio + 13 drives 32kHz buffer for wifi module */
+	gpio_free(gpio + 13);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.setup		= omap3pandora_twl_gpio_setup,
+	.teardown	= omap3pandora_twl_gpio_teardown,
 };
 
 static struct regulator_consumer_supply pandora_vmmc1_supply[] = {
arch/arm/mach-omap2/board-omap3stalker.c +14 -0
index 1cad225..5c73750 100644
@@ -307,12 +307,26 @@ omap3stalker_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int
+omap3stalker_twl_gpio_teardown(struct device *dev,
+			    unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* gpio + TWL4030_GPIO_MAX used for ledA, LCD Backlight control */
+	gpio_free(gpio + TWL4030_GPIO_MAX);
+	/* gpio + 7 used for DVI Enable */
+	gpio_free(gpio + 7);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data omap3stalker_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.use_leds	= true,
 	.setup		= omap3stalker_twl_gpio_setup,
+	.teardown	= omap3stalker_twl_gpio_teardown,
 };
 
 static uint32_t board_keymap[] = {
arch/arm/mach-omap2/board-omap3touchbook.c +13 -0
index 932ac8e..d3752f2 100644
@@ -137,6 +137,18 @@ static int touchbook_twl_gpio_setup(struct device *dev,
 	return 0;
 }
 
+static int touchbook_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	/* gpio + 1 used for EHCI_nOC */
+	gpio_free(gpio + 1);
+	/* gpio + TWL4030_GPIO_MAX used for ledA, EHCI nEN_USB_PWR */
+	gpio_free(gpio + TWL4030_GPIO_MAX);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data touchbook_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -146,6 +158,7 @@ static struct twl4030_gpio_platform_data touchbook_gpio_data = {
 	.pulldowns	= BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13)
 				| BIT(15) | BIT(16) | BIT(17),
 	.setup		= touchbook_twl_gpio_setup,
+	.teardown	= touchbook_twl_gpio_teardown,
 };
 
 static struct regulator_consumer_supply touchbook_vdac_supply[] = {
arch/arm/mach-omap2/board-rx51-peripherals.c +11 -0
index 0e9d89a..e900d40 100644
@@ -702,6 +702,16 @@ static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
 	return 0;
 }
 
+static int rx51_twlgpio_teardown(struct device *dev, unsigned gpio, unsigned n)
+{
+	/* gpio + 6 used for backlight_pwm */
+	gpio_free(gpio + 6);
+	/* gpio + 7 used for speaker_en */
+	gpio_free(gpio + 7);
+
+	return 0;
+}
+
 static struct twl4030_gpio_platform_data rx51_gpio_data = {
 	.gpio_base		= OMAP_MAX_GPIO_LINES,
 	.irq_base		= TWL4030_GPIO_IRQ_BASE,
@@ -712,6 +722,7 @@ static struct twl4030_gpio_platform_data rx51_gpio_data = {
 				| BIT(12) | BIT(13) | BIT(14) | BIT(15)
 				| BIT(16) | BIT(17) ,
 	.setup			= rx51_twlgpio_setup,
+	.teardown		= rx51_twlgpio_teardown,
 };
 
 static struct twl4030_ins sleep_on_seq[] __initdata = {
arch/arm/mach-omap2/board-zoom-peripherals.c +10 -0
index 1c200ee..a5fd25a 100644
@@ -245,6 +245,15 @@ static int zoom_twl_gpio_setup(struct device *dev,
 	return ret;
 }
 
+static int zoom_twl_gpio_teardown(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	omap_hsmmc_deferred_del(mmc);
+	gpio_free(LCD_PANEL_ENABLE_GPIO);
+
+	return 0;
+}
+
 /* EXTMUTE callback function */
 static void zoom2_set_hs_extmute(int mute)
 {
@@ -256,6 +265,7 @@ static struct twl4030_gpio_platform_data zoom_gpio_data = {
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 	.setup		= zoom_twl_gpio_setup,
+	.teardown	= zoom_twl_gpio_teardown,
 };
 
 static struct twl4030_platform_data zoom_twldata = {
Signature · 1 line
1.7.1