mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-07-05 13:25:20 +02:00
USB fixes for 6.10-rc6
Here are a handful of small USB driver fixes for 6.10-rc6 to resolve some reported issues. Included in here are: - typec driver bugfixes - usb gadget driver reverts for commits that were reported to have problems - resource leak bugfix - gadget driver bugfixes - dwc3 driver bugfixes - usb atm driver bugfix for when syzbot got loose on it All of these have been in linux-next this week with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZoFnUA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ym3ggCgyM2B+cIOH4FtyWi7FfXj8XjDsjIAoKzX45+o TO/pSGQhRwx9PeFfDISM =pFEO -----END PGP SIGNATURE----- Merge tag 'usb-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB fixes from Greg KH: "Here are a handful of small USB driver fixes for 6.10-rc6 to resolve some reported issues. Included in here are: - typec driver bugfixes - usb gadget driver reverts for commits that were reported to have problems - resource leak bugfix - gadget driver bugfixes - dwc3 driver bugfixes - usb atm driver bugfix for when syzbot got loose on it All of these have been in linux-next this week with no reported issues" * tag 'usb-6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: usb: dwc3: core: Workaround for CSR read timeout Revert "usb: gadget: u_ether: Replace netif_stop_queue with netif_device_detach" Revert "usb: gadget: u_ether: Re-attach netif device to mirror detachment" usb: gadget: aspeed_udc: fix device address configuration usb: dwc3: core: remove lock of otg mode during gadget suspend/resume to avoid deadlock usb: typec: ucsi: glink: fix child node release in probe function usb: musb: da8xx: fix a resource leak in probe() usb: typec: ucsi_acpi: Add LG Gram quirk usb: ucsi: stm32: fix command completion handling usb: atm: cxacru: fix endpoint checking in cxacru_bind() usb: gadget: printer: fix races against disable usb: gadget: printer: SS+ support
This commit is contained in:
commit
2c01c3d552
|
@ -1131,6 +1131,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
||||||
struct cxacru_data *instance;
|
struct cxacru_data *instance;
|
||||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||||
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
|
struct usb_host_endpoint *cmd_ep = usb_dev->ep_in[CXACRU_EP_CMD];
|
||||||
|
struct usb_endpoint_descriptor *in, *out;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* instance init */
|
/* instance init */
|
||||||
|
@ -1177,6 +1178,19 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (usb_endpoint_xfer_int(&cmd_ep->desc))
|
||||||
|
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||||
|
NULL, NULL, &in, &out);
|
||||||
|
else
|
||||||
|
ret = usb_find_common_endpoints(intf->cur_altsetting,
|
||||||
|
&in, &out, NULL, NULL);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
usb_err(usbatm_instance, "cxacru_bind: interface has incorrect endpoints\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
if ((cmd_ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
||||||
== USB_ENDPOINT_XFER_INT) {
|
== USB_ENDPOINT_XFER_INT) {
|
||||||
usb_fill_int_urb(instance->rcv_urb,
|
usb_fill_int_urb(instance->rcv_urb,
|
||||||
|
|
|
@ -957,12 +957,16 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
|
||||||
|
|
||||||
static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
|
unsigned int power_opt;
|
||||||
|
unsigned int hw_mode;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||||||
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
|
||||||
|
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
|
||||||
|
power_opt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
|
||||||
|
|
||||||
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
|
switch (power_opt) {
|
||||||
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
|
||||||
/**
|
/**
|
||||||
* WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
|
* WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an
|
||||||
|
@ -995,6 +999,20 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a workaround for STAR#4846132, which only affects
|
||||||
|
* DWC_usb31 version2.00a operating in host mode.
|
||||||
|
*
|
||||||
|
* There is a problem in DWC_usb31 version 2.00a operating
|
||||||
|
* in host mode that would cause a CSR read timeout When CSR
|
||||||
|
* read coincides with RAM Clock Gating Entry. By disable
|
||||||
|
* Clock Gating, sacrificing power consumption for normal
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
if (power_opt != DWC3_GHWPARAMS1_EN_PWROPT_NO &&
|
||||||
|
hw_mode != DWC3_GHWPARAMS0_MODE_GADGET && DWC3_VER_IS(DWC31, 200A))
|
||||||
|
reg |= DWC3_GCTL_DSBLCLKGTNG;
|
||||||
|
|
||||||
/* check if current dwc3 is on simulation board */
|
/* check if current dwc3 is on simulation board */
|
||||||
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
|
if (dwc->hwparams.hwparams6 & DWC3_GHWPARAMS6_EN_FPGA) {
|
||||||
dev_info(dwc->dev, "Running with FPGA optimizations\n");
|
dev_info(dwc->dev, "Running with FPGA optimizations\n");
|
||||||
|
@ -2250,7 +2268,6 @@ assert_reset:
|
||||||
|
|
||||||
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
u32 reg;
|
u32 reg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2293,9 +2310,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
|
||||||
dwc3_gadget_suspend(dwc);
|
dwc3_gadget_suspend(dwc);
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
||||||
synchronize_irq(dwc->irq_gadget);
|
synchronize_irq(dwc->irq_gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2312,7 +2327,6 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
|
|
||||||
static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
int ret;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2366,9 +2380,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
|
||||||
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
|
||||||
dwc3_otg_host_init(dwc);
|
dwc3_otg_host_init(dwc);
|
||||||
} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
} else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
|
||||||
dwc3_gadget_resume(dwc);
|
dwc3_gadget_resume(dwc);
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -213,6 +213,7 @@ static inline struct usb_endpoint_descriptor *ep_desc(struct usb_gadget *gadget,
|
||||||
struct usb_endpoint_descriptor *ss)
|
struct usb_endpoint_descriptor *ss)
|
||||||
{
|
{
|
||||||
switch (gadget->speed) {
|
switch (gadget->speed) {
|
||||||
|
case USB_SPEED_SUPER_PLUS:
|
||||||
case USB_SPEED_SUPER:
|
case USB_SPEED_SUPER:
|
||||||
return ss;
|
return ss;
|
||||||
case USB_SPEED_HIGH:
|
case USB_SPEED_HIGH:
|
||||||
|
@ -449,11 +450,8 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
mutex_lock(&dev->lock_printer_io);
|
mutex_lock(&dev->lock_printer_io);
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
|
||||||
if (dev->interface < 0) {
|
if (dev->interface < 0)
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
goto out_disabled;
|
||||||
mutex_unlock(&dev->lock_printer_io);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We will use this flag later to check if a printer reset happened
|
/* We will use this flag later to check if a printer reset happened
|
||||||
* after we turn interrupts back on.
|
* after we turn interrupts back on.
|
||||||
|
@ -461,6 +459,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
dev->reset_printer = 0;
|
dev->reset_printer = 0;
|
||||||
|
|
||||||
setup_rx_reqs(dev);
|
setup_rx_reqs(dev);
|
||||||
|
/* this dropped the lock - need to retest */
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
|
|
||||||
bytes_copied = 0;
|
bytes_copied = 0;
|
||||||
current_rx_req = dev->current_rx_req;
|
current_rx_req = dev->current_rx_req;
|
||||||
|
@ -494,6 +495,8 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
wait_event_interruptible(dev->rx_wait,
|
wait_event_interruptible(dev->rx_wait,
|
||||||
(likely(!list_empty(&dev->rx_buffers))));
|
(likely(!list_empty(&dev->rx_buffers))));
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have data to return then copy it to the caller's buffer.*/
|
/* We have data to return then copy it to the caller's buffer.*/
|
||||||
|
@ -537,6 +540,9 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
|
|
||||||
/* If we not returning all the data left in this RX request
|
/* If we not returning all the data left in this RX request
|
||||||
* buffer then adjust the amount of data left in the buffer.
|
* buffer then adjust the amount of data left in the buffer.
|
||||||
* Othewise if we are done with this RX request buffer then
|
* Othewise if we are done with this RX request buffer then
|
||||||
|
@ -566,6 +572,11 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
|
||||||
return bytes_copied;
|
return bytes_copied;
|
||||||
else
|
else
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
out_disabled:
|
||||||
|
spin_unlock_irqrestore(&dev->lock, flags);
|
||||||
|
mutex_unlock(&dev->lock_printer_io);
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -586,11 +597,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||||
mutex_lock(&dev->lock_printer_io);
|
mutex_lock(&dev->lock_printer_io);
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
|
||||||
if (dev->interface < 0) {
|
if (dev->interface < 0)
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
goto out_disabled;
|
||||||
mutex_unlock(&dev->lock_printer_io);
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if a printer reset happens while we have interrupts on */
|
/* Check if a printer reset happens while we have interrupts on */
|
||||||
dev->reset_printer = 0;
|
dev->reset_printer = 0;
|
||||||
|
@ -613,6 +621,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||||
wait_event_interruptible(dev->tx_wait,
|
wait_event_interruptible(dev->tx_wait,
|
||||||
(likely(!list_empty(&dev->tx_reqs))));
|
(likely(!list_empty(&dev->tx_reqs))));
|
||||||
spin_lock_irqsave(&dev->lock, flags);
|
spin_lock_irqsave(&dev->lock, flags);
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (likely(!list_empty(&dev->tx_reqs)) && len) {
|
while (likely(!list_empty(&dev->tx_reqs)) && len) {
|
||||||
|
@ -662,6 +672,9 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
|
|
||||||
list_add(&req->list, &dev->tx_reqs_active);
|
list_add(&req->list, &dev->tx_reqs_active);
|
||||||
|
|
||||||
/* here, we unlock, and only unlock, to avoid deadlock. */
|
/* here, we unlock, and only unlock, to avoid deadlock. */
|
||||||
|
@ -674,6 +687,8 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||||
mutex_unlock(&dev->lock_printer_io);
|
mutex_unlock(&dev->lock_printer_io);
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
if (dev->interface < 0)
|
||||||
|
goto out_disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->lock, flags);
|
spin_unlock_irqrestore(&dev->lock, flags);
|
||||||
|
@ -685,6 +700,11 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
||||||
return bytes_copied;
|
return bytes_copied;
|
||||||
else
|
else
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
|
out_disabled:
|
||||||
|
spin_unlock_irqrestore(&dev->lock, flags);
|
||||||
|
mutex_unlock(&dev->lock_printer_io);
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -1163,8 +1163,6 @@ struct net_device *gether_connect(struct gether *link)
|
||||||
if (netif_running(dev->net))
|
if (netif_running(dev->net))
|
||||||
eth_start(dev, GFP_ATOMIC);
|
eth_start(dev, GFP_ATOMIC);
|
||||||
|
|
||||||
netif_device_attach(dev->net);
|
|
||||||
|
|
||||||
/* on error, disable any endpoints */
|
/* on error, disable any endpoints */
|
||||||
} else {
|
} else {
|
||||||
(void) usb_ep_disable(link->out_ep);
|
(void) usb_ep_disable(link->out_ep);
|
||||||
|
@ -1202,7 +1200,7 @@ void gether_disconnect(struct gether *link)
|
||||||
|
|
||||||
DBG(dev, "%s\n", __func__);
|
DBG(dev, "%s\n", __func__);
|
||||||
|
|
||||||
netif_device_detach(dev->net);
|
netif_stop_queue(dev->net);
|
||||||
netif_carrier_off(dev->net);
|
netif_carrier_off(dev->net);
|
||||||
|
|
||||||
/* disable endpoints, forcing (synchronous) completion
|
/* disable endpoints, forcing (synchronous) completion
|
||||||
|
|
|
@ -66,8 +66,8 @@
|
||||||
#define USB_UPSTREAM_EN BIT(0)
|
#define USB_UPSTREAM_EN BIT(0)
|
||||||
|
|
||||||
/* Main config reg */
|
/* Main config reg */
|
||||||
#define UDC_CFG_SET_ADDR(x) ((x) & 0x3f)
|
#define UDC_CFG_SET_ADDR(x) ((x) & UDC_CFG_ADDR_MASK)
|
||||||
#define UDC_CFG_ADDR_MASK (0x3f)
|
#define UDC_CFG_ADDR_MASK GENMASK(6, 0)
|
||||||
|
|
||||||
/* Interrupt ctrl & status reg */
|
/* Interrupt ctrl & status reg */
|
||||||
#define UDC_IRQ_EP_POOL_NAK BIT(17)
|
#define UDC_IRQ_EP_POOL_NAK BIT(17)
|
||||||
|
|
|
@ -556,7 +556,7 @@ static int da8xx_probe(struct platform_device *pdev)
|
||||||
ret = of_platform_populate(pdev->dev.of_node, NULL,
|
ret = of_platform_populate(pdev->dev.of_node, NULL,
|
||||||
da8xx_auxdata_lookup, &pdev->dev);
|
da8xx_auxdata_lookup, &pdev->dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto err_unregister_phy;
|
||||||
|
|
||||||
pinfo = da8xx_dev_info;
|
pinfo = da8xx_dev_info;
|
||||||
pinfo.parent = &pdev->dev;
|
pinfo.parent = &pdev->dev;
|
||||||
|
@ -571,9 +571,13 @@ static int da8xx_probe(struct platform_device *pdev)
|
||||||
ret = PTR_ERR_OR_ZERO(glue->musb);
|
ret = PTR_ERR_OR_ZERO(glue->musb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
|
dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);
|
||||||
usb_phy_generic_unregister(glue->usb_phy);
|
goto err_unregister_phy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_phy:
|
||||||
|
usb_phy_generic_unregister(glue->usb_phy);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ struct ucsi_acpi {
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
#define UCSI_ACPI_COMMAND_PENDING 1
|
#define UCSI_ACPI_COMMAND_PENDING 1
|
||||||
#define UCSI_ACPI_ACK_PENDING 2
|
#define UCSI_ACPI_ACK_PENDING 2
|
||||||
|
#define UCSI_ACPI_CHECK_BOGUS_EVENT 3
|
||||||
guid_t guid;
|
guid_t guid;
|
||||||
u64 cmd;
|
u64 cmd;
|
||||||
};
|
};
|
||||||
|
@ -128,6 +129,58 @@ static const struct ucsi_operations ucsi_zenbook_ops = {
|
||||||
.async_write = ucsi_acpi_async_write
|
.async_write = ucsi_acpi_async_write
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int ucsi_gram_read(struct ucsi *ucsi, unsigned int offset,
|
||||||
|
void *val, size_t val_len)
|
||||||
|
{
|
||||||
|
u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE |
|
||||||
|
UCSI_CONSTAT_PDOS_CHANGE;
|
||||||
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
struct ucsi_connector_status *status;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ucsi_acpi_read(ucsi, offset, val, val_len);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS &&
|
||||||
|
test_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags) &&
|
||||||
|
offset == UCSI_MESSAGE_IN) {
|
||||||
|
status = (struct ucsi_connector_status *)val;
|
||||||
|
|
||||||
|
/* Clear the bogus change */
|
||||||
|
if (status->change == bogus_change)
|
||||||
|
status->change = 0;
|
||||||
|
|
||||||
|
clear_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ucsi_gram_sync_write(struct ucsi *ucsi, unsigned int offset,
|
||||||
|
const void *val, size_t val_len)
|
||||||
|
{
|
||||||
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ucsi_acpi_sync_write(ucsi, offset, val, val_len);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (UCSI_COMMAND(ua->cmd) == UCSI_GET_PDOS &&
|
||||||
|
ua->cmd & UCSI_GET_PDOS_PARTNER_PDO(1) &&
|
||||||
|
ua->cmd & UCSI_GET_PDOS_SRC_PDOS)
|
||||||
|
set_bit(UCSI_ACPI_CHECK_BOGUS_EVENT, &ua->flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ucsi_operations ucsi_gram_ops = {
|
||||||
|
.read = ucsi_gram_read,
|
||||||
|
.sync_write = ucsi_gram_sync_write,
|
||||||
|
.async_write = ucsi_acpi_async_write
|
||||||
|
};
|
||||||
|
|
||||||
static const struct dmi_system_id ucsi_acpi_quirks[] = {
|
static const struct dmi_system_id ucsi_acpi_quirks[] = {
|
||||||
{
|
{
|
||||||
.matches = {
|
.matches = {
|
||||||
|
@ -136,6 +189,14 @@ static const struct dmi_system_id ucsi_acpi_quirks[] = {
|
||||||
},
|
},
|
||||||
.driver_data = (void *)&ucsi_zenbook_ops,
|
.driver_data = (void *)&ucsi_zenbook_ops,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_FAMILY, "LG gram PC"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "90Q"),
|
||||||
|
},
|
||||||
|
.driver_data = (void *)&ucsi_gram_ops,
|
||||||
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -372,6 +372,7 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
|
||||||
ret = fwnode_property_read_u32(fwnode, "reg", &port);
|
ret = fwnode_property_read_u32(fwnode, "reg", &port);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "missing reg property of %pOFn\n", fwnode);
|
dev_err(dev, "missing reg property of %pOFn\n", fwnode);
|
||||||
|
fwnode_handle_put(fwnode);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,9 +387,11 @@ static int pmic_glink_ucsi_probe(struct auxiliary_device *adev,
|
||||||
if (!desc)
|
if (!desc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IS_ERR(desc))
|
if (IS_ERR(desc)) {
|
||||||
|
fwnode_handle_put(fwnode);
|
||||||
return dev_err_probe(dev, PTR_ERR(desc),
|
return dev_err_probe(dev, PTR_ERR(desc),
|
||||||
"unable to acquire orientation gpio\n");
|
"unable to acquire orientation gpio\n");
|
||||||
|
}
|
||||||
ucsi->port_orientation[port] = desc;
|
ucsi->port_orientation[port] = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ struct ucsi_stm32g0 {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
#define COMMAND_PENDING 1
|
#define COMMAND_PENDING 1
|
||||||
|
#define ACK_PENDING 2
|
||||||
const char *fw_name;
|
const char *fw_name;
|
||||||
struct ucsi *ucsi;
|
struct ucsi *ucsi;
|
||||||
bool suspended;
|
bool suspended;
|
||||||
|
@ -396,9 +397,13 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
|
struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi);
|
||||||
|
bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
set_bit(COMMAND_PENDING, &g0->flags);
|
if (ack)
|
||||||
|
set_bit(ACK_PENDING, &g0->flags);
|
||||||
|
else
|
||||||
|
set_bit(COMMAND_PENDING, &g0->flags);
|
||||||
|
|
||||||
ret = ucsi_stm32g0_async_write(ucsi, offset, val, len);
|
ret = ucsi_stm32g0_async_write(ucsi, offset, val, len);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -406,9 +411,14 @@ static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const
|
||||||
|
|
||||||
if (!wait_for_completion_timeout(&g0->complete, msecs_to_jiffies(5000)))
|
if (!wait_for_completion_timeout(&g0->complete, msecs_to_jiffies(5000)))
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
|
||||||
out_clear_bit:
|
out_clear_bit:
|
||||||
clear_bit(COMMAND_PENDING, &g0->flags);
|
if (ack)
|
||||||
|
clear_bit(ACK_PENDING, &g0->flags);
|
||||||
|
else
|
||||||
|
clear_bit(COMMAND_PENDING, &g0->flags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -429,8 +439,9 @@ static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data)
|
||||||
if (UCSI_CCI_CONNECTOR(cci))
|
if (UCSI_CCI_CONNECTOR(cci))
|
||||||
ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci));
|
ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci));
|
||||||
|
|
||||||
if (test_bit(COMMAND_PENDING, &g0->flags) &&
|
if (cci & UCSI_CCI_ACK_COMPLETE && test_and_clear_bit(ACK_PENDING, &g0->flags))
|
||||||
cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
|
complete(&g0->complete);
|
||||||
|
if (cci & UCSI_CCI_COMMAND_COMPLETE && test_and_clear_bit(COMMAND_PENDING, &g0->flags))
|
||||||
complete(&g0->complete);
|
complete(&g0->complete);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user