Skip to content

Commit

Permalink
Merge tag 'usb-ci-v4.4-rc2' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/peter.chen/usb into usb-linus

Peter writes:

USB Chipidea Fixes for v4.4-rc2

The first four fixes was for v4.3-rc7, but it is too late
at that time, and other two small fixes are for possible NULL
pointer issue.
  • Loading branch information
Greg Kroah-Hartman committed Nov 18, 2015
2 parents aa05cfa + 6f51bc3 commit 53de980
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 29 deletions.
16 changes: 12 additions & 4 deletions arch/arm/boot/dts/imx27.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024000 0x200>;
interrupts = <56>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 0>;
status = "disabled";
};
Expand All @@ -495,7 +498,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024200 0x200>;
interrupts = <54>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 1>;
dr_mode = "host";
status = "disabled";
Expand All @@ -505,7 +511,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024400 0x200>;
interrupts = <55>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 2>;
dr_mode = "host";
status = "disabled";
Expand All @@ -515,7 +524,6 @@
#index-cells = <1>;
compatible = "fsl,imx27-usbmisc";
reg = <0x10024600 0x200>;
clocks = <&clks IMX27_CLK_USB_AHB_GATE>;
};

sahara2: sahara@10025000 {
Expand Down
142 changes: 121 additions & 21 deletions drivers/usb/chipidea/ci_hdrc_imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ struct ci_hdrc_imx_data {
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
bool in_lpm;
/* SoC before i.mx6 (except imx23/imx28) needs three clks */
bool need_three_clks;
struct clk *clk_ipg;
struct clk *clk_ahb;
struct clk *clk_per;
/* --------------------------------- */
};

/* Common functions shared by usbmisc drivers */
Expand Down Expand Up @@ -135,6 +141,102 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
}

/* End of common functions shared by usbmisc drivers*/
static int imx_get_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;

data->clk_ipg = devm_clk_get(dev, "ipg");
if (IS_ERR(data->clk_ipg)) {
/* If the platform only needs one clocks */
data->clk = devm_clk_get(dev, NULL);
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
dev_err(dev,
"Failed to get clks, err=%ld,%ld\n",
PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
return ret;
}
return ret;
}

data->clk_ahb = devm_clk_get(dev, "ahb");
if (IS_ERR(data->clk_ahb)) {
ret = PTR_ERR(data->clk_ahb);
dev_err(dev,
"Failed to get ahb clock, err=%d\n", ret);
return ret;
}

data->clk_per = devm_clk_get(dev, "per");
if (IS_ERR(data->clk_per)) {
ret = PTR_ERR(data->clk_per);
dev_err(dev,
"Failed to get per clock, err=%d\n", ret);
return ret;
}

data->need_three_clks = true;
return ret;
}

static int imx_prepare_enable_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;

if (data->need_three_clks) {
ret = clk_prepare_enable(data->clk_ipg);
if (ret) {
dev_err(dev,
"Failed to prepare/enable ipg clk, err=%d\n",
ret);
return ret;
}

ret = clk_prepare_enable(data->clk_ahb);
if (ret) {
dev_err(dev,
"Failed to prepare/enable ahb clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ipg);
return ret;
}

ret = clk_prepare_enable(data->clk_per);
if (ret) {
dev_err(dev,
"Failed to prepare/enable per clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ahb);
clk_disable_unprepare(data->clk_ipg);
return ret;
}
} else {
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(dev,
"Failed to prepare/enable clk, err=%d\n",
ret);
return ret;
}
}

return ret;
}

static void imx_disable_unprepare_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);

if (data->need_three_clks) {
clk_disable_unprepare(data->clk_per);
clk_disable_unprepare(data->clk_ahb);
clk_disable_unprepare(data->clk_ipg);
} else {
clk_disable_unprepare(data->clk);
}
}

static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
Expand All @@ -145,31 +247,31 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
.flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id =
of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
const struct of_device_id *of_id;
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;

of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
if (!of_id)
return -ENODEV;

imx_platform_flag = of_id->data;

data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;

platform_set_drvdata(pdev, data);
data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
if (IS_ERR(data->usbmisc_data))
return PTR_ERR(data->usbmisc_data);

data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
"Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
return PTR_ERR(data->clk);
}
ret = imx_get_clks(&pdev->dev);
if (ret)
return ret;

ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(&pdev->dev,
"Failed to prepare or enable clock, err=%d\n", ret);
ret = imx_prepare_enable_clks(&pdev->dev);
if (ret)
return ret;
}

data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
Expand Down Expand Up @@ -212,8 +314,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto disable_device;
}

platform_set_drvdata(pdev, data);

if (data->supports_runtime_pm) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
Expand All @@ -226,7 +326,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
err_clk:
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(&pdev->dev);
return ret;
}

Expand All @@ -240,7 +340,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
}
ci_hdrc_remove_device(data->ci_pdev);
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(&pdev->dev);

return 0;
}
Expand All @@ -252,7 +352,7 @@ static int imx_controller_suspend(struct device *dev)

dev_dbg(dev, "at %s\n", __func__);

clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(dev);
data->in_lpm = true;

return 0;
Expand All @@ -270,7 +370,7 @@ static int imx_controller_resume(struct device *dev)
return 0;
}

ret = clk_prepare_enable(data->clk);
ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;

Expand All @@ -285,7 +385,7 @@ static int imx_controller_resume(struct device *dev)
return 0;

clk_disable:
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(dev);
return ret;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/chipidea/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
return -EINVAL;

pm_runtime_get_sync(ci->dev);
disable_irq(ci->irq);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
enable_irq(ci->irq);
pm_runtime_put_sync(ci->dev);

return ret ? ret : count;
Expand Down
17 changes: 17 additions & 0 deletions drivers/usb/chipidea/udc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget,
return retval;
}

static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
{
if (!ci_otg_is_fsm_mode(ci))
return;

mutex_lock(&ci->fsm.lock);
if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
ci->fsm.a_bidl_adis_tmout = 1;
ci_hdrc_otg_fsm_start(ci);
} else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
ci->fsm.protocol = PROTO_UNDEF;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
}
mutex_unlock(&ci->fsm.lock);
}

/**
* ci_udc_stop: unregister a gadget driver
*/
Expand All @@ -1775,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
ci->driver = NULL;
spin_unlock_irqrestore(&ci->lock, flags);

ci_udc_stop_for_otg_fsm(ci);
return 0;
}

Expand Down
10 changes: 6 additions & 4 deletions drivers/usb/chipidea/usbmisc_imx.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,11 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_usbmisc *data;
struct of_device_id *tmp_dev;
const struct of_device_id *of_id;

of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
if (!of_id)
return -ENODEV;

data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
Expand All @@ -513,9 +517,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);

tmp_dev = (struct of_device_id *)
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
data->ops = (const struct usbmisc_ops *)of_id->data;
platform_set_drvdata(pdev, data);

return 0;
Expand Down

0 comments on commit 53de980

Please sign in to comment.