Merge "msm: mhi_dev: Increase size of ipa_clnt_hndl array"
diff --git a/arch/arm64/boot/dts/qcom/sxr1130-svr.dtsi b/arch/arm64/boot/dts/qcom/sxr1130-svr.dtsi
index 4dfa320..16ed764 100644
--- a/arch/arm64/boot/dts/qcom/sxr1130-svr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sxr1130-svr.dtsi
@@ -528,3 +528,7 @@
regulator-min-microvolt = <5700000>;
regulator-max-microvolt = <5700000>;
};
+
+&pm660_pdphy {
+ qcom,sxr1130-sxr-dp-sink;
+};
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 1a29b0e..e2584cd 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -252,6 +252,103 @@
return rc;
}
+static int dsi_panel_exd_gpio_request(struct dsi_panel *panel)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en)) {
+ rc = gpio_request(e_config->display_1p8_en, "display_1p8_en");
+ if (rc) {
+ pr_err("request for display_1p8_en failed, rc=%d\n",
+ rc);
+ goto error;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_5v_en)) {
+ rc = gpio_request(e_config->led_5v_en, "led_5v_en");
+ if (rc) {
+ pr_err("request for led_5v_en failed, rc=%d\n",
+ rc);
+ goto error_release_1p8;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_en1)) {
+ rc = gpio_request(e_config->led_en1, "led_en1");
+ if (rc) {
+ pr_err("request for led_en1 failed, rc=%d\n",
+ rc);
+ goto error_release_5v;
+ }
+ }
+
+ if (gpio_is_valid(e_config->led_en2)) {
+ rc = gpio_request(e_config->led_en2, "led_en2");
+ if (rc) {
+ pr_err("request for led_en2 failed, rc=%d\n",
+ rc);
+ goto error_release_led;
+ }
+ }
+
+ if (gpio_is_valid(e_config->oenab)) {
+ rc = gpio_request(e_config->oenab, "oenab");
+ if (rc) {
+ pr_err("request for oenab failed, rc=%d\n",
+ rc);
+ goto error_release_led2;
+ }
+ }
+
+ if (gpio_is_valid(e_config->selab)) {
+ rc = gpio_request(e_config->selab, "selab");
+ if (rc) {
+ pr_err("request for selab failed, rc=%d\n",
+ rc);
+ goto error_release_oenab;
+ }
+ }
+
+ if (gpio_is_valid(e_config->switch_power)) {
+ rc = gpio_request(e_config->switch_power, "switch_power");
+ if (rc) {
+ pr_err("request for switch_power failed, rc=%d\n",
+ rc);
+ goto error_release_selab;
+ }
+ }
+ return rc;
+
+error_release_selab:
+ if (gpio_is_valid(e_config->selab))
+ gpio_free(e_config->selab);
+error_release_oenab:
+ if (gpio_is_valid(e_config->oenab))
+ gpio_free(e_config->oenab);
+error_release_led2:
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_free(e_config->led_en2);
+error_release_led:
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_free(e_config->led_en1);
+error_release_5v:
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_free(e_config->led_5v_en);
+error_release_1p8:
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_free(e_config->display_1p8_en);
+error:
+ return rc;
+}
+
static int dsi_panel_gpio_request(struct dsi_panel *panel)
{
int rc = 0;
@@ -303,6 +400,34 @@
return rc;
}
+static int dsi_panel_exd_gpio_release(struct dsi_panel *panel)
+{
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_free(e_config->display_1p8_en);
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_free(e_config->led_5v_en);
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_free(e_config->led_en1);
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_free(e_config->led_en2);
+ if (gpio_is_valid(e_config->oenab))
+ gpio_free(e_config->oenab);
+ if (gpio_is_valid(e_config->selab))
+ gpio_free(e_config->selab);
+ if (gpio_is_valid(e_config->switch_power))
+ gpio_free(e_config->switch_power);
+
+ return 0;
+}
+
static int dsi_panel_gpio_release(struct dsi_panel *panel)
{
int rc = 0;
@@ -426,6 +551,110 @@
return rc;
}
+static int dsi_panel_exd_enable(struct dsi_panel *panel)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return 0;
+
+ if (gpio_is_valid(e_config->display_1p8_en)) {
+ rc = gpio_direction_output(e_config->display_1p8_en, 0);
+ if (rc) {
+ pr_err("unable to set dir for disp_1p8_en rc:%d\n",
+ rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->display_1p8_en, 1);
+ }
+
+ if (gpio_is_valid(e_config->switch_power)) {
+ rc = gpio_direction_output(e_config->switch_power, 0);
+ if (rc) {
+ pr_err("unable to set dir for switch_power rc:%d\n",
+ rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->switch_power, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_5v_en)) {
+ rc = gpio_direction_output(e_config->led_5v_en, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_5v_en rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_5v_en, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_en1)) {
+ rc = gpio_direction_output(e_config->led_en1, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_en1 rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_en1, 1);
+ }
+
+ if (gpio_is_valid(e_config->led_en2)) {
+ rc = gpio_direction_output(e_config->led_en2, 0);
+ if (rc) {
+ pr_err("unable to set dir for led_en2 rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->led_en2, 1);
+ }
+
+ if (gpio_is_valid(e_config->oenab)) {
+ rc = gpio_direction_output(e_config->oenab, 0);
+ if (rc) {
+ pr_err("unable to set dir for oenab rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->oenab, 0);
+ }
+
+ if (gpio_is_valid(e_config->selab)) {
+ rc = gpio_direction_output(e_config->selab, 0);
+ if (rc) {
+ pr_err("unable to set dir for selab rc:%d\n", rc);
+ goto exit;
+ }
+ gpio_set_value(e_config->selab, 1);
+ }
+exit:
+ return rc;
+}
+
+static void dsi_panel_exd_disable(struct dsi_panel *panel)
+{
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ if (!e_config->display_1p8_en && !e_config->led_5v_en &&
+ !e_config->led_en1 && !e_config->led_en2 &&
+ !e_config->oenab && !e_config->selab &&
+ !e_config->switch_power)
+ return;
+
+ if (gpio_is_valid(e_config->display_1p8_en))
+ gpio_set_value(e_config->display_1p8_en, 0);
+ if (gpio_is_valid(e_config->led_5v_en))
+ gpio_set_value(e_config->led_5v_en, 0);
+ if (gpio_is_valid(e_config->led_en1))
+ gpio_set_value(e_config->led_en1, 0);
+ if (gpio_is_valid(e_config->led_en2))
+ gpio_set_value(e_config->led_en2, 0);
+ if (gpio_is_valid(e_config->oenab))
+ gpio_set_value(e_config->oenab, 1);
+ if (gpio_is_valid(e_config->selab))
+ gpio_set_value(e_config->selab, 0);
+ if (gpio_is_valid(e_config->switch_power))
+ gpio_set_value(e_config->switch_power, 0);
+}
static int dsi_panel_power_on(struct dsi_panel *panel)
{
@@ -449,6 +678,13 @@
goto error_disable_gpio;
}
+ rc = dsi_panel_exd_enable(panel);
+ if (rc) {
+ pr_err("[%s] failed to reset panel, rc=%d\n", panel->name, rc);
+ dsi_panel_exd_disable(panel);
+ goto error_disable_gpio;
+ }
+
goto exit;
error_disable_gpio:
@@ -471,6 +707,8 @@
{
int rc = 0;
+ dsi_panel_exd_disable(panel);
+
if (gpio_is_valid(panel->reset_config.disp_en_gpio))
gpio_set_value(panel->reset_config.disp_en_gpio, 0);
@@ -1887,6 +2125,63 @@
return rc;
}
+static int dsi_panel_exd_parse_gpios(struct dsi_panel *panel,
+ struct device_node *of_node)
+{
+ int rc = 0;
+ struct dsi_panel_exd_config *e_config = &panel->exd_config;
+
+ e_config->display_1p8_en = of_get_named_gpio(of_node,
+ "qcom,1p8-en-gpio", 0);
+ if (!e_config->display_1p8_en) {
+ pr_debug("%s qcom,display-1p8-en-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_5v_en = of_get_named_gpio(of_node,
+ "qcom,led-5v-en-gpio", 0);
+ if (!e_config->led_5v_en) {
+ pr_debug("%s qcom,led-5v-en-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_en1 = of_get_named_gpio(of_node,
+ "qcom,led-driver-en1-gpio", 0);
+ if (!e_config->led_en1) {
+ pr_debug("%s qcom,led-driver-en1-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->led_en2 = of_get_named_gpio(of_node,
+ "qcom,led-driver-en2-gpio", 0);
+ if (!e_config->led_en2) {
+ pr_debug("%s qcom,led-driver-en2-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->oenab = of_get_named_gpio(of_node,
+ "qcom,oenab-gpio", 0);
+ if (!e_config->oenab) {
+ pr_debug("%s qcom,oenab-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->selab = of_get_named_gpio(of_node,
+ "qcom,selab-gpio", 0);
+ if (!e_config->selab) {
+ pr_debug("%s qcom,selab-gpio not found\n", __func__);
+ return -EINVAL;
+ }
+
+ e_config->switch_power = of_get_named_gpio(of_node,
+ "qcom,switch-power-gpio", 0);
+ if (!e_config->switch_power) {
+ pr_debug("%s qcom,switch_power not found\n", __func__);
+ return -EINVAL;
+ }
+ return rc;
+}
+
static int dsi_panel_parse_gpios(struct dsi_panel *panel,
struct device_node *of_node)
{
@@ -1942,6 +2237,12 @@
panel->reset_config.mode_sel_state = MODE_SEL_DUAL_PORT;
}
+ /* Extended display panel gpios parsed */
+ rc = dsi_panel_exd_parse_gpios(panel, of_node);
+ if (rc && rc != -EINVAL)
+ pr_err("[%s] failed to parse gpios, rc=%d\n",
+ panel->name, rc);
+
/* TODO: release memory */
rc = dsi_panel_parse_reset_sequence(panel, of_node);
if (rc) {
@@ -3105,8 +3406,17 @@
goto error_gpio_release;
}
+ rc = dsi_panel_exd_gpio_request(panel);
+ if (rc) {
+ pr_err("[%s] failed to request gpios, rc=%d\n", panel->name,
+ rc);
+ goto error_exd_gpio_release;
+ }
+
goto exit;
+error_exd_gpio_release:
+ (void)dsi_panel_exd_gpio_release(panel);
error_gpio_release:
(void)dsi_panel_gpio_release(panel);
error_pinctrl_deinit:
@@ -3142,6 +3452,11 @@
pr_err("[%s] failed to release gpios, rc=%d\n", panel->name,
rc);
+ rc = dsi_panel_exd_gpio_release(panel);
+ if (rc)
+ pr_err("[%s] failed to release gpios, rc=%d\n", panel->name,
+ rc);
+
rc = dsi_panel_pinctrl_deinit(panel);
if (rc)
pr_err("[%s] failed to deinit gpios, rc=%d\n", panel->name,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
index ab8ccee..8702375 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -161,6 +161,17 @@
DSI_PANEL_TYPE_MAX,
};
+/* Extended Panel config for panels with additional gpios */
+struct dsi_panel_exd_config {
+ int display_1p8_en;
+ int led_5v_en;
+ int switch_power;
+ int led_en1;
+ int led_en2;
+ int oenab;
+ int selab;
+};
+
struct dsi_panel {
const char *name;
enum dsi_panel_type type;
@@ -204,6 +215,8 @@
enum dsi_dms_mode dms_mode;
bool sync_broadcast_en;
+
+ struct dsi_panel_exd_config exd_config;
};
static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel)
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 64918e8..7dee607 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -67,6 +67,7 @@
HW_PLATFORM_STP = 23,
HW_PLATFORM_SBC = 24,
HW_PLATFORM_ADP = 25,
+ HW_PLATFORM_TTP = 30,
HW_PLATFORM_HDK = 31,
HW_PLATFORM_INVALID
};
@@ -89,6 +90,7 @@
[HW_PLATFORM_STP] = "STP",
[HW_PLATFORM_SBC] = "SBC",
[HW_PLATFORM_ADP] = "ADP",
+ [HW_PLATFORM_TTP] = "TTP",
[HW_PLATFORM_HDK] = "HDK",
};
diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c
index 312ae24..76a5896 100644
--- a/drivers/usb/gadget/function/f_qdss.c
+++ b/drivers/usb/gadget/function/f_qdss.c
@@ -1,7 +1,7 @@
/*
* f_qdss.c -- QDSS function Driver
*
- * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 2020, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1129,8 +1129,21 @@
static void usb_qdss_free_inst(struct usb_function_instance *fi)
{
struct usb_qdss_opts *opts;
+ struct usb_qdss_ch *ch;
+ unsigned long flags;
opts = container_of(fi, struct usb_qdss_opts, func_inst);
+ spin_lock_irqsave(&qdss_lock, flags);
+ list_for_each_entry(ch, &usb_qdss_ch_list, list) {
+ if (!strcmp(opts->channel_name, ch->name)) {
+ list_del(&ch->list);
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&qdss_lock, flags);
+ kfree(opts->channel_name);
+ destroy_workqueue(opts->usb_qdss->wq);
kfree(opts->usb_qdss);
kfree(opts);
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 3811792..a6a7380 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2018, Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2020, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -42,6 +42,13 @@
module_param(rev3_sink_only, bool, 0644);
MODULE_PARM_DESC(rev3_sink_only, "Enable power delivery rev3.0 sink only mode");
+#define XR1_DISCOVER_VDO 0x1085
+#define XR1_DEFAULT_VDO 0x0
+#define XR1_PIN_E_VDO 0x0082
+#define DP_USBPD_EVT_STATUS_XR1 0x10
+#define DP_USBPD_EVT_CONFIGURE_XR1 0x11
+static bool sxr_dp_mode;
+
enum usbpd_state {
PE_UNKNOWN,
PE_ERROR_RECOVERY,
@@ -394,6 +401,9 @@
#define IS_EXT(m, t) ((m) && PD_MSG_HDR_IS_EXTENDED((m)->hdr) && \
(PD_MSG_HDR_TYPE((m)->hdr) == (t)))
+#define SXR_SEND_SVDM(pd, cmd, num, tx_vdos, pos) usbpd_send_svdm(pd, 0xFF01, \
+ cmd, SVDM_CMD_TYPE_RESP_ACK, \
+ num, tx_vdos, pos)
struct usbpd {
struct device dev;
struct workqueue_struct *wq;
@@ -488,6 +498,7 @@
u8 get_battery_status_db;
bool send_get_battery_status;
u32 battery_sts_dobj;
+ bool is_sxr_dp_sink;
};
static LIST_HEAD(_usbpd); /* useful for debugging */
@@ -1698,7 +1709,47 @@
}
if (handler && handler->svdm_received) {
- handler->svdm_received(handler, cmd, cmd_type, vdos, num_vdos);
+ if (pd->is_sxr_dp_sink) {
+ u32 tx_vdos[1];
+
+ switch (cmd) {
+ /*CMD 3, Type 1, PayLoad 43 */
+ case USBPD_SVDM_DISCOVER_MODES:
+ usbpd_dbg(&pd->dev,
+ "USBPD_SVDM_DISCOVER_MODES\n");
+ tx_vdos[0] = XR1_DISCOVER_VDO;
+ usbpd_dbg(&pd->dev, "sending RESP_ACK\n");
+ SXR_SEND_SVDM(pd, cmd, 0x0, tx_vdos, 0x1);
+ break;
+ /*CMD 4, Type 1, PayLoad 44 */
+ case USBPD_SVDM_ENTER_MODE:
+ usbpd_dbg(&pd->dev, "USBPD_SVDM_ENTER_MODE\n");
+ tx_vdos[0] = XR1_DEFAULT_VDO;
+ usbpd_dbg(&pd->dev, "sending RESP_ACK\n");
+ SXR_SEND_SVDM(pd, cmd, 0x1, tx_vdos, 0x0);
+ break;
+ /*CMD 10, Type 1, PayLoad 50 */
+ case DP_USBPD_EVT_STATUS_XR1:
+ tx_vdos[0] = XR1_PIN_E_VDO; // Pin assign E
+ usbpd_dbg(&pd->dev,
+ "DP_USBPD_EVT_STATUS_XR1\n");
+ SXR_SEND_SVDM(pd, cmd, 0x1, tx_vdos, 0x1);
+ break;
+ /*CMD 11, Type 1, PayLoad 51 */
+ case DP_USBPD_EVT_CONFIGURE_XR1:
+ usbpd_dbg(&pd->dev,
+ "DP_USBPD_EVT_CONFIGURE_XR1\n");
+ tx_vdos[0] = XR1_DEFAULT_VDO;
+ usbpd_dbg(&pd->dev,
+ "DP_USBPD_EVT_STATUS_XR1\n");
+ SXR_SEND_SVDM(pd, cmd, 0x1, tx_vdos, 0x0);
+ break;
+ default:
+ usbpd_dbg(&pd->dev, "default mode:%d\n", cmd);
+ }
+ } else
+ handler->svdm_received(handler, cmd, cmd_type, vdos,
+ num_vdos);
return;
}
@@ -1716,9 +1767,21 @@
usbpd_send_svdm(pd, USBPD_SID, cmd,
SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3);
- } else if (cmd != USBPD_SVDM_ATTENTION) {
- usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK,
+ } else if (cmd != USBPD_SVDM_ATTENTION) {
+ if (pd->is_sxr_dp_sink) {
+ u32 tx_vdos_pd[3] = {
+ ID_HDR_VID,
+ 0xFF01,
+ 0x0,
+ };
+ usbpd_send_svdm(pd, USBPD_SID, cmd,
+ SVDM_CMD_TYPE_RESP_ACK, 0,
+ tx_vdos_pd, 3);
+ } else {
+ usbpd_send_svdm(pd, svid, cmd,
+ SVDM_CMD_TYPE_RESP_NAK,
SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0);
+ }
}
break;
@@ -4117,6 +4180,15 @@
goto put_psy;
}
+ /*
+ * Need to set is_sxr_dp_sink to TRUE only when device tree node is
+ * present, and sim_vid_display string is present in
+ * boot_command_line string.
+ */
+ if (sxr_dp_mode)
+ pd->is_sxr_dp_sink = device_property_present(parent,
+ "qcom,sxr1130-sxr-dp-sink");
+
pd->vconn_is_external = device_property_present(parent,
"qcom,vconn-uses-external-source");
@@ -4236,6 +4308,15 @@
static int __init usbpd_init(void)
{
+ char *cmdline;
+
+ cmdline = strnstr(boot_command_line,
+ "msm_drm.dsi_display0=dsi_sim_vid_display",
+ strlen(boot_command_line));
+ sxr_dp_mode = false;
+ if (cmdline)
+ sxr_dp_mode = true;
+
usbpd_ipc_log = ipc_log_context_create(NUM_LOG_PAGES, "usb_pd", 0);
return class_register(&usbpd_class);
}