Skip to contentSkip to conversation

s3c-hsudc: regulator handling and a lot of fixes

PATCH New Heiko Stübner 4 participants 19 messages Dec 19, 2011 – Dec 21, 2011

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

v4 cover s3c-hsudc: regulator handling and a lot of fixes

In his response to the first submission Felipe Balbi asked to also move the driver to the new udc_start and udc_stop functions and to make an effort to reduce dependencies on archictecture code.

v3 of the series does not try to provide a remove function, due to the possible lifetime problem of gadget.dev found by Russel King.

v4 also gets rid of the the_controller global and uses container_of instead and moves the platform-data header to include/linux/platform_data.

The first patch reduces the number of arch dependencies by one by moving the platform data struct to a header unter include/linux/usb.

The fourth and fifth patches implement the move to udc_start / udc_stop

And the sixt patch finally allows the s3c-hsudc driver to control its supplying regulators as intended in the first place.

The regulator calls can use the regulators unconditionally and let necessary "stubbing and mapping" happen through the regulator framework, according to for example
http://marc.info/?l=linux-netdev&m=131914562120725&w=2
meaning there is no need to gracefully fail if a regulator is not present.

Each patch was compile-tested individually, the series applies cleanly against linux-next from 2011-12-16.

Real-life testing happened on S3C2416 hardware.
Heiko Stuebner (8):
s3c-hsudc: move platform_data struct to global header
s3c-hsudc: add __devinit to probe function
s3c-hsudc: add missing otg_put_transceiver in probe
s3c-hsudc: move device registration to probe
s3c-hsudc: use udc_start and udc_stop functions
s3c-hsudc: Add regulator handling
s3c-hsudc: use release_mem_region instead of release_resource
s3c-hsudc: remove the_controller global

 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +----
 drivers/usb/gadget/s3c-hsudc.c           |  120 +++++++++++++++++-------------
 include/linux/platform_data/s3c-hsudc.h  |   34 +++++++++
 5 files changed, 106 insertions(+), 65 deletions(-)
 create mode 100644 include/linux/platform_data/s3c-hsudc.h
Signature · 1 line
1.7.2.3
#1 lore raw

PATCH v4 1/8 s3c-hsudc: move platform_data struct to global header

Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code.

---
 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +------------
 drivers/usb/gadget/s3c-hsudc.c           |    2 +-
 include/linux/platform_data/s3c-hsudc.h  |   34 ++++++++++++++++++++++++++++++
 5 files changed, 38 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/platform_data/s3c-hsudc.h
arch/arm/mach-s3c2416/mach-smdk2416.c +1 -0
index a9eee53..6345bcb 100644
@@ -50,6 +50,7 @@
 #include <plat/nand.h>
 #include <plat/sdhci.h>
 #include <plat/udc.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
arch/arm/plat-samsung/devs.c +1 -0
index 4ca8b57..92b4c02 100644
@@ -29,6 +29,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 #include <linux/ioport.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <asm/irq.h>
 #include <asm/pmu.h>
arch/arm/plat-samsung/include/plat/udc.h +1 -14
index 8c22d58..de8e228 100644
@@ -37,20 +37,7 @@ struct s3c2410_udc_mach_info {
 
 extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
 
-/**
- * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
- * @epnum: Number of endpoints to be instantiated by the controller driver.
- * @gpio_init: Platform specific USB related GPIO initialization.
- * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
- *
- * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
- * controllers.
- */
-struct s3c24xx_hsudc_platdata {
-	unsigned int	epnum;
-	void		(*gpio_init)(void);
-	void		(*gpio_uninit)(void);
-};
+struct s3c24xx_hsudc_platdata;
 
 extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
 
drivers/usb/gadget/s3c-hsudc.c +1 -1
index 6f2a041..606b20f 100644
@@ -28,9 +28,9 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/prefetch.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <mach/regs-s3c2443-clock.h>
-#include <plat/udc.h>
 
 #define S3C_HSUDC_REG(x)	(x)
 
include/linux/platform_data/s3c-hsudc.h new file +34 -0
new file mode 100644
index 0000000..6fa1093
@@ -0,0 +1,34 @@
+/*
+ * S3C24XX USB 2.0 High-speed USB controller gadget driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints.
+ * Each endpoint can be configured as either in or out endpoint. Endpoints
+ * can be configured for Bulk or Interrupt transfer mode.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_USB_S3C_HSUDC_H
+#define __LINUX_USB_S3C_HSUDC_H
+
+/**
+ * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
+ * @epnum: Number of endpoints to be instantiated by the controller driver.
+ * @gpio_init: Platform specific USB related GPIO initialization.
+ * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
+ *
+ * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
+ * controllers.
+ */
+struct s3c24xx_hsudc_platdata {
+	unsigned int	epnum;
+	void		(*gpio_init)(void);
+	void		(*gpio_uninit)(void);
+};
+
+#endif	/* __LINUX_USB_S3C_HSUDC_H */
Signature · 1 line
1.7.2.3
#2 lore raw

PATCH 1/8 s3c-hsudc: move platform_data struct to global header

Hi,

Quoted 8 lines · Heiko St?bner

Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code.

---
 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +------------

I would like to have ack from Ben and/or Kukjin before applying this one. Ben are you ok with this patch ?

Signature · 8 lines
balbi
-------------- 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/20111220/d9343b33/attachment.sig>
#3 lore raw

PATCH v4 1/8 s3c-hsudc: move platform_data struct to global header

Am Dienstag, 20. Dezember 2011, 12:25:00 schrieb Felipe Balbi:

Quoted 9 lines

Hi,

Quoted 6 lines · Heiko St?bner

Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code.

---

Quoted 6 lines
Quoted 3 lines
 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +------------

I would like to have ack from Ben and/or Kukjin before applying this one. Ben are you ok with this patch ?

I think Kukjin does more acking if this stuff currently, so hopefully he will see this mail.

Heiko

#4 lore raw

PATCH 1/8 s3c-hsudc: move platform_data struct to global header

Quoted 11 lines · Heiko St?bner

Am Dienstag, 20. Dezember 2011, 12:25:00 schrieb Felipe Balbi:

Quoted 9 lines

Hi,

Quoted 6 lines · Heiko St?bner

Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code.

---

Quoted 9 lines
Quoted 6 lines
Quoted 3 lines
 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +------------

I would like to have ack from Ben and/or Kukjin before applying this one. Ben are you ok with this patch ?

I think Kukjin does more acking if this stuff currently, so hopefully he will see this mail.

Hi Felipe,

Looks ok to me, you can go ahead with my ack.

Thanks.

Best regards,
Kgene.
--
Kukjin Kim <[email protected]>, Senior Engineer, SW Solution Development Team, Samsung Electronics Co., Ltd.

#5 lore raw

PATCH 1/8 s3c-hsudc: move platform_data struct to global header

Quoted 18 lines · Kukjin Kim
Quoted 17 lines · Heiko St?bner

Am Dienstag, 20. Dezember 2011, 12:25:00 schrieb Felipe Balbi:

Quoted 15 lines

Hi,

Quoted 9 lines · Heiko St?bner

Gadget drivers should be compilable on all architectures. This patch removes one dependency on architecture-specific code.

---

 arch/arm/mach-s3c2416/mach-smdk2416.c    |    1 +
 arch/arm/plat-samsung/devs.c             |    1 +
 arch/arm/plat-samsung/include/plat/udc.h |   15 +------------

I would like to have ack from Ben and/or Kukjin before applying this one. Ben are you ok with this patch ?

Quoted 8 lines
Quoted 3 lines

I think Kukjin does more acking if this stuff currently, so hopefully he will see this mail.

Hi Felipe,

Looks ok to me, you can go ahead with my ack.

Thanks.

Signature · 8 lines
balbi
-------------- 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/20111221/59212d2c/attachment.sig>
#6 lore raw

PATCH v4 2/8 s3c-hsudc: add __devinit to probe function

In reply to Heiko Stübner

Fixes possible section mismatch warnings.

---
 drivers/usb/gadget/s3c-hsudc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +1 -1
index 606b20f..86e336e 100644
@@ -1260,7 +1260,7 @@ static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.vbus_draw	= s3c_hsudc_vbus_draw,
 };
 
-static int s3c_hsudc_probe(struct platform_device *pdev)
+static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
Signature · 1 line
1.7.2.3
#7 lore raw

PATCH v4 3/8 s3c-hsudc: add missing otg_put_transceiver in probe

In reply to Heiko Stübner

The number of get and put calls should always be equal.

---
 drivers/usb/gadget/s3c-hsudc.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +3 -0
index 86e336e..1171efb 100644
@@ -1366,6 +1366,9 @@ err_remap:
 	kfree(hsudc->mem_rsrc);
 
 err_res:
+	if (hsudc->transceiver)
+		otg_put_transceiver(hsudc->transceiver);
+
 	kfree(hsudc);
 	return ret;
 }
Signature · 1 line
1.7.2.3
#8 lore raw

PATCH v4 4/8 s3c-hsudc: move device registration to probe

In reply to Heiko Stübner

Instead of adding and deleting the gadget device in the start and stop invocations. Use device_register in the probe method to initialize and add the gadget device.

---
 drivers/usb/gadget/s3c-hsudc.c |   17 ++++++++---------
 1 files changed, 8 insertions(+), 9 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +8 -9
index 1171efb..8792830 100644
@@ -1156,11 +1156,6 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 	hsudc->driver = driver;
 	hsudc->gadget.dev.driver = &driver->driver;
 	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
-	ret = device_add(&hsudc->gadget.dev);
-	if (ret) {
-		dev_err(hsudc->dev, "failed to probe gadget device");
-		return ret;
-	}
 
 	ret = bind(&hsudc->gadget);
 	if (ret) {
@@ -1180,8 +1175,6 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 					hsudc->gadget.name);
 			driver->unbind(&hsudc->gadget);
 
-			device_del(&hsudc->gadget.dev);
-
 			hsudc->driver = NULL;
 			hsudc->gadget.dev.driver = NULL;
 			return ret;
@@ -1222,7 +1215,6 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
 		(void) otg_set_peripheral(hsudc->transceiver, NULL);
 
 	driver->unbind(&hsudc->gadget);
-	device_del(&hsudc->gadget.dev);
 	disable_irq(hsudc->irq);
 
 	dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
@@ -1307,7 +1299,6 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 
 	spin_lock_init(&hsudc->lock);
 
-	device_initialize(&hsudc->gadget.dev);
 	dev_set_name(&hsudc->gadget.dev, "gadget");
 
 	hsudc->gadget.max_speed = USB_SPEED_HIGH;
@@ -1348,12 +1339,20 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 	disable_irq(hsudc->irq);
 	local_irq_enable();
 
+	ret = device_register(&hsudc->gadget.dev);
+	if (ret) {
+		put_device(&hsudc->gadget.dev);
+		goto err_add_device;
+	}
+
 	ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
 	if (ret)
 		goto err_add_udc;
 
 	return 0;
 err_add_udc:
+	device_unregister(&hsudc->gadget.dev);
+err_add_device:
 	clk_disable(hsudc->uclk);
 	clk_put(hsudc->uclk);
 err_clk:
Signature · 1 line
1.7.2.3
#9 lore raw

PATCH v4 5/8 s3c-hsudc: use udc_start and udc_stop functions

In reply to Heiko Stübner

udc_start and udc_stop reduce code duplication in comparison to start and stop generalising calls done by all drivers (i.e. bind and unbind) and moving these calls to common code.

---
 drivers/usb/gadget/s3c-hsudc.c |   44 ++++++++++++---------------------------
 1 files changed, 14 insertions(+), 30 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +14 -30
index 8792830..d17cbcf 100644
@@ -282,8 +282,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
  * All the endpoints are stopped and any pending transfer requests if any on
  * the endpoint are terminated.
  */
-static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
-			  struct usb_gadget_driver *driver)
+static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
 {
 	struct s3c_hsudc_ep *hsep;
 	int epnum;
@@ -295,10 +294,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
 		hsep->stopped = 1;
 		s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
 	}
-
-	spin_unlock(&hsudc->lock);
-	driver->disconnect(&hsudc->gadget);
-	spin_lock(&hsudc->lock);
 }
 
 /**
@@ -1135,16 +1130,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
 	return IRQ_HANDLED;
 }
 
-static int s3c_hsudc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int s3c_hsudc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	struct s3c_hsudc *hsudc = the_controller;
 	int ret;
 
 	if (!driver
 		|| driver->max_speed < USB_SPEED_FULL
-		|| !bind
-		|| !driver->unbind || !driver->disconnect || !driver->setup)
+		|| !driver->setup)
 		return -EINVAL;
 
 	if (!hsudc)
@@ -1155,17 +1149,6 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 
 	hsudc->driver = driver;
 	hsudc->gadget.dev.driver = &driver->driver;
-	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
-
-	ret = bind(&hsudc->gadget);
-	if (ret) {
-		dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
-		device_del(&hsudc->gadget.dev);
-
-		hsudc->driver = NULL;
-		hsudc->gadget.dev.driver = NULL;
-		return ret;
-	}
 
 	/* connect to bus through transceiver */
 	if (hsudc->transceiver) {
@@ -1173,8 +1156,6 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 		if (ret) {
 			dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
 					hsudc->gadget.name);
-			driver->unbind(&hsudc->gadget);
-
 			hsudc->driver = NULL;
 			hsudc->gadget.dev.driver = NULL;
 			return ret;
@@ -1192,7 +1173,8 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 	return 0;
 }
 
-static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	struct s3c_hsudc *hsudc = the_controller;
 	unsigned long flags;
@@ -1200,21 +1182,22 @@ static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
 	if (!hsudc)
 		return -ENODEV;
 
-	if (!driver || driver != hsudc->driver || !driver->unbind)
+	if (!driver || driver != hsudc->driver)
 		return -EINVAL;
 
 	spin_lock_irqsave(&hsudc->lock, flags);
-	hsudc->driver = 0;
+	hsudc->driver = NULL;
+	hsudc->gadget.dev.driver = NULL;
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 	s3c_hsudc_uninit_phy();
 	if (hsudc->pd->gpio_uninit)
 		hsudc->pd->gpio_uninit();
-	s3c_hsudc_stop_activity(hsudc, driver);
+	s3c_hsudc_stop_activity(hsudc);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 
 	if (hsudc->transceiver)
 		(void) otg_set_peripheral(hsudc->transceiver, NULL);
 
-	driver->unbind(&hsudc->gadget);
 	disable_irq(hsudc->irq);
 
 	dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
@@ -1247,8 +1230,8 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.get_frame	= s3c_hsudc_gadget_getframe,
-	.start		= s3c_hsudc_start,
-	.stop		= s3c_hsudc_stop,
+	.udc_start	= s3c_hsudc_start,
+	.udc_stop	= s3c_hsudc_stop,
 	.vbus_draw	= s3c_hsudc_vbus_draw,
 };
 
@@ -1310,6 +1293,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 
 	hsudc->gadget.is_otg = 0;
 	hsudc->gadget.is_a_peripheral = 0;
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 
 	s3c_hsudc_setup_ep(hsudc);
 
Signature · 1 line
1.7.2.3
#10 lore raw

PATCH 5/8 s3c-hsudc: use udc_start and udc_stop functions

Hi,

Quoted 35 lines · Heiko St?bner

udc_start and udc_stop reduce code duplication in comparison to start and stop generalising calls done by all drivers (i.e. bind and unbind) and moving these calls to common code.

---
 drivers/usb/gadget/s3c-hsudc.c |   44 ++++++++++++---------------------------
 1 files changed, 14 insertions(+), 30 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +1 -6
index 8792830..d17cbcf 100644
@@ -282,8 +282,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
  * All the endpoints are stopped and any pending transfer requests if any on
  * the endpoint are terminated.
  */
-static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
-			  struct usb_gadget_driver *driver)
+static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
 {
 	struct s3c_hsudc_ep *hsep;
 	int epnum;
@@ -295,10 +294,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
 		hsep->stopped = 1;
 		s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
 	}
-
-	spin_unlock(&hsudc->lock);
-	driver->disconnect(&hsudc->gadget);
-	spin_lock(&hsudc->lock);
 }
 
 /**

drivers/usb/gadget/s3c-hsudc.c static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) · line 1136

Quoted 9 lines
drivers/usb/gadget/s3c-hsudc.c +2 -2
@@ -1135,16 +1130,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
 	return IRQ_HANDLED;
 }
 
-static int s3c_hsudc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int s3c_hsudc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
 	struct s3c_hsudc *hsudc = the_controller;

I remember commenting that this 'the_controller' global could be dropped. I will add a patch to this series myself this time otherwise we will not have time to get this in during 3.3 merge window, but next time please make sure you fix all comments (or give reasons not to do so) before sending another version.

Signature · 8 lines
balbi
-------------- 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/20111220/3d738792/attachment-0001.sig>
#11 lore raw

PATCH v4 6/8 s3c-hsudc: Add regulator handling

In reply to Heiko Stübner

The udc has three supplies: vdda (3.3V), vddi (1.2V) and vddosc (1.8-3.3V). Turn these on and off on start and stop calls.

---
 drivers/usb/gadget/s3c-hsudc.c |   41 ++++++++++++++++++++++++++++++++++++---
 1 files changed, 37 insertions(+), 4 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +37 -4
index d17cbcf..c8ac13a 100644
@@ -29,6 +29,7 @@
 #include <linux/usb/otg.h>
 #include <linux/prefetch.h>
 #include <linux/platform_data/s3c-hsudc.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/regs-s3c2443-clock.h>
 
@@ -87,6 +88,12 @@
 #define DATA_STATE_XMIT			(1)
 #define DATA_STATE_RECV			(2)
 
+static const char * const s3c_hsudc_supply_names[] = {
+	"vdda",		/* analog phy supply, 3.3V */
+	"vddi",		/* digital phy supply, 1.2V */
+	"vddosc",	/* oscillator supply, 1.8V - 3.3V */
+};
+
 /**
  * struct s3c_hsudc_ep - Endpoint representation used by driver.
  * @ep: USB gadget layer representation of device endpoint.
@@ -139,6 +146,7 @@ struct s3c_hsudc {
 	struct device *dev;
 	struct s3c24xx_hsudc_platdata *pd;
 	struct otg_transceiver *transceiver;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
 	spinlock_t lock;
 	void __iomem *regs;
 	struct resource *mem_rsrc;
@@ -1150,15 +1158,20 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
 	hsudc->driver = driver;
 	hsudc->gadget.dev.driver = &driver->driver;
 
+	ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
+				    hsudc->supplies);
+	if (ret != 0) {
+		dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
+		goto err_supplies;
+	}
+
 	/* connect to bus through transceiver */
 	if (hsudc->transceiver) {
 		ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
 		if (ret) {
 			dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
 					hsudc->gadget.name);
-			hsudc->driver = NULL;
-			hsudc->gadget.dev.driver = NULL;
-			return ret;
+			goto err_otg;
 		}
 	}
 
@@ -1171,6 +1184,12 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
 		hsudc->pd->gpio_init();
 
 	return 0;
+err_otg:
+	regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
+	hsudc->driver = NULL;
+	hsudc->gadget.dev.driver = NULL;
+	return ret;
 }
 
 static int s3c_hsudc_stop(struct usb_gadget *gadget,
@@ -1200,6 +1219,8 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
 
 	disable_irq(hsudc->irq);
 
+	regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+
 	dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
 			driver->driver.name);
 	return 0;
@@ -1241,7 +1262,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct s3c_hsudc *hsudc;
 	struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
-	int ret;
+	int ret, i;
 
 	hsudc = kzalloc(sizeof(struct s3c_hsudc) +
 			sizeof(struct s3c_hsudc_ep) * pd->epnum,
@@ -1258,6 +1279,16 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 
 	hsudc->transceiver = otg_get_transceiver();
 
+	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
+		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
+
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
+				 hsudc->supplies);
+	if (ret != 0) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		goto err_supplies;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(dev, "unable to obtain driver resource data\n");
@@ -1352,6 +1383,8 @@ err_res:
 	if (hsudc->transceiver)
 		otg_put_transceiver(hsudc->transceiver);
 
+	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
 	kfree(hsudc);
 	return ret;
 }
Signature · 1 line
1.7.2.3
#12 lore raw

PATCH v4 7/8 s3c-hsudc: use release_mem_region instead of release_resource

In reply to Heiko Stübner

As the memory region is requested through request_mem_region use the correct paired method to release it in the error path and don't go "beneath the API" as pointed out by Russel King.

---
 drivers/usb/gadget/s3c-hsudc.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +1 -3
index c8ac13a..8e69758 100644
@@ -1376,9 +1376,7 @@ err_irq:
 	iounmap(hsudc->regs);
 
 err_remap:
-	release_resource(hsudc->mem_rsrc);
-	kfree(hsudc->mem_rsrc);
-
+	release_mem_region(res->start, resource_size(res));
 err_res:
 	if (hsudc->transceiver)
 		otg_put_transceiver(hsudc->transceiver);
Signature · 1 line
1.7.2.3
#13 lore raw

PATCH 7/8 s3c-hsudc: use release_mem_region instead of release_resource

Quoted 3 lines · Heiko St?bner

As the memory region is requested through request_mem_region use the correct paired method to release it in the error path and don't go "beneath the API" as pointed out by Russel King.

Please correct the spelling, thanks.

#14 lore raw

PATCH 7/8 s3c-hsudc: use release_mem_region instead of release_resource

Quoted 6 lines · Russell King - ARM Linux
Quoted 3 lines · Heiko St?bner

As the memory region is requested through request_mem_region use the correct paired method to release it in the error path and don't go "beneath the API" as pointed out by Russel King.

Please correct the spelling, thanks.

Just did, do you prefer that I add a Reported-by: Russell instead of that mention ?

Signature · 8 lines
balbi
-------------- 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/20111220/ea81203d/attachment.sig>
#15 lore raw

PATCH 7/8 s3c-hsudc: use release_mem_region instead of release_resource

Quoted 10 lines · Felipe Balbi
Quoted 6 lines · Russell King - ARM Linux
Quoted 3 lines · Heiko St?bner

As the memory region is requested through request_mem_region use the correct paired method to release it in the error path and don't go "beneath the API" as pointed out by Russel King.

Please correct the spelling, thanks.

Just did, do you prefer that I add a Reported-by: Russell instead of that mention ?

If you wish - I don't mind. If you do, please use an email address of rmk+kernel at arm.linux.org.uk in the attributations. Thanks.

#16 lore raw

PATCH v4 8/8 s3c-hsudc: remove the_controller global

In reply to Heiko Stübner

Instead use container_of to retrieve the s3c_hsudc from the struct usb_gadget pointer.

---
 drivers/usb/gadget/s3c-hsudc.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +6 -5
index 8e69758..23cac9d 100644
@@ -161,7 +161,6 @@ struct s3c_hsudc {
 #define ep_index(_ep)		((_ep)->bEndpointAddress & \
 					USB_ENDPOINT_NUMBER_MASK)
 
-static struct s3c_hsudc *the_controller;
 static const char driver_name[] = "s3c-udc";
 static const char ep0name[] = "ep0-control";
 
@@ -1141,7 +1140,8 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
 static int s3c_hsudc_start(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc =
+			container_of(gadget, struct s3c_hsudc, gadget);
 	int ret;
 
 	if (!driver
@@ -1195,7 +1195,8 @@ err_supplies:
 static int s3c_hsudc_stop(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc =
+			container_of(gadget, struct s3c_hsudc, gadget);
 	unsigned long flags;
 
 	if (!hsudc)
@@ -1238,7 +1239,8 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
 
 static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc =
+			container_of(gadget, struct s3c_hsudc, gadget);
 
 	if (!hsudc)
 		return -ENODEV;
@@ -1272,7 +1274,6 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
-	the_controller = hsudc;
 	platform_set_drvdata(pdev, dev);
 	hsudc->dev = dev;
 	hsudc->pd = pdev->dev.platform_data;
Signature · 1 line
1.7.2.3
#17 lore raw

PATCH 8/8 s3c-hsudc: remove the_controller global

Hi,

Quoted 4 lines · Heiko St?bner

Instead use container_of to retrieve the s3c_hsudc from the struct usb_gadget pointer.

aha, it's here. So I replied too fast. Sorry about that and thanks for doing this.

Signature · 8 lines
balbi
-------------- 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/20111220/9ec3e5da/attachment.sig>
#18 lore raw

PATCH 8/8 s3c-hsudc: remove the_controller global

In reply to Heiko Stübner
Quoted 21 lines · Heiko St?bner

Instead use container_of to retrieve the s3c_hsudc from the struct usb_gadget pointer.

---
 drivers/usb/gadget/s3c-hsudc.c |   11 ++++++-----
 1 files changed, 6 insertions(+), 5 deletions(-)
drivers/usb/gadget/s3c-hsudc.c +0 -1
index 8e69758..23cac9d 100644
@@ -161,7 +161,6 @@ struct s3c_hsudc {
 #define ep_index(_ep)		((_ep)->bEndpointAddress & \
 					USB_ENDPOINT_NUMBER_MASK)
 
-static struct s3c_hsudc *the_controller;
 static const char driver_name[] = "s3c-udc";
 static const char ep0name[] = "ep0-control";
 

drivers/usb/gadget/s3c-hsudc.c static irqreturn_t s3c_hsudc_irq(int irq, void *_dev) · line 1144

Quoted 6 lines
drivers/usb/gadget/s3c-hsudc.c +2 -1
@@ -1141,7 +1140,8 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
 static int s3c_hsudc_start(struct usb_gadget *gadget,
 		struct usb_gadget_driver *driver)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc =
+			container_of(gadget, struct s3c_hsudc, gadget);

I have changed all these container_of() to your to_hsudc() helper function.

Signature · 8 lines
balbi
-------------- 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/20111220/e3d28962/attachment.sig>