USB Chipidea fixes for v4.3-rc2
- Fix the stall implementation - Fix device mode transfer at zynq platform - other small fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJV+8GAAAoJEEhZKYFQ1nG79FMH/2dAYwuA4S9OgQq2rGZnaZnM MaWFKF5Q/4mLdVd9cnJDL1B/GVq0yT50n2P8h4/pjHLGetmo6iMIDgjsQXcO6JTa vyWTggq/2eCQDJk/dBMbQlyzyavrGT4SY4PYbMJ/ggZEm9UmI/ONjBWlExnLkiqp Yjk7lJ/JH3Du3cgZ3nePJoB7r0ETbJnxZf3H1AgU3//n74xcgRz48HeBQxMHXqj5 Hy9CDbsrKcyhigx3liIPr1zFdWs0P5km199PrWTkyKVmjAjIxU7mlimUbM2RuPwo IVOcce5Z6OWObfmNiZtrc2ZcxbAfvUOeT6OkEmyhAeq1fvVtdEO3Wh8suWZGaSg= =O6FV -----END PGP SIGNATURE----- Merge tag 'usb-ci-v4.3-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/peter.chen/usb into usb-linus Peter writes: USB Chipidea fixes for v4.3-rc2 - Fix the stall implementation - Fix device mode transfer at zynq platform - other small fixes
This commit is contained in:
commit
ea9346514e
|
@ -6,6 +6,7 @@ Required properties:
|
|||
"lsi,zevio-usb"
|
||||
"qcom,ci-hdrc"
|
||||
"chipidea,usb2"
|
||||
"xlnx,zynq-usb-2.20a"
|
||||
- reg: base address and length of the registers
|
||||
- interrupts: interrupt for the USB controller
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
|||
{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
|
||||
{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
|
||||
{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
|
||||
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sl_usb_data},
|
||||
{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
|
@ -30,18 +31,36 @@ static const struct ci_hdrc_platform_data ci_default_pdata = {
|
|||
.flags = CI_HDRC_DISABLE_STREAMING,
|
||||
};
|
||||
|
||||
static struct ci_hdrc_platform_data ci_zynq_pdata = {
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
};
|
||||
|
||||
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
|
||||
{ .compatible = "chipidea,usb2"},
|
||||
{ .compatible = "xlnx,zynq-usb-2.20a", .data = &ci_zynq_pdata},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
|
||||
|
||||
static int ci_hdrc_usb2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ci_hdrc_usb2_priv *priv;
|
||||
struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (!ci_pdata) {
|
||||
ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL);
|
||||
*ci_pdata = ci_default_pdata; /* struct copy */
|
||||
}
|
||||
|
||||
match = of_match_device(ci_hdrc_usb2_of_match, &pdev->dev);
|
||||
if (match && match->data) {
|
||||
/* struct copy */
|
||||
*ci_pdata = *(struct ci_hdrc_platform_data *)match->data;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
@ -96,12 +115,6 @@ static int ci_hdrc_usb2_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
|
||||
{ .compatible = "chipidea,usb2" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
|
||||
|
||||
static struct platform_driver ci_hdrc_usb2_driver = {
|
||||
.probe = ci_hdrc_usb2_probe,
|
||||
.remove = ci_hdrc_usb2_remove,
|
||||
|
|
|
@ -656,6 +656,44 @@ __acquires(hwep->lock)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer)
|
||||
{
|
||||
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
|
||||
int direction, retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (ep == NULL || hwep->ep.desc == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(hwep->ep.desc))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(hwep->lock, flags);
|
||||
|
||||
if (value && hwep->dir == TX && check_transfer &&
|
||||
!list_empty(&hwep->qh.queue) &&
|
||||
!usb_endpoint_xfer_control(hwep->ep.desc)) {
|
||||
spin_unlock_irqrestore(hwep->lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
direction = hwep->dir;
|
||||
do {
|
||||
retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
|
||||
|
||||
if (!value)
|
||||
hwep->wedge = 0;
|
||||
|
||||
if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
|
||||
hwep->dir = (hwep->dir == TX) ? RX : TX;
|
||||
|
||||
} while (hwep->dir != direction);
|
||||
|
||||
spin_unlock_irqrestore(hwep->lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
|
||||
* @gadget: gadget
|
||||
|
@ -1051,7 +1089,7 @@ __acquires(ci->lock)
|
|||
num += ci->hw_ep_max / 2;
|
||||
|
||||
spin_unlock(&ci->lock);
|
||||
err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep);
|
||||
err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false);
|
||||
spin_lock(&ci->lock);
|
||||
if (!err)
|
||||
isr_setup_status_phase(ci);
|
||||
|
@ -1117,8 +1155,8 @@ delegate:
|
|||
|
||||
if (err < 0) {
|
||||
spin_unlock(&ci->lock);
|
||||
if (usb_ep_set_halt(&hwep->ep))
|
||||
dev_err(ci->dev, "error: ep_set_halt\n");
|
||||
if (_ep_set_halt(&hwep->ep, 1, false))
|
||||
dev_err(ci->dev, "error: _ep_set_halt\n");
|
||||
spin_lock(&ci->lock);
|
||||
}
|
||||
}
|
||||
|
@ -1149,9 +1187,9 @@ __acquires(ci->lock)
|
|||
err = isr_setup_status_phase(ci);
|
||||
if (err < 0) {
|
||||
spin_unlock(&ci->lock);
|
||||
if (usb_ep_set_halt(&hwep->ep))
|
||||
if (_ep_set_halt(&hwep->ep, 1, false))
|
||||
dev_err(ci->dev,
|
||||
"error: ep_set_halt\n");
|
||||
"error: _ep_set_halt\n");
|
||||
spin_lock(&ci->lock);
|
||||
}
|
||||
}
|
||||
|
@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
|||
*/
|
||||
static int ep_set_halt(struct usb_ep *ep, int value)
|
||||
{
|
||||
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
|
||||
int direction, retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (ep == NULL || hwep->ep.desc == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (usb_endpoint_xfer_isoc(hwep->ep.desc))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(hwep->lock, flags);
|
||||
|
||||
#ifndef STALL_IN
|
||||
/* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
|
||||
if (value && hwep->type == USB_ENDPOINT_XFER_BULK && hwep->dir == TX &&
|
||||
!list_empty(&hwep->qh.queue)) {
|
||||
spin_unlock_irqrestore(hwep->lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
#endif
|
||||
|
||||
direction = hwep->dir;
|
||||
do {
|
||||
retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value);
|
||||
|
||||
if (!value)
|
||||
hwep->wedge = 0;
|
||||
|
||||
if (hwep->type == USB_ENDPOINT_XFER_CONTROL)
|
||||
hwep->dir = (hwep->dir == TX) ? RX : TX;
|
||||
|
||||
} while (hwep->dir != direction);
|
||||
|
||||
spin_unlock_irqrestore(hwep->lock, flags);
|
||||
return retval;
|
||||
return _ep_set_halt(ep, value, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue