usb: phy: ab8500-usb: add platform_device_id table
[linux-2.6-microblaze.git] / drivers / usb / phy / phy-ab8500-usb.c
index 4acef26..a0f7bec 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/notifier.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
 #include <linux/mfd/abx500.h>
 #include <linux/mfd/abx500/ab8500.h>
 #include <linux/usb/musb-ux500.h>
@@ -126,6 +128,7 @@ struct ab8500_usb {
        unsigned vbus_draw;
        struct work_struct phy_dis_work;
        enum ab8500_usb_mode mode;
+       struct clk *sysclk;
        struct regulator *v_ape;
        struct regulator *v_musb;
        struct regulator *v_ulpi;
@@ -252,6 +255,9 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host)
        if (IS_ERR(ab->pinctrl))
                dev_err(ab->dev, "could not get/set default pinstate\n");
 
+       if (clk_prepare_enable(ab->sysclk))
+               dev_err(ab->dev, "can't prepare/enable clock\n");
+
        ab8500_usb_regulator_enable(ab);
 
        abx500_mask_and_set_register_interruptible(ab->dev,
@@ -274,6 +280,8 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
        /* Needed to disable the phy.*/
        ab8500_usb_wd_workaround(ab);
 
+       clk_disable_unprepare(ab->sysclk);
+
        ab8500_usb_regulator_disable(ab);
 
        if (!IS_ERR(ab->pinctrl)) {
@@ -286,7 +294,8 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host)
                else if (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
                        dev_err(ab->dev, "could not set pins to sleep state\n");
 
-               /* as USB pins are shared with idddet, release them to allow
+               /*
+                * as USB pins are shared with iddet, release them to allow
                 * iddet to request them
                 */
                pinctrl_put(ab->pinctrl);
@@ -553,7 +562,7 @@ static irqreturn_t ab8500_usb_disconnect_irq(int irq, void *data)
 
 static irqreturn_t ab8500_usb_link_status_irq(int irq, void *data)
 {
-       struct ab8500_usb *ab = (struct ab8500_usb *) data;
+       struct ab8500_usb *ab = (struct ab8500_usb *)data;
 
        abx500_usb_link_status_update(ab);
 
@@ -627,7 +636,7 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg,
         * is fixed.
         */
 
-       if ((ab->mode != USB_IDLE) && (!gadget)) {
+       if ((ab->mode != USB_IDLE) && !gadget) {
                ab->mode = USB_IDLE;
                schedule_work(&ab->phy_dis_work);
        }
@@ -651,7 +660,7 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
         * is fixed.
         */
 
-       if ((ab->mode != USB_IDLE) && (!host)) {
+       if ((ab->mode != USB_IDLE) && !host) {
                ab->mode = USB_IDLE;
                schedule_work(&ab->phy_dis_work);
        }
@@ -659,6 +668,33 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
        return 0;
 }
 
+static void ab8500_usb_restart_phy(struct ab8500_usb *ab)
+{
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       AB8500_BIT_PHY_CTRL_DEVICE_EN,
+                       AB8500_BIT_PHY_CTRL_DEVICE_EN);
+
+       udelay(100);
+
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       AB8500_BIT_PHY_CTRL_DEVICE_EN,
+                       0);
+
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       AB8500_BIT_PHY_CTRL_HOST_EN,
+                       AB8500_BIT_PHY_CTRL_HOST_EN);
+
+       udelay(100);
+
+       abx500_mask_and_set_register_interruptible(ab->dev,
+                       AB8500_USB, AB8500_USB_PHY_CTRL_REG,
+                       AB8500_BIT_PHY_CTRL_HOST_EN,
+                       0);
+}
+
 static int ab8500_usb_regulator_get(struct ab8500_usb *ab)
 {
        int err;
@@ -783,6 +819,12 @@ static int ab8500_usb_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       ab->sysclk = devm_clk_get(ab->dev, "sysclk");
+       if (IS_ERR(ab->sysclk)) {
+               dev_err(ab->dev, "Could not get sysclk.\n");
+               return PTR_ERR(ab->sysclk);
+       }
+
        err = ab8500_usb_irq_setup(pdev, ab);
        if (err < 0)
                return err;
@@ -793,8 +835,8 @@ static int ab8500_usb_probe(struct platform_device *pdev)
                return err;
        }
 
-       /* Phy tuning values for AB8500 */
-       if (!is_ab8500_2p0_or_earlier(ab->ab8500)) {
+       /* Phy tuning values for AB8500 > v2.0 */
+       if (is_ab8500(ab->ab8500) && !is_ab8500_2p0_or_earlier(ab->ab8500)) {
                /* Enable the PBT/Bank 0x12 access */
                err = abx500_set_register_interruptible(ab->dev,
                                AB8500_DEVELOPMENT, AB8500_BANK12_ACCESS, 0x01);
@@ -872,6 +914,12 @@ static int ab8500_usb_probe(struct platform_device *pdev)
        /* Needed to enable ID detection. */
        ab8500_usb_wd_workaround(ab);
 
+       /*
+        * This is required for usb-link-status to work properly when a
+        * cable is connected at boot time.
+        */
+       ab8500_usb_restart_phy(ab);
+
        abx500_usb_link_status_update(ab);
 
        dev_info(&pdev->dev, "revision 0x%2x driver initialized\n", rev);
@@ -892,16 +940,21 @@ static int ab8500_usb_remove(struct platform_device *pdev)
        else if (ab->mode == USB_PERIPHERAL)
                ab8500_usb_peri_phy_dis(ab);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
+static struct platform_device_id ab8500_usb_devtype[] = {
+       { .name = "ab8500-usb", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype);
+
 static struct platform_driver ab8500_usb_driver = {
        .probe          = ab8500_usb_probe,
        .remove         = ab8500_usb_remove,
+       .id_table       = ab8500_usb_devtype,
        .driver         = {
-               .name   = "ab8500-usb",
+               .name   = "abx5x0-usb",
                .owner  = THIS_MODULE,
        },
 };
@@ -918,7 +971,6 @@ static void __exit ab8500_usb_exit(void)
 }
 module_exit(ab8500_usb_exit);
 
-MODULE_ALIAS("platform:ab8500_usb");
 MODULE_AUTHOR("ST-Ericsson AB");
 MODULE_DESCRIPTION("AB8500 usb transceiver driver");
 MODULE_LICENSE("GPL");