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");