|
@@ -35,6 +35,9 @@
|
|
|
#include <linux/clk.h>
|
|
|
#include <linux/regulator/consumer.h>
|
|
|
#include <linux/of.h>
|
|
|
+#include <linux/of_gpio.h>
|
|
|
+#include <linux/gpio.h>
|
|
|
+#include <linux/delay.h>
|
|
|
|
|
|
#include "phy-generic.h"
|
|
|
|
|
@@ -64,6 +67,23 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void nop_reset_set(struct usb_phy_gen_xceiv *nop, int asserted)
|
|
|
+{
|
|
|
+ int value;
|
|
|
+
|
|
|
+ if (!gpio_is_valid(nop->gpio_reset))
|
|
|
+ return;
|
|
|
+
|
|
|
+ value = asserted;
|
|
|
+ if (nop->reset_active_low)
|
|
|
+ value = !value;
|
|
|
+
|
|
|
+ gpio_set_value_cansleep(nop->gpio_reset, value);
|
|
|
+
|
|
|
+ if (!asserted)
|
|
|
+ usleep_range(10000, 20000);
|
|
|
+}
|
|
|
+
|
|
|
int usb_gen_phy_init(struct usb_phy *phy)
|
|
|
{
|
|
|
struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
|
|
@@ -76,11 +96,8 @@ int usb_gen_phy_init(struct usb_phy *phy)
|
|
|
if (!IS_ERR(nop->clk))
|
|
|
clk_prepare_enable(nop->clk);
|
|
|
|
|
|
- if (!IS_ERR(nop->reset)) {
|
|
|
- /* De-assert RESET */
|
|
|
- if (regulator_enable(nop->reset))
|
|
|
- dev_err(phy->dev, "Failed to de-assert reset\n");
|
|
|
- }
|
|
|
+ /* De-assert RESET */
|
|
|
+ nop_reset_set(nop, 0);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -90,11 +107,8 @@ void usb_gen_phy_shutdown(struct usb_phy *phy)
|
|
|
{
|
|
|
struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev);
|
|
|
|
|
|
- if (!IS_ERR(nop->reset)) {
|
|
|
- /* Assert RESET */
|
|
|
- if (regulator_disable(nop->reset))
|
|
|
- dev_err(phy->dev, "Failed to assert reset\n");
|
|
|
- }
|
|
|
+ /* Assert RESET */
|
|
|
+ nop_reset_set(nop, 1);
|
|
|
|
|
|
if (!IS_ERR(nop->clk))
|
|
|
clk_disable_unprepare(nop->clk);
|
|
@@ -136,8 +150,7 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
|
|
|
}
|
|
|
|
|
|
int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
|
|
|
- enum usb_phy_type type, u32 clk_rate, bool needs_vcc,
|
|
|
- bool needs_reset)
|
|
|
+ enum usb_phy_type type, u32 clk_rate, bool needs_vcc)
|
|
|
{
|
|
|
int err;
|
|
|
|
|
@@ -168,12 +181,22 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,
|
|
|
return -EPROBE_DEFER;
|
|
|
}
|
|
|
|
|
|
- nop->reset = devm_regulator_get(dev, "reset");
|
|
|
- if (IS_ERR(nop->reset)) {
|
|
|
- dev_dbg(dev, "Error getting reset regulator: %ld\n",
|
|
|
- PTR_ERR(nop->reset));
|
|
|
- if (needs_reset)
|
|
|
- return -EPROBE_DEFER;
|
|
|
+ if (gpio_is_valid(nop->gpio_reset)) {
|
|
|
+ unsigned long gpio_flags;
|
|
|
+
|
|
|
+ /* Assert RESET */
|
|
|
+ if (nop->reset_active_low)
|
|
|
+ gpio_flags = GPIOF_OUT_INIT_LOW;
|
|
|
+ else
|
|
|
+ gpio_flags = GPIOF_OUT_INIT_HIGH;
|
|
|
+
|
|
|
+ err = devm_gpio_request_one(dev, nop->gpio_reset,
|
|
|
+ gpio_flags, dev_name(dev));
|
|
|
+ if (err) {
|
|
|
+ dev_err(dev, "Error requesting RESET GPIO %d\n",
|
|
|
+ nop->gpio_reset);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
nop->dev = dev;
|
|
@@ -202,31 +225,36 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)
|
|
|
int err;
|
|
|
u32 clk_rate = 0;
|
|
|
bool needs_vcc = false;
|
|
|
- bool needs_reset = false;
|
|
|
+
|
|
|
+ nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
|
|
|
+ if (!nop)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ nop->reset_active_low = true; /* default behaviour */
|
|
|
|
|
|
if (dev->of_node) {
|
|
|
struct device_node *node = dev->of_node;
|
|
|
+ enum of_gpio_flags flags;
|
|
|
|
|
|
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
|
|
|
clk_rate = 0;
|
|
|
|
|
|
needs_vcc = of_property_read_bool(node, "vcc-supply");
|
|
|
- needs_reset = of_property_read_bool(node, "reset-supply");
|
|
|
+ nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
|
|
|
+ 0, &flags);
|
|
|
+ if (nop->gpio_reset == -EPROBE_DEFER)
|
|
|
+ return -EPROBE_DEFER;
|
|
|
+
|
|
|
+ nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
|
|
|
|
|
|
} else if (pdata) {
|
|
|
type = pdata->type;
|
|
|
clk_rate = pdata->clk_rate;
|
|
|
needs_vcc = pdata->needs_vcc;
|
|
|
- needs_reset = pdata->needs_reset;
|
|
|
+ nop->gpio_reset = pdata->gpio_reset;
|
|
|
}
|
|
|
|
|
|
- nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);
|
|
|
- if (!nop)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
-
|
|
|
- err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc,
|
|
|
- needs_reset);
|
|
|
+ err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|