[RFC] AM35xx glue code for M-USB driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

we're running a 4.x kernel on a board with an AM3505 CPU and would like
to use device trees. The AM35xx glue code for the M-USB controller
didn't support configuration from a DT yet. I now got it working
somehow, but I'm not sure if I'm doing it the correct way. So this post
is not meant as a patch submission, but more as a request for comments
or help.

In the older kernel we were using before (3.2.x), some data structures
were set up in the respective board file and then passed to the function
am35x_probe(). For the use with DT, I added the function
am35x_get_config, which sets up these data structures with default
values and then tries to read settings from the DT.
The device .compatible declaration is now "ti,am35x-musb", so it's
separate from "ti,omap3-musb" (as used in omap2430.c).

Now the two things I'm not so sure about:

a) We needed to set pointers to machine-specific functions like
am35x_musb_clear_irq etc. These functions are implemented in
arch/arm/mach-omap2/omap_phy_internal.c, and declared in
arch/arm/mach-omap2/usb.h.
As this header file can't be included easily from am35x.c, I moved the
declarations to include/linux/platform_data/usb-omap.h. I hope that's
OK, but would be happy about suggestions.

b) The M-USB port on our board is wired as host only. If a device is
unplugged, the driver normally goes into some idle state and waits for
an ID signal change. But on our board that never happens.
So I added two checks for MUSB_OTG mode to support our hardware. Then I
noticed similar code was removed from this file three years ago (commit
032ec49f5351e9cb242b1a1c367d14415043ab95), and I don't know if these
lines might break something on other hardware.

Best regards,
Rolf

---
Index: linux4/drivers/usb/musb/am35x.c
===================================================================
--- linux4.orig/drivers/usb/musb/am35x.c
+++ linux4/drivers/usb/musb/am35x.c
@@ -188,6 +188,10 @@ static void am35x_musb_try_idle(struct m
 {
 	static unsigned long last_timer;

+	/* do not try if not in OTG mode */
+	if (musb->port_mode != MUSB_OTG)
+		return;
+
 	if (timeout == 0)
 		timeout = jiffies + msecs_to_jiffies(3);

@@ -323,8 +327,9 @@ eoi:
 		musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
 	}

-	/* Poll for ID change */
-	if (musb->xceiv->otg->state == OTG_STATE_B_IDLE)
+	/* Poll for ID change (in OTG mode only) */
+	if (musb->port_mode == MUSB_OTG &&
+		musb->xceiv->otg->state == OTG_STATE_B_IDLE)
 		mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);

 	spin_unlock_irqrestore(&musb->lock, flags);
@@ -458,6 +463,70 @@ static const struct platform_device_info
 	.dma_mask	= DMA_BIT_MASK(32),
 };

+static struct musb_hdrc_platform_data *
+am35x_get_config(struct platform_device *pdev)
+{
+	struct musb_hdrc_platform_data *pdata;
+	struct omap_musb_board_data *bdata;
+	struct musb_hdrc_config *config;
+	struct device_node *np;
+	int val, ret;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		goto err_out;
+
+	bdata = devm_kzalloc(&pdev->dev, sizeof(*bdata), GFP_KERNEL);
+	if (!bdata)
+		goto err_pdata;
+
+	config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
+	if (!config)
+		goto err_bdata;
+
+	/* Set defaults */
+	config->num_eps = 16;
+	config->ram_bits = 12;
+	config->multipoint = true;
+
+	bdata->interface_type = MUSB_INTERFACE_UTMI;
+	bdata->mode = MUSB_OTG;
+	bdata->power = 500;
+	bdata->extvbus = 1;
+	bdata->set_phy_power = am35x_musb_phy_power;
+	bdata->clear_irq = am35x_musb_clear_irq;
+	bdata->set_mode = am35x_set_mode;
+	bdata->reset = am35x_musb_reset;
+
+	pdata->mode = MUSB_OTG;
+	pdata->power = 250;
+	pdata->board_data = bdata;
+	pdata->config = config;
+
+	/* Read settings from device tree */
+	np = pdev->dev.of_node;
+	if (np) {
+		of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
+		of_property_read_u32(np, "interface-type",
+				(u32 *)&bdata->interface_type);
+		of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
+		of_property_read_u32(np, "power", (u32 *)&pdata->power);
+
+		ret = of_property_read_u32(np, "multipoint", &val);
+		if (!ret && val)
+			config->multipoint = true;
+	}
+	return pdata;
+
+err_bdata:
+	kfree(bdata);
+err_pdata:
+	kfree(pdata);
+err_out:
+	return NULL;
+}
+
 static int am35x_probe(struct platform_device *pdev)
 {
 	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);
@@ -475,14 +544,20 @@ static int am35x_probe(struct platform_d
 		goto err0;
 	}

-	phy_clk = clk_get(&pdev->dev, "fck");
+	if (!pdata) {
+		pdata = am35x_get_config(pdev);
+		if (!pdata)
+			goto err1;
+	}
+
+	phy_clk = clk_get(&pdev->dev, "hsotgusb_fck");
 	if (IS_ERR(phy_clk)) {
 		dev_err(&pdev->dev, "failed to get PHY clock\n");
 		ret = PTR_ERR(phy_clk);
 		goto err3;
 	}

-	clk = clk_get(&pdev->dev, "ick");
+	clk = clk_get(&pdev->dev, "hsotgusb_ick");
 	if (IS_ERR(clk)) {
 		dev_err(&pdev->dev, "failed to get clock\n");
 		ret = PTR_ERR(clk);
@@ -544,6 +619,7 @@ err4:
 	clk_put(phy_clk);

 err3:
+err1:
 	kfree(glue);

 err0:
@@ -611,12 +687,25 @@ static int am35x_resume(struct device *d

 static SIMPLE_DEV_PM_OPS(am35x_pm_ops, am35x_suspend, am35x_resume);

+#ifdef CONFIG_OF
+static const struct of_device_id am35x_id_table[] = {
+	{
+		.compatible = "ti,am35x-musb"
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, am35x_id_table);
+#endif
+
 static struct platform_driver am35x_driver = {
 	.probe		= am35x_probe,
 	.remove		= am35x_remove,
 	.driver		= {
 		.name	= "musb-am35x",
 		.pm	= &am35x_pm_ops,
+#ifdef CONFIG_OF
+		.of_match_table = of_match_ptr(am35x_id_table),
+#endif
 	},
 };

Index: linux4/arch/arm/mach-omap2/usb.h
===================================================================
--- linux4.orig/arch/arm/mach-omap2/usb.h
+++ linux4/arch/arm/mach-omap2/usb.h
@@ -63,8 +63,3 @@ struct usbhs_phy_data {
 extern void usb_musb_init(struct omap_musb_board_data *board_data);
 extern void usbhs_init(struct usbhs_omap_platform_data *pdata);
 extern int usbhs_init_phys(struct usbhs_phy_data *phy, int num_phys);
-
-extern void am35x_musb_reset(void);
-extern void am35x_musb_phy_power(u8 on);
-extern void am35x_musb_clear_irq(void);
-extern void am35x_set_mode(u8 musb_mode);
Index: linux4/include/linux/platform_data/usb-omap.h
===================================================================
--- linux4.orig/include/linux/platform_data/usb-omap.h
+++ linux4/include/linux/platform_data/usb-omap.h
@@ -86,3 +86,8 @@ enum musb_interface {
 	MUSB_INTERFACE_ULPI,
 	MUSB_INTERFACE_UTMI
 };
+
+extern void am35x_musb_reset(void);
+extern void am35x_musb_phy_power(u8 on);
+extern void am35x_musb_clear_irq(void);
+extern void am35x_set_mode(u8 musb_mode);
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux