Commit fc49583c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-5.18-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some small fixes for reported issues with some USB drivers.
  They include:

   - xhci fixes for xhci-mtk platform driver

   - typec driver fixes for reported problems.

   - cdc-wdm read-stuck fix

   - gadget driver fix for reported race condition

   - new usb-serial driver ids

  All of these have been in linux-next with no reported problems"

* tag 'usb-5.18-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
  usb: xhci-mtk: remove bandwidth budget table
  usb: xhci-mtk: fix fs isoc's transfer error
  usb: gadget: fix race when gadget driver register via ioctl
  usb: typec: tcpci_mt6360: Update for BMC PHY setting
  usb: gadget: uvc: allow for application to cleanly shutdown
  usb: typec: tcpci: Don't skip cleanup in .remove() on error
  usb: cdc-wdm: fix reading stuck on device close
  USB: serial: qcserial: add support for Sierra Wireless EM7590
  USB: serial: option: add Fibocom MA510 modem
  USB: serial: option: add Fibocom L610 modem
  USB: serial: pl2303: add device id for HP LM930 Display
parents bc403203 757b9f6e
...@@ -774,6 +774,7 @@ static int wdm_release(struct inode *inode, struct file *file) ...@@ -774,6 +774,7 @@ static int wdm_release(struct inode *inode, struct file *file)
poison_urbs(desc); poison_urbs(desc);
spin_lock_irq(&desc->iuspin); spin_lock_irq(&desc->iuspin);
desc->resp_count = 0; desc->resp_count = 0;
clear_bit(WDM_RESPONDING, &desc->flags);
spin_unlock_irq(&desc->iuspin); spin_unlock_irq(&desc->iuspin);
desc->manage_power(desc->intf, 0); desc->manage_power(desc->intf, 0);
unpoison_urbs(desc); unpoison_urbs(desc);
......
...@@ -890,13 +890,37 @@ static void uvc_function_unbind(struct usb_configuration *c, ...@@ -890,13 +890,37 @@ static void uvc_function_unbind(struct usb_configuration *c,
{ {
struct usb_composite_dev *cdev = c->cdev; struct usb_composite_dev *cdev = c->cdev;
struct uvc_device *uvc = to_uvc(f); struct uvc_device *uvc = to_uvc(f);
long wait_ret = 1;
uvcg_info(f, "%s()\n", __func__); uvcg_info(f, "%s()\n", __func__);
/* If we know we're connected via v4l2, then there should be a cleanup
* of the device from userspace either via UVC_EVENT_DISCONNECT or
* though the video device removal uevent. Allow some time for the
* application to close out before things get deleted.
*/
if (uvc->func_connected) {
uvcg_dbg(f, "waiting for clean disconnect\n");
wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
uvc->func_connected == false, msecs_to_jiffies(500));
uvcg_dbg(f, "done waiting with ret: %ld\n", wait_ret);
}
device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
video_unregister_device(&uvc->vdev); video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev); v4l2_device_unregister(&uvc->v4l2_dev);
if (uvc->func_connected) {
/* Wait for the release to occur to ensure there are no longer any
* pending operations that may cause panics when resources are cleaned
* up.
*/
uvcg_warn(f, "%s no clean disconnect, wait for release\n", __func__);
wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue,
uvc->func_connected == false, msecs_to_jiffies(1000));
uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret);
}
usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
kfree(uvc->control_buf); kfree(uvc->control_buf);
...@@ -915,6 +939,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) ...@@ -915,6 +939,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
mutex_init(&uvc->video.mutex); mutex_init(&uvc->video.mutex);
uvc->state = UVC_STATE_DISCONNECTED; uvc->state = UVC_STATE_DISCONNECTED;
init_waitqueue_head(&uvc->func_connected_queue);
opts = fi_to_f_uvc_opts(fi); opts = fi_to_f_uvc_opts(fi);
mutex_lock(&opts->lock); mutex_lock(&opts->lock);
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/wait.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
...@@ -129,6 +130,7 @@ struct uvc_device { ...@@ -129,6 +130,7 @@ struct uvc_device {
struct usb_function func; struct usb_function func;
struct uvc_video video; struct uvc_video video;
bool func_connected; bool func_connected;
wait_queue_head_t func_connected_queue;
/* Descriptors */ /* Descriptors */
struct { struct {
......
...@@ -253,10 +253,11 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, ...@@ -253,10 +253,11 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh,
static void uvc_v4l2_disable(struct uvc_device *uvc) static void uvc_v4l2_disable(struct uvc_device *uvc)
{ {
uvc->func_connected = false;
uvc_function_disconnect(uvc); uvc_function_disconnect(uvc);
uvcg_video_enable(&uvc->video, 0); uvcg_video_enable(&uvc->video, 0);
uvcg_free_buffers(&uvc->video.queue); uvcg_free_buffers(&uvc->video.queue);
uvc->func_connected = false;
wake_up_interruptible(&uvc->func_connected_queue);
} }
static int static int
......
...@@ -145,6 +145,7 @@ enum dev_state { ...@@ -145,6 +145,7 @@ enum dev_state {
STATE_DEV_INVALID = 0, STATE_DEV_INVALID = 0,
STATE_DEV_OPENED, STATE_DEV_OPENED,
STATE_DEV_INITIALIZED, STATE_DEV_INITIALIZED,
STATE_DEV_REGISTERING,
STATE_DEV_RUNNING, STATE_DEV_RUNNING,
STATE_DEV_CLOSED, STATE_DEV_CLOSED,
STATE_DEV_FAILED STATE_DEV_FAILED
...@@ -508,6 +509,7 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value) ...@@ -508,6 +509,7 @@ static int raw_ioctl_run(struct raw_dev *dev, unsigned long value)
ret = -EINVAL; ret = -EINVAL;
goto out_unlock; goto out_unlock;
} }
dev->state = STATE_DEV_REGISTERING;
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
ret = usb_gadget_probe_driver(&dev->driver); ret = usb_gadget_probe_driver(&dev->driver);
......
...@@ -19,11 +19,6 @@ ...@@ -19,11 +19,6 @@
#define HS_BW_BOUNDARY 6144 #define HS_BW_BOUNDARY 6144
/* usb2 spec section11.18.1: at most 188 FS bytes per microframe */ /* usb2 spec section11.18.1: at most 188 FS bytes per microframe */
#define FS_PAYLOAD_MAX 188 #define FS_PAYLOAD_MAX 188
/*
* max number of microframes for split transfer,
* for fs isoc in : 1 ss + 1 idle + 7 cs
*/
#define TT_MICROFRAMES_MAX 9
#define DBG_BUF_EN 64 #define DBG_BUF_EN 64
...@@ -242,28 +237,17 @@ static void drop_tt(struct usb_device *udev) ...@@ -242,28 +237,17 @@ static void drop_tt(struct usb_device *udev)
static struct mu3h_sch_ep_info * static struct mu3h_sch_ep_info *
create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev, create_sch_ep(struct xhci_hcd_mtk *mtk, struct usb_device *udev,
struct usb_host_endpoint *ep, struct xhci_ep_ctx *ep_ctx) struct usb_host_endpoint *ep)
{ {
struct mu3h_sch_ep_info *sch_ep; struct mu3h_sch_ep_info *sch_ep;
struct mu3h_sch_bw_info *bw_info; struct mu3h_sch_bw_info *bw_info;
struct mu3h_sch_tt *tt = NULL; struct mu3h_sch_tt *tt = NULL;
u32 len_bw_budget_table;
bw_info = get_bw_info(mtk, udev, ep); bw_info = get_bw_info(mtk, udev, ep);
if (!bw_info) if (!bw_info)
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
if (is_fs_or_ls(udev->speed)) sch_ep = kzalloc(sizeof(*sch_ep), GFP_KERNEL);
len_bw_budget_table = TT_MICROFRAMES_MAX;
else if ((udev->speed >= USB_SPEED_SUPER)
&& usb_endpoint_xfer_isoc(&ep->desc))
len_bw_budget_table = get_esit(ep_ctx);
else
len_bw_budget_table = 1;
sch_ep = kzalloc(struct_size(sch_ep, bw_budget_table,
len_bw_budget_table),
GFP_KERNEL);
if (!sch_ep) if (!sch_ep)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -295,8 +279,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, ...@@ -295,8 +279,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
u32 mult; u32 mult;
u32 esit_pkts; u32 esit_pkts;
u32 max_esit_payload; u32 max_esit_payload;
u32 *bwb_table = sch_ep->bw_budget_table;
int i;
ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2)); ep_type = CTX_TO_EP_TYPE(le32_to_cpu(ep_ctx->ep_info2));
maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2)); maxpkt = MAX_PACKET_DECODED(le32_to_cpu(ep_ctx->ep_info2));
...@@ -332,7 +314,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, ...@@ -332,7 +314,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
*/ */
sch_ep->pkts = max_burst + 1; sch_ep->pkts = max_burst + 1;
sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts; sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
bwb_table[0] = sch_ep->bw_cost_per_microframe;
} else if (sch_ep->speed >= USB_SPEED_SUPER) { } else if (sch_ep->speed >= USB_SPEED_SUPER) {
/* usb3_r1 spec section4.4.7 & 4.4.8 */ /* usb3_r1 spec section4.4.7 & 4.4.8 */
sch_ep->cs_count = 0; sch_ep->cs_count = 0;
...@@ -349,7 +330,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, ...@@ -349,7 +330,6 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) { if (ep_type == INT_IN_EP || ep_type == INT_OUT_EP) {
sch_ep->pkts = esit_pkts; sch_ep->pkts = esit_pkts;
sch_ep->num_budget_microframes = 1; sch_ep->num_budget_microframes = 1;
bwb_table[0] = maxpkt * sch_ep->pkts;
} }
if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) { if (ep_type == ISOC_IN_EP || ep_type == ISOC_OUT_EP) {
...@@ -366,15 +346,8 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, ...@@ -366,15 +346,8 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
DIV_ROUND_UP(esit_pkts, sch_ep->pkts); DIV_ROUND_UP(esit_pkts, sch_ep->pkts);
sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1); sch_ep->repeat = !!(sch_ep->num_budget_microframes > 1);
sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
for (i = 0; i < sch_ep->num_budget_microframes - 1; i++)
bwb_table[i] = sch_ep->bw_cost_per_microframe;
/* last one <= bw_cost_per_microframe */
bwb_table[i] = maxpkt * esit_pkts
- i * sch_ep->bw_cost_per_microframe;
} }
sch_ep->bw_cost_per_microframe = maxpkt * sch_ep->pkts;
} else if (is_fs_or_ls(sch_ep->speed)) { } else if (is_fs_or_ls(sch_ep->speed)) {
sch_ep->pkts = 1; /* at most one packet for each microframe */ sch_ep->pkts = 1; /* at most one packet for each microframe */
...@@ -384,28 +357,7 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx, ...@@ -384,28 +357,7 @@ static void setup_sch_info(struct xhci_ep_ctx *ep_ctx,
*/ */
sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX); sch_ep->cs_count = DIV_ROUND_UP(maxpkt, FS_PAYLOAD_MAX);
sch_ep->num_budget_microframes = sch_ep->cs_count; sch_ep->num_budget_microframes = sch_ep->cs_count;
sch_ep->bw_cost_per_microframe = sch_ep->bw_cost_per_microframe = min_t(u32, maxpkt, FS_PAYLOAD_MAX);
(maxpkt < FS_PAYLOAD_MAX) ? maxpkt : FS_PAYLOAD_MAX;
/* init budget table */
if (ep_type == ISOC_OUT_EP) {
for (i = 0; i < sch_ep->num_budget_microframes; i++)
bwb_table[i] = sch_ep->bw_cost_per_microframe;
} else if (ep_type == INT_OUT_EP) {
/* only first one consumes bandwidth, others as zero */
bwb_table[0] = sch_ep->bw_cost_per_microframe;
} else { /* INT_IN_EP or ISOC_IN_EP */
bwb_table[0] = 0; /* start split */
bwb_table[1] = 0; /* idle */
/*
* due to cs_count will be updated according to cs
* position, assign all remainder budget array
* elements as @bw_cost_per_microframe, but only first
* @num_budget_microframes elements will be used later
*/
for (i = 2; i < TT_MICROFRAMES_MAX; i++)
bwb_table[i] = sch_ep->bw_cost_per_microframe;
}
} }
} }
...@@ -422,7 +374,7 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, ...@@ -422,7 +374,7 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
for (j = 0; j < sch_ep->num_budget_microframes; j++) { for (j = 0; j < sch_ep->num_budget_microframes; j++) {
k = XHCI_MTK_BW_INDEX(base + j); k = XHCI_MTK_BW_INDEX(base + j);
bw = sch_bw->bus_bw[k] + sch_ep->bw_budget_table[j]; bw = sch_bw->bus_bw[k] + sch_ep->bw_cost_per_microframe;
if (bw > max_bw) if (bw > max_bw)
max_bw = bw; max_bw = bw;
} }
...@@ -433,18 +385,16 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw, ...@@ -433,18 +385,16 @@ static u32 get_max_bw(struct mu3h_sch_bw_info *sch_bw,
static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw, static void update_bus_bw(struct mu3h_sch_bw_info *sch_bw,
struct mu3h_sch_ep_info *sch_ep, bool used) struct mu3h_sch_ep_info *sch_ep, bool used)
{ {
int bw_updated;
u32 base; u32 base;
int i, j, k; int i, j;
bw_updated = sch_ep->bw_cost_per_microframe * (used ? 1 : -1);
for (i = 0; i < sch_ep->num_esit; i++) { for (i = 0; i < sch_ep->num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit; base = sch_ep->offset + i * sch_ep->esit;
for (j = 0; j < sch_ep->num_budget_microframes; j++) { for (j = 0; j < sch_ep->num_budget_microframes; j++)
k = XHCI_MTK_BW_INDEX(base + j); sch_bw->bus_bw[XHCI_MTK_BW_INDEX(base + j)] += bw_updated;
if (used)
sch_bw->bus_bw[k] += sch_ep->bw_budget_table[j];
else
sch_bw->bus_bw[k] -= sch_ep->bw_budget_table[j];
}
} }
} }
...@@ -464,7 +414,7 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset) ...@@ -464,7 +414,7 @@ static int check_fs_bus_bw(struct mu3h_sch_ep_info *sch_ep, int offset)
*/ */
for (j = 0; j < sch_ep->num_budget_microframes; j++) { for (j = 0; j < sch_ep->num_budget_microframes; j++) {
k = XHCI_MTK_BW_INDEX(base + j); k = XHCI_MTK_BW_INDEX(base + j);
tmp = tt->fs_bus_bw[k] + sch_ep->bw_budget_table[j]; tmp = tt->fs_bus_bw[k] + sch_ep->bw_cost_per_microframe;
if (tmp > FS_PAYLOAD_MAX) if (tmp > FS_PAYLOAD_MAX)
return -ESCH_BW_OVERFLOW; return -ESCH_BW_OVERFLOW;
} }
...@@ -538,19 +488,17 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset) ...@@ -538,19 +488,17 @@ static int check_sch_tt(struct mu3h_sch_ep_info *sch_ep, u32 offset)
static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used) static void update_sch_tt(struct mu3h_sch_ep_info *sch_ep, bool used)
{ {
struct mu3h_sch_tt *tt = sch_ep->sch_tt; struct mu3h_sch_tt *tt = sch_ep->sch_tt;
int bw_updated;
u32 base; u32 base;
int i, j, k; int i, j;
bw_updated = sch_ep->bw_cost_per_microframe * (used ? 1 : -1);
for (i = 0; i < sch_ep->num_esit; i++) { for (i = 0; i < sch_ep->num_esit; i++) {
base = sch_ep->offset + i * sch_ep->esit; base = sch_ep->offset + i * sch_ep->esit;
for (j = 0; j < sch_ep->num_budget_microframes; j++) { for (j = 0; j < sch_ep->num_budget_microframes; j++)
k = XHCI_MTK_BW_INDEX(base + j); tt->fs_bus_bw[XHCI_MTK_BW_INDEX(base + j)] += bw_updated;
if (used)
tt->fs_bus_bw[k] += sch_ep->bw_budget_table[j];
else
tt->fs_bus_bw[k] -= sch_ep->bw_budget_table[j];
}
} }
if (used) if (used)
...@@ -710,7 +658,7 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev, ...@@ -710,7 +658,7 @@ static int add_ep_quirk(struct usb_hcd *hcd, struct usb_device *udev,
xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed)); xhci_dbg(xhci, "%s %s\n", __func__, decode_ep(ep, udev->speed));
sch_ep = create_sch_ep(mtk, udev, ep, ep_ctx); sch_ep = create_sch_ep(mtk, udev, ep);
if (IS_ERR_OR_NULL(sch_ep)) if (IS_ERR_OR_NULL(sch_ep))
return -ENOMEM; return -ENOMEM;
......
...@@ -83,7 +83,6 @@ struct mu3h_sch_bw_info { ...@@ -83,7 +83,6 @@ struct mu3h_sch_bw_info {
* times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets * times; 1: distribute the (bMaxBurst+1)*(Mult+1) packets
* according to @pkts and @repeat. normal mode is used by * according to @pkts and @repeat. normal mode is used by
* default * default
* @bw_budget_table: table to record bandwidth budget per microframe
*/ */
struct mu3h_sch_ep_info { struct mu3h_sch_ep_info {
u32 esit; u32 esit;
...@@ -109,7 +108,6 @@ struct mu3h_sch_ep_info { ...@@ -109,7 +108,6 @@ struct mu3h_sch_ep_info {
u32 pkts; u32 pkts;
u32 cs_count; u32 cs_count;
u32 burst_mode; u32 burst_mode;
u32 bw_budget_table[];
}; };
#define MU3C_U3_PORT_MAX 4 #define MU3C_U3_PORT_MAX 4
......
...@@ -2123,10 +2123,14 @@ static const struct usb_device_id option_ids[] = { ...@@ -2123,10 +2123,14 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(3) }, .driver_info = RSVD(3) },
{ USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */
.driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, .driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
{ USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */
{ USB_DEVICE_INTERFACE_CLASS(0x1782, 0x4d11, 0xff) }, /* Fibocom L610 (ECM/RNDIS mode) */
{ USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */ { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */
.driver_info = RSVD(4) | RSVD(5) }, .driver_info = RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */
.driver_info = RSVD(6) }, .driver_info = RSVD(6) },
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0106, 0xff) }, /* Fibocom MA510 (ECM mode w/ diag intf.) */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x010a, 0xff) }, /* Fibocom MA510 (ECM mode) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */ { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */
{ USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */
......
...@@ -106,6 +106,7 @@ static const struct usb_device_id id_table[] = { ...@@ -106,6 +106,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LM920_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LM930_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LM940_PRODUCT_ID) },
{ USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_TD620_PRODUCT_ID) },
{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
......
...@@ -135,6 +135,7 @@ ...@@ -135,6 +135,7 @@
#define HP_TD620_PRODUCT_ID 0x0956 #define HP_TD620_PRODUCT_ID 0x0956
#define HP_LD960_PRODUCT_ID 0x0b39 #define HP_LD960_PRODUCT_ID 0x0b39
#define HP_LD381_PRODUCT_ID 0x0f7f #define HP_LD381_PRODUCT_ID 0x0f7f
#define HP_LM930_PRODUCT_ID 0x0f9b
#define HP_LCM220_PRODUCT_ID 0x3139 #define HP_LCM220_PRODUCT_ID 0x3139
#define HP_LCM960_PRODUCT_ID 0x3239 #define HP_LCM960_PRODUCT_ID 0x3239
#define HP_LD220_PRODUCT_ID 0x3524 #define HP_LD220_PRODUCT_ID 0x3524
......
...@@ -166,6 +166,8 @@ static const struct usb_device_id id_table[] = { ...@@ -166,6 +166,8 @@ static const struct usb_device_id id_table[] = {
{DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */ {DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */
{DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */ {DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */
{DEVICE_SWI(0x1199, 0x90d2)}, /* Sierra Wireless EM9191 QDL */ {DEVICE_SWI(0x1199, 0x90d2)}, /* Sierra Wireless EM9191 QDL */
{DEVICE_SWI(0x1199, 0xc080)}, /* Sierra Wireless EM7590 QDL */
{DEVICE_SWI(0x1199, 0xc081)}, /* Sierra Wireless EM7590 */
{DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
{DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
......
...@@ -877,7 +877,7 @@ static int tcpci_remove(struct i2c_client *client) ...@@ -877,7 +877,7 @@ static int tcpci_remove(struct i2c_client *client)
/* Disable chip interrupts before unregistering port */ /* Disable chip interrupts before unregistering port */
err = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, 0); err = tcpci_write16(chip->tcpci, TCPC_ALERT_MASK, 0);
if (err < 0) if (err < 0)
return err; dev_warn(&client->dev, "Failed to disable irqs (%pe)\n", ERR_PTR(err));
tcpci_unregister_port(chip->tcpci); tcpci_unregister_port(chip->tcpci);
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include "tcpci.h" #include "tcpci.h"
#define MT6360_REG_PHYCTRL1 0x80
#define MT6360_REG_PHYCTRL3 0x82
#define MT6360_REG_PHYCTRL7 0x86
#define MT6360_REG_VCONNCTRL1 0x8C #define MT6360_REG_VCONNCTRL1 0x8C
#define MT6360_REG_MODECTRL2 0x8F #define MT6360_REG_MODECTRL2 0x8F
#define MT6360_REG_SWRESET 0xA0 #define MT6360_REG_SWRESET 0xA0
...@@ -22,6 +25,8 @@ ...@@ -22,6 +25,8 @@
#define MT6360_REG_DRPCTRL1 0xA2 #define MT6360_REG_DRPCTRL1 0xA2
#define MT6360_REG_DRPCTRL2 0xA3 #define MT6360_REG_DRPCTRL2 0xA3
#define MT6360_REG_I2CTORST 0xBF #define MT6360_REG_I2CTORST 0xBF
#define MT6360_REG_PHYCTRL11 0xCA
#define MT6360_REG_RXCTRL1 0xCE
#define MT6360_REG_RXCTRL2 0xCF #define MT6360_REG_RXCTRL2 0xCF
#define MT6360_REG_CTDCTRL2 0xEC #define MT6360_REG_CTDCTRL2 0xEC
...@@ -106,6 +111,27 @@ static int mt6360_tcpc_init(struct tcpci *tcpci, struct tcpci_data *tdata) ...@@ -106,6 +111,27 @@ static int mt6360_tcpc_init(struct tcpci *tcpci, struct tcpci_data *tdata)
if (ret) if (ret)
return ret; return ret;
/* BMC PHY */
ret = mt6360_tcpc_write16(regmap, MT6360_REG_PHYCTRL1, 0x3A70);
if (ret)
return ret;
ret = regmap_write(regmap, MT6360_REG_PHYCTRL3, 0x82);
if (ret)
return ret;
ret = regmap_write(regmap, MT6360_REG_PHYCTRL7, 0x36);
if (ret)
return ret;
ret = mt6360_tcpc_write16(regmap, MT6360_REG_PHYCTRL11, 0x3C60);
if (ret)
return ret;
ret = regmap_write(regmap, MT6360_REG_RXCTRL1, 0xE8);
if (ret)
return ret;
/* Set shipping mode off, AUTOIDLE on */ /* Set shipping mode off, AUTOIDLE on */
return regmap_write(regmap, MT6360_REG_MODECTRL2, 0x7A); return regmap_write(regmap, MT6360_REG_MODECTRL2, 0x7A);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment