MSM8953/SDM450 去PMI的USB3.0 TYPE-C Micro USB OTG功能适配
提前说明一下有哪些“坑”。
1、PM8953 GPIO_8的TZ权限
2、PM8953 GPIO_8寄存器的写入保护
3、去掉高通默认的ID检测
4、增加dwc3的ID检测
5、增加TYPE-C的ID PIN控制
设备树配置:
&tlmm {
usb_id_default: usb_id_default {
mux {
pins = "gpio1";
function = "gpio";
};
config {
pins = "gpio1";
drive-strength = <2>;
bias-pull-up;
};
};
};
&pm8953_typec {
qcom,ssmux-gpio = <&tlmm 139 GPIO_ACTIVE_LOW>;
qcom,id-gpio = <&pm8953_gpios 8 0x0>;
pinctrl-names = "default";
pinctrl-0 = <&typec_ssmux_config>;
status = "ok";
};
&usb3 {
vbus_dwc3-supply = <&usb_otg_switch>;
otg,id_det_pin = <&tlmm 1 0x0>;
extcon = <&usb_detect>;
pinctrl-names = "default";
pinctrl-0 = <&usb_id_default>;
};
&usb_otg_switch {
gpio = <&tlmm 3 0>;
};
&soc {
usb_detect: usb_detect {
compatible = "qcom,gpio-usbdetect";
interrupt-parent = <&spmi_bus>;
interrupts = <0x0 0xc6 0x0>;
interrupt-names = "vbus_det_irq";
qcom,vbus-det-gpio = <&pm8953_gpios 7 0x00>;
pinctrl-names = "default";
pinctrl-0 = <&pm8953_gpio7_default>;
};
};
修改PM8953 GPIO8 TZ权限
index e1d339e..dda5a23 100755
--- a/TZ.BF.4.0.5/trustzone_images/core/systemdrivers/pmic/config/msm8953_pm8950/src/pm_spmi_config.c
+++ b/TZ.BF.4.0.5/trustzone_images/core/systemdrivers/pmic/config/msm8953_pm8950/src/pm_spmi_config.c
@@ -167,7 +167,7 @@ SpmiCfg_ChannelCfg pm_spmi_pheriph_cfg [] =
{0x0, 0xFE, 0, PM_RPM_OWNER, PM_RPM_OWNER}, /* TRIM */
- {0x0, 0xC7, 0, PM_WCONNECT_OWNER, SPMI_OPEN_OWNER}, /* GPIO8 */
+ {0x0, 0xC7, 0, PM_APPS_HLOS_OWNER, SPMI_OPEN_OWNER}, /* GPIO8 */
{0x0, 0xC6, 0, PM_APPS_HLOS_OWNER, SPMI_OPEN_OWNER}, /* GPIO7 */
{0x0, 0xC5, 0, PM_WCONNECT_OWNER, SPMI_OPEN_OWNER}, /* GPIO6 */
{0x0, 0xC4, 0, PM_WCONNECT_OWNER, SPMI_OPEN_OWNER}, /* GPIO5 */
去除PM8953 GPIO_8寄存器的写入保护
index 0f0b7ba..f7946e0 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -451,6 +451,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
dev_err(&pa->spmic->dev,
"error: impermissible write to peripheral sid:%d addr:0x%x\n",
sid, addr);
+ if (!(0xc740 == (addr & 0xc740))) // skip PM8953 GPIO_8 Register protect check
return -ENODEV;
}
去掉高通默认的ID检测
diff --git a/drivers/platform/msm/gpio-usbdetect.c b/drivers/platform/msm/gpio-usbdetect.c
index 6730d4a..d2cbdea 100644
--- a/drivers/platform/msm/gpio-usbdetect.c
+++ b/drivers/platform/msm/gpio-usbdetect.c
@@ -22,6 +22,7 @@
#include <linux/gpio.h>
#include <linux/extcon.h>
#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
struct gpio_usbdetect {
struct platform_device *pdev;
@@ -45,66 +46,21 @@ static irqreturn_t gpio_usbdetect_vbus_irq(int irq, void *data)
struct gpio_usbdetect *usb = data;
union extcon_property_value val;
- usb->vbus_state = gpio_get_value(usb->gpio);
+ usb->vbus_state = !!gpio_get_value(usb->gpio);
+
if (usb->vbus_state) {
- dev_dbg(&usb->pdev->dev, "setting vbus notification\n");
+ dev_err(&usb->pdev->dev, "xcz setting vbus notification\n");
val.intval = true;
- extcon_set_property(usb->extcon_dev, EXTCON_USB,
- EXTCON_PROP_USB_SS, val);
+
extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 1);
} else {
- dev_dbg(&usb->pdev->dev, "setting vbus removed notification\n");
+ dev_err(&usb->pdev->dev, "xcz setting vbus removed notification\n");
extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB, 0);
}
return IRQ_HANDLED;
}
-static irqreturn_t gpio_usbdetect_id_irq(int irq, void *data)
-{
- struct gpio_usbdetect *usb = data;
- int ret;
-
- ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL,
- &usb->id_state);
- if (ret < 0) {
- dev_err(&usb->pdev->dev, "unable to read ID IRQ LINE\n");
- return IRQ_HANDLED;
- }
-
- return IRQ_WAKE_THREAD;
-}
-
-static irqreturn_t gpio_usbdetect_id_irq_thread(int irq, void *data)
-{
- struct gpio_usbdetect *usb = data;
- bool curr_id_state;
- static int prev_id_state = -EINVAL;
- union extcon_property_value val;
-
- curr_id_state = usb->id_state;
- if (curr_id_state == prev_id_state) {
- dev_dbg(&usb->pdev->dev, "no change in ID state\n");
- return IRQ_HANDLED;
- }
-
- if (curr_id_state) {
- dev_dbg(&usb->pdev->dev, "stopping usb host\n");
- extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 0);
- enable_irq(usb->vbus_det_irq);
- } else {
- dev_dbg(&usb->pdev->dev, "starting usb HOST\n");
- disable_irq(usb->vbus_det_irq);
- val.intval = true;
- extcon_set_property(usb->extcon_dev, EXTCON_USB_HOST,
- EXTCON_PROP_USB_SS, val);
- extcon_set_cable_state_(usb->extcon_dev, EXTCON_USB_HOST, 1);
- }
-
- prev_id_state = curr_id_state;
- return IRQ_HANDLED;
-}
-
static const u32 gpio_usb_extcon_exclusive[] = {0x3, 0};
static int gpio_usbdetect_probe(struct platform_device *pdev)
@@ -164,8 +120,6 @@ static int gpio_usbdetect_probe(struct platform_device *pdev)
"qcom,vbus-det-gpio", 0);
if (usb->gpio < 0) {
dev_err(&pdev->dev, "Failed to get gpio: %d\n", usb->gpio);
- rc = usb->gpio;
- goto error;
}
rc = gpio_request(usb->gpio, "vbus-det-gpio");
@@ -174,7 +128,7 @@ static int gpio_usbdetect_probe(struct platform_device *pdev)
goto error;
}
- usb->vbus_det_irq = gpio_to_irq(usb->gpio);
+ usb->vbus_det_irq = gpio_to_irq(usb->gpio);//0xc6;//= gpio_to_irq(usb->gpio);
if (usb->vbus_det_irq < 0) {
dev_err(&pdev->dev, "get vbus_det_irq failed\n");
rc = usb->vbus_det_irq;
@@ -191,35 +145,11 @@ static int gpio_usbdetect_probe(struct platform_device *pdev)
goto error;
}
- usb->id_det_irq = platform_get_irq_byname(pdev, "pmic_id_irq");
- if (usb->id_det_irq < 0) {
- dev_err(&pdev->dev, "get id_det_irq failed\n");
- rc = usb->id_det_irq;
- goto error;
- }
-
- rc = devm_request_threaded_irq(&pdev->dev, usb->id_det_irq,
- gpio_usbdetect_id_irq,
- gpio_usbdetect_id_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT, "id_det_irq", usb);
- if (rc) {
- dev_err(&pdev->dev, "request for id_det_irq failed: %d\n", rc);
- goto error;
- }
+ usb->id_det_irq = platform_get_irq_byname(pdev, "vbus_det_irq");
enable_irq_wake(usb->vbus_det_irq);
- enable_irq_wake(usb->id_det_irq);
dev_set_drvdata(&pdev->dev, usb);
- if (usb->id_det_irq) {
- gpio_usbdetect_id_irq(usb->id_det_irq, usb);
- if (!usb->id_state) {
- gpio_usbdetect_id_irq_thread(usb->id_det_irq, usb);
- return 0;
- }
- }
-
/* Read and report initial VBUS state */
gpio_usbdetect_vbus_irq(usb->vbus_det_irq, usb);
增加dwc3的ID检测
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index f549047..cc54672 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -55,6 +55,8 @@
#include "debug.h"
#include "xhci.h"
+#define DEBUG
+
#define SDP_CONNETION_CHECK_TIME 10000 /* in ms */
/* time out to wait for USB cable status notification (in ms)*/
@@ -235,6 +237,8 @@ struct dwc3_msm {
bool use_pdc_interrupts;
enum dwc3_id_state id_state;
unsigned long lpm_flags;
+ int id_det_pin;
+ int id_det_irq;
#define MDWC3_SS_PHY_SUSPEND BIT(0)
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1)
#define MDWC3_POWER_COLLAPSE BIT(2)
@@ -290,7 +294,7 @@ struct dwc3_msm {
#define DSTS_CONNECTSPD_SS 0x4
-
+static int dwc3_msm_id_notifier(struct notifier_block *nb, unsigned long event, void *ptr);
static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc);
static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA);
static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
@@ -1860,13 +1864,8 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event,
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);
- /*
- * If the core could not recover after MAX_ERROR_RECOVERY_TRIES,
- * skip the restart USB work and keep the core in softreset
- * state.
- */
- if (dwc->retries_on_error < MAX_ERROR_RECOVERY_TRIES)
- schedule_work(&mdwc->restart_usb_work);
+ /* restart USB which performs full reset and reconnect */
+ schedule_work(&mdwc->restart_usb_work);
break;
case DWC3_CONTROLLER_RESET_EVENT:
dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -2828,6 +2827,17 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data)
return IRQ_HANDLED;
}
+// add 2020-02-24
+static irqreturn_t id_det_irq_handle(int irq, void *data)
+{
+ struct dwc3_msm *mdwc = data;
+
+ dwc3_msm_id_notifier(&mdwc->id_nb, gpio_get_value(mdwc->id_det_pin) ? 0 : 1, mdwc->extcon_id);
+
+ return IRQ_HANDLED;
+}
+// add 2020-02-24 end
+
static int dwc3_cpu_notifier_cb(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
@@ -2953,7 +2963,7 @@ static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc)
return 0;
}
-static int dwc3_msm_id_notifier(struct notifier_block *nb,
+static int dwc3_msm_id_notifier(struct notifier_block *nb, //xcz
unsigned long event, void *ptr)
{
struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, id_nb);
@@ -3005,7 +3015,10 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, vbus_nb);
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
- dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);
+ dev_err(mdwc->dev, "vbus:%ld event received\n", event);
+
+ printk("xcz haha ===== vbus:%ld event received\n", event);
+
if (mdwc->vbus_active == event)
return NOTIFY_DONE;
@@ -3442,6 +3455,30 @@ static int dwc3_msm_probe(struct platform_device *pdev)
}
}
+ // add 2020-02-24
+ mdwc->id_det_pin = of_get_named_gpio(pdev->dev.of_node, "otg,id_det_pin", 0);
+ if (mdwc->id_det_pin > 0) {
+ ret = gpio_request(mdwc->id_det_pin, "id_det_pin");
+ if(0 != ret) {
+ dev_err(&pdev->dev, "xcz Otg id_det_pin request %d failed.\n", mdwc->id_det_pin);
+ }
+
+ mdwc->id_det_irq = gpio_to_irq(mdwc->id_det_pin);
+ dev_err(&pdev->dev, "xcz Otg id_det_pin: %d, irq: %d\n",
+ mdwc->id_det_pin, mdwc->id_det_irq);
+
+ ret = devm_request_irq(&pdev->dev,
+ mdwc->id_det_irq,
+ id_det_irq_handle,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "id_det_irq",
+ mdwc);
+ } else {
+ dev_err(&pdev->dev, "xcz Otg id_det_pin NUll\n");
+ }
+ // add 2020-02-24 end
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcsr_base");
if (!res) {
dev_dbg(&pdev->dev, "missing TCSR memory resource\n");
@@ -3701,7 +3738,8 @@ static int dwc3_msm_probe(struct platform_device *pdev)
if (pval.intval > 0)
dev_info(mdwc->dev, "charger detection in progress\n");
}
-
+ if(mdwc->id_det_pin > 0)
+ id_det_irq_handle(mdwc->id_det_irq, mdwc);
device_create_file(&pdev->dev, &dev_attr_mode);
device_create_file(&pdev->dev, &dev_attr_speed);
device_create_file(&pdev->dev, &dev_attr_usb_compliance_mode);
增加TYPE-C的ID PIN控制
diff --git a/drivers/power/supply/qcom/qpnp-typec.c b/drivers/power/supply/qcom/qpnp-typec.c
index 12aa16b..20f1a71 100644
--- a/drivers/power/supply/qcom/qpnp-typec.c
+++ b/drivers/power/supply/qcom/qpnp-typec.c
@@ -113,6 +113,7 @@ struct qpnp_typec_chip {
int ssmux_gpio;
enum of_gpio_flags gpio_flag;
int typec_state;
+ int id_gpio;
/* Dual role support */
bool role_reversal_supported;
@@ -280,6 +281,15 @@ static int qpnp_typec_configure_ssmux(struct qpnp_typec_chip *chip,
return rc;
}
}
+
+ if (chip->id_gpio) {
+ rc = gpio_direction_input(chip->id_gpio);
+ if (rc) {
+ pr_err("failed to configure usb id gpio rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
break;
case CC_1:
case CC_2:
@@ -526,6 +536,8 @@ static irqreturn_t dfp_detect_handler(int irq, void *_chip)
pr_debug("UFP status reg = 0x%x DFP status reg = 0x%x\n",
reg[0], reg[1]);
+ // pull down USB ID pin to start host
+ gpio_direction_output(chip->id_gpio, 0);
out:
mutex_unlock(&chip->typec_lock);
return IRQ_HANDLED;
@@ -545,6 +557,8 @@ static irqreturn_t dfp_detach_handler(int irq, void *_chip)
mutex_unlock(&chip->typec_lock);
+ // pull up USB ID pin to start device
+ gpio_direction_output(chip->id_gpio, 1);
return IRQ_HANDLED;
}
@@ -589,6 +603,27 @@ static int qpnp_typec_parse_dt(struct qpnp_typec_chip *chip)
}
}
+ /* USB ID configuration gpio */
+ if (of_find_property(node, "qcom,id-gpio", NULL)) {
+ chip->id_gpio = of_get_named_gpio(node,
+ "qcom,id-gpio", 0);
+ if (!gpio_is_valid(chip->id_gpio)) {
+ if (chip->id_gpio != -EPROBE_DEFER)
+ pr_err("failed to get usb id config gpio=%d\n",
+ chip->id_gpio);
+ return chip->id_gpio;
+ }
+
+ rc = devm_gpio_request(chip->dev, chip->id_gpio,
+ "typec_usb_id_gpio");
+ if (rc) {
+ pr_err("failed to request usb id gpio rc=%d\n", rc);
+ chip->id_gpio = 0;
+ } else {
+ gpio_direction_input(chip->id_gpio);
+ }
+ }
+
/* SS-Mux regulator */
if (of_find_property(node, "ss-mux-supply", NULL)) {
chip->ss_mux_vreg = devm_regulator_get(chip->dev, "ss-mux");

浙公网安备 33010602011771号