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控制

 

设备树配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
&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权限

1
2
3
4
5
6
7
8
9
10
11
12
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寄存器的写入保护

1
2
3
4
5
6
7
8
9
10
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检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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");

  

posted @   PYPYN  阅读(950)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示