// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if IS_ENABLED(CONFIG_USB_CONFIGFS_F_SS_MON_GADGET) #include #endif #define USB_PHY_UTMI_CTRL0 (0x3c) #define OPMODE_MASK (0x3 << 3) #define OPMODE_NONDRIVING (0x1 << 3) #define SLEEPM BIT(0) #define USB_PHY_UTMI_CTRL5 (0x50) #define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) #define PHY_ENABLE BIT(0) #define SIDDQ_SEL BIT(1) #define SIDDQ BIT(2) #define RETENABLEN BIT(3) #define FSEL (0x7 << 4) #define FSEL_19_2_MHZ_VAL (0x4 << 4) #define FSEL_38_4_MHZ_VAL (0x6 << 4) #define USB_PHY_CFG_CTRL_1 (0x58) #define PHY_CFG_PLL_CPBIAS_CNTRL (0xfe) #define PHY_CFG_PLL_CPBIAS_CNTRL_SHIFT (0x1) #define USB_PHY_CFG_CTRL_2 (0x5c) #define PHY_CFG_PLL_FB_DIV_7_0 (0xff) #define DIV_7_0_19_2_MHZ_VAL (0x90) #define DIV_7_0_38_4_MHZ_VAL (0xc8) #define USB_PHY_CFG_CTRL_3 (0x60) #define PHY_CFG_PLL_FB_DIV_11_8 (0xf) #define DIV_11_8_19_2_MHZ_VAL (0x1) #define DIV_11_8_38_4_MHZ_VAL (0x0) #define PHY_CFG_PLL_REF_DIV (0xf << 4) #define PLL_REF_DIV_VAL (0x0) #define USB_PHY_HS_PHY_CTRL2 (0x64) #define VBUSVLDEXT0 BIT(0) #define USB2_SUSPEND_N BIT(2) #define USB2_SUSPEND_N_SEL BIT(3) #define VBUS_DET_EXT_SEL BIT(4) #define USB_PHY_CFG_CTRL_4 (0x68) #define PHY_CFG_PLL_GMP_CNTRL (0x3) #define PHY_CFG_PLL_GMP_CNTRL_SHIFT (0x0) #define PHY_CFG_PLL_INT_CNTRL (0xfc) #define PHY_CFG_PLL_INT_CNTRL_SHIFT (0x2) #define USB_PHY_CFG_CTRL_5 (0x6c) #define PHY_CFG_PLL_PROP_CNTRL (0x1f) #define PHY_CFG_PLL_PROP_CNTRL_SHIFT (0x0) #define PHY_CFG_PLL_VREF_TUNE (0x3 << 6) #define PHY_CFG_PLL_VREF_TUNE_SHIFT (6) #define USB_PHY_CFG_CTRL_6 (0x70) #define PHY_CFG_PLL_VCO_CNTRL (0x7) #define PHY_CFG_PLL_VCO_CNTRL_SHIFT (0x0) #define USB_PHY_CFG_CTRL_7 (0x74) #define USB_PHY_CFG_CTRL_8 (0x78) #define PHY_CFG_TX_FSLS_VREF_TUNE (0x3) #define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2) #define PHY_CFG_TX_HS_VREF_TUNE (0x7 << 3) #define PHY_CFG_TX_HS_VREF_TUNE_SHIFT (0x3) #define PHY_CFG_TX_HS_XV_TUNE (0x3 << 6) #define PHY_CFG_TX_HS_XV_TUNE_SHIFT (6) #define USB_PHY_CFG_CTRL_9 (0x7c) #define PHY_CFG_TX_PREEMP_TUNE (0x7) #define PHY_CFG_TX_PREEMP_TUNE_SHIFT (0x0) #define PHY_CFG_TX_RES_TUNE (0x3 << 3) #define PHY_CFG_TX_RES_TUNE_SHIFT (0x3) #define PHY_CFG_TX_RISE_TUNE (0x3 << 5) #define PHY_CFG_TX_RISE_TUNE_SHIFT (0x5) #define PHY_CFG_RCAL_BYPASS BIT(7) #define PHY_CFG_RCAL_BYPASS_SHIFT (0x7) #define USB_PHY_CFG_CTRL_10 (0x80) #define USB_PHY_CFG0 (0x94) #define DATAPATH_CTRL_OVERRIDE_EN BIT(0) #define USB_PHY_CFG1 (0x154) #define USB_PHY_CFG1_PLL_EN BIT(0) #define UTMI_PHY_CMN_CTRL0 (0x98) #define TESTBURNIN BIT(6) #define USB_PHY_FSEL_SEL (0xb8) /* M31 PHY XCFGI interface registers */ #define USB_PHY_XCFGI_39_32 (0x16c) #define USB_PHY_XCFGI_71_64 (0x17c) #define USB_PHY_XCFGI_31_24 (0x168) #define XCFG_U2_HSTX_SLEW (0x7) #define USB_PHY_XCFGI_7_0 (0x15c) #define XCFG_U2_PLLLOCKTIME (0x3) /* EUD CSR field */ #define EUD_EN2 BIT(0) /* VIOCTL_EUD_DETECT register based EUD_DETECT field */ #define EUD_DETECT BIT(0) #define USB_HSPHY_1P2_VOL_MIN 1200000 /* uV */ #define USB_HSPHY_1P2_VOL_MAX 1200000 /* uV */ #define USB_HSPHY_1P2_HPM_LOAD 5905 /* uA */ #define USB_HSPHY_VDD_HPM_LOAD 7757 /* uA */ #undef dev_dbg #define dev_dbg dev_err struct eusb_phy_tbl { u32 offset; u32 bit_mask; u32 val; }; #define EUSB_PHY_INIT_CFG(o, b, v) \ { \ .offset = o, \ .bit_mask = b, \ .val = v, \ } static const struct eusb_phy_tbl m31_eusb_phy_tbl[] = { EUSB_PHY_INIT_CFG(USB_PHY_CFG0, BIT(1), 1), EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, BIT(1), 1), // EUSB_PHY_INIT_CFG(USB_PHY_CFG1, BIT(0), 1), EUSB_PHY_INIT_CFG(USB_PHY_FSEL_SEL, BIT(0), 1), }; static const struct eusb_phy_tbl m31_eusb_phy_override_tbl[] = { EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_39_32, GENMASK(3, 2), 0), EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_71_64, GENMASK(3, 0), 7), EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_31_24, GENMASK(2, 0), 0), EUSB_PHY_INIT_CFG(USB_PHY_XCFGI_7_0, GENMASK(1, 0), 0), }; static const struct eusb_phy_tbl m31_eusb_phy_reset_tbl[] = { EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(3), 1), EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(2), 1), EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL0, BIT(0), 1), EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, BIT(1), 1), EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL_COMMON0, BIT(2), 0), EUSB_PHY_INIT_CFG(USB_PHY_UTMI_CTRL5, BIT(1), 0), EUSB_PHY_INIT_CFG(USB_PHY_HS_PHY_CTRL2, BIT(3), 0), EUSB_PHY_INIT_CFG(USB_PHY_CFG0, BIT(1), 0), }; struct eusb_phy_cfg { const struct eusb_phy_tbl *init_seq; int init_seq_num; const struct eusb_phy_tbl *override_seq; int override_seq_num; const struct eusb_phy_tbl *reset_seq; int reset_seq_num; }; static const struct eusb_phy_cfg m31_eusb_phy_cfg = { .init_seq = m31_eusb_phy_tbl, .init_seq_num = ARRAY_SIZE(m31_eusb_phy_tbl), .override_seq = m31_eusb_phy_override_tbl, .override_seq_num = ARRAY_SIZE(m31_eusb_phy_override_tbl), .reset_seq = m31_eusb_phy_reset_tbl, .reset_seq_num = ARRAY_SIZE(m31_eusb_phy_reset_tbl), }; struct m31_eusb2_phy { struct usb_phy phy; void __iomem *base; /* EUD related parameters */ phys_addr_t eud_reg; void __iomem *eud_enable_reg; void __iomem *eud_detect_reg; bool re_enable_eud; struct clk *ref_clk_src; struct clk *ref_clk; struct reset_control *phy_reset; struct regulator *vdd; struct regulator *vdda12; struct regulator *vdd_refgen; int vdd_levels[3]; /* none, low, high */ bool clocks_enabled; bool power_enabled; bool suspended; bool cable_connected; bool ref_clk_enable; struct power_supply *usb_psy; unsigned int vbus_draw; struct work_struct vbus_draw_work; int *param_override_seq; int param_override_seq_cnt; /* debugfs entries */ struct dentry *root; u8 xcfgi_39_32; u8 xcfgi_71_64; u8 xcfgi_31_24; u8 xcfgi_7_0; struct usb_repeater *ur; const struct eusb_phy_cfg *cfg; }; static inline bool is_eud_debug_mode_active(struct m31_eusb2_phy *phy) { if (phy->eud_enable_reg && (readl_relaxed(phy->eud_enable_reg) & EUD_EN2)) return true; return false; } static void msm_m31_eusb2_phy_clocks(struct m31_eusb2_phy *phy, bool on) { dev_dbg(phy->phy.dev, "clocks_enabled:%d on:%d\n", phy->clocks_enabled, on); if (phy->clocks_enabled == on) return; if (on) { clk_prepare_enable(phy->ref_clk_src); if (phy->ref_clk) clk_prepare_enable(phy->ref_clk); /* It takes extra time for the PLS field to reflect * the proper port status when PLL_EN is disabled. * so we add delay to ensure port status change reflection */ usleep_range(1500, 2000); } else { if (phy->ref_clk) clk_disable_unprepare(phy->ref_clk); clk_disable_unprepare(phy->ref_clk_src); } phy->clocks_enabled = on; } static void msm_m31_eusb2_phy_update_eud_detect(struct m31_eusb2_phy *phy, bool set) { if (set) writel_relaxed(EUD_DETECT, phy->eud_detect_reg); else writel_relaxed(readl_relaxed(phy->eud_detect_reg) & ~EUD_DETECT, phy->eud_detect_reg); } static int msm_m31_eusb2_phy_power(struct m31_eusb2_phy *phy, bool on) { int ret = 0; dev_dbg(phy->phy.dev, "turn %s regulators. power_enabled:%d\n", on ? "on" : "off", phy->power_enabled); if (phy->power_enabled == on) { dev_dbg(phy->phy.dev, "PHYs' regulators are already ON.\n"); return 0; } if (!on) goto clear_eud_det; ret = regulator_set_load(phy->vdd_refgen, USB_HSPHY_VDD_HPM_LOAD); if (ret < 0) { dev_err(phy->phy.dev, "Unable to set HPM of vdd_refgen:%d\n", ret); goto err_vdd; } ret = regulator_set_voltage(phy->vdd_refgen, phy->vdd_levels[1], phy->vdd_levels[2]); if (ret) { dev_err(phy->phy.dev, "Unable to set voltage for hsusb vdd_refgen\n"); goto put_vdd_refgen_lpm; } ret = regulator_enable(phy->vdd_refgen); if (ret) { dev_err(phy->phy.dev, "Unable to enable VDD refgen\n"); goto unconfig_vdd_refgen; } ret = regulator_set_load(phy->vdd, USB_HSPHY_VDD_HPM_LOAD); if (ret < 0) { dev_err(phy->phy.dev, "Unable to set HPM of vdd:%d\n", ret); goto disable_vdd_refgen; } ret = regulator_set_voltage(phy->vdd, phy->vdd_levels[1], phy->vdd_levels[2]); if (ret) { dev_err(phy->phy.dev, "Unable to set voltage for hsusb vdd\n"); goto put_vdd_lpm; } ret = regulator_enable(phy->vdd); if (ret) { dev_err(phy->phy.dev, "Unable to enable VDD\n"); goto unconfig_vdd; } ret = regulator_set_load(phy->vdda12, USB_HSPHY_1P2_HPM_LOAD); if (ret < 0) { dev_err(phy->phy.dev, "Unable to set HPM of vdda12:%d\n", ret); goto disable_vdd; } ret = regulator_set_voltage(phy->vdda12, USB_HSPHY_1P2_VOL_MIN, USB_HSPHY_1P2_VOL_MAX); if (ret) { dev_err(phy->phy.dev, "Unable to set voltage for vdda12:%d\n", ret); goto put_vdda12_lpm; } ret = regulator_enable(phy->vdda12); if (ret) { dev_err(phy->phy.dev, "Unable to enable vdda12:%d\n", ret); goto unset_vdda12; } /* Make sure all the writes are processed before setting EUD_DETECT */ mb(); /* Set eud_detect_reg after powering on eUSB PHY rails to bring EUD out of reset */ msm_m31_eusb2_phy_update_eud_detect(phy, true); phy->power_enabled = true; dev_dbg(phy->phy.dev, "eUSB2_PHY's regulators are turned ON.\n"); return ret; clear_eud_det: /* Clear eud_detect_reg to put EUD in reset */ msm_m31_eusb2_phy_update_eud_detect(phy, false); /* Make sure clearing EUD_DETECT is completed before turning off the regulators */ mb(); ret = regulator_disable(phy->vdda12); if (ret) dev_err(phy->phy.dev, "Unable to disable vdda12:%d\n", ret); unset_vdda12: ret = regulator_set_voltage(phy->vdda12, 0, USB_HSPHY_1P2_VOL_MAX); if (ret) dev_err(phy->phy.dev, "Unable to set (0) voltage for vdda12:%d\n", ret); put_vdda12_lpm: ret = regulator_set_load(phy->vdda12, 0); if (ret < 0) dev_err(phy->phy.dev, "Unable to set LPM of vdda12\n"); disable_vdd: ret = regulator_disable(phy->vdd); if (ret) dev_err(phy->phy.dev, "Unable to disable vdd:%d\n", ret); unconfig_vdd: ret = regulator_set_voltage(phy->vdd, phy->vdd_levels[0], phy->vdd_levels[2]); if (ret) dev_err(phy->phy.dev, "unable to set voltage for hsusb vdd\n"); put_vdd_lpm: ret = regulator_set_load(phy->vdd, 0); if (ret < 0) dev_err(phy->phy.dev, "Unable to set LPM of vdd\n"); /* case handling when regulator turning on failed */ if (!phy->power_enabled) return -EINVAL; disable_vdd_refgen: ret = regulator_disable(phy->vdd_refgen); if (ret) dev_err(phy->phy.dev, "Unable to disable vdd_refgen:%d\n", ret); unconfig_vdd_refgen: ret = regulator_set_voltage(phy->vdd_refgen, phy->vdd_levels[0], phy->vdd_levels[2]); if (ret) dev_err(phy->phy.dev, "unable to set voltage for hsusb vdd_refgen\n"); put_vdd_refgen_lpm: ret = regulator_set_load(phy->vdd_refgen, 0); if (ret < 0) dev_err(phy->phy.dev, "Unable to set LPM of vdd_refgen\n"); /* case handling when regulator turning on failed */ if (!phy->power_enabled) return -EINVAL; err_vdd: phy->power_enabled = false; dev_dbg(phy->phy.dev, "eusb2_PHY's regulators are turned OFF.\n"); return ret; } static void msm_m31_eusb2_write_readback(void __iomem *base, u32 offset, const u32 mask, u32 val) { u32 write_val, tmp = readl_relaxed(base + offset); tmp &= ~mask; /* retain other bits */ write_val = tmp | val; writel_relaxed(write_val, base + offset); /* Read back to see if val was written */ tmp = readl_relaxed(base + offset); tmp &= mask; /* clear other bits */ if (tmp != val) pr_err("write: %x to offset: %x FAILED\n", val, offset); } static void msm_m31_eusb2_phy_reset(struct m31_eusb2_phy *phy) { int ret; ret = reset_control_assert(phy->phy_reset); if (ret) dev_err(phy->phy.dev, "phy reset assert failed\n"); usleep_range(100, 150); ret = reset_control_deassert(phy->phy_reset); if (ret) dev_err(phy->phy.dev, "phy reset deassert failed\n"); } static void eusb2_phy_write_seq(struct m31_eusb2_phy *phy, u32 *seq, int cnt) { int i; dev_dbg(phy->phy.dev, "Seq count:%d\n", cnt); for (i = 0; i < cnt; i = i + 2) { dev_dbg(phy->phy.dev, "write 0x%02x to 0x%02x\n", seq[i], seq[i + 1]); writel_relaxed(seq[i], phy->base + seq[i + 1]); } } static void msm_m31_eusb2_parameter_override(struct m31_eusb2_phy *phy) { const struct eusb_phy_cfg *cfg = phy->cfg; const struct eusb_phy_tbl *tbl = cfg->override_seq; /* override init sequence using devicetree based values */ eusb2_phy_write_seq(phy, phy->param_override_seq, phy->param_override_seq_cnt); /* override tune params using debugfs based values */ /* USB_PHY_XCFGI_39_32 */ if (phy->xcfgi_39_32 != 0xFF) msm_m31_eusb2_write_readback(phy->base, tbl[0].offset, tbl[0].bit_mask, phy->xcfgi_39_32 << 2); /* USB_PHY_XCFGI_71_64 */ if (phy->xcfgi_71_64 != 0xFF) msm_m31_eusb2_write_readback(phy->base, tbl[1].offset, tbl[1].bit_mask, phy->xcfgi_71_64); /* USB_PHY_XCFGI_31_24 */ if (phy->xcfgi_31_24 != 0xFF) msm_m31_eusb2_write_readback(phy->base, tbl[2].offset, tbl[2].bit_mask, phy->xcfgi_31_24); /* USB_PHY_XCFGI_7_0 */ if (phy->xcfgi_7_0 != 0xFF) msm_m31_eusb2_write_readback(phy->base, tbl[3].offset, tbl[3].bit_mask, phy->xcfgi_7_0); } static void msm_m31_eusb2_ref_clk_init(struct usb_phy *uphy) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); msm_m31_eusb2_write_readback(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, FSEL, FSEL_38_4_MHZ_VAL); } static int msm_m31_eusb2_repeater_reset_and_init(struct m31_eusb2_phy *phy) { int ret; if (phy->ur) phy->ur->flags = phy->phy.flags; ret = usb_repeater_powerup(phy->ur); if (ret) dev_err(phy->phy.dev, "repeater powerup failed.\n"); ret = usb_repeater_reset(phy->ur, true); if (ret) dev_err(phy->phy.dev, "repeater reset failed.\n"); #if IS_ENABLED(CONFIG_USB_PHY_SETTING_QCOM) if (phy->ur) { if (phy->phy.flags & PHY_HOST_MODE) phy->ur->is_host = true; else phy->ur->is_host = false; } else dev_err(phy->phy.dev, "phy->ur is null.\n"); /* device start up time. TI 3ms, NXP 1ms */ usleep_range(3000, 3500); #endif ret = usb_repeater_init(phy->ur); if (ret) dev_err(phy->phy.dev, "repeater init failed.\n"); return ret; } static void msm_m31_eusb2_phy_write_configs(struct m31_eusb2_phy *phy, const struct eusb_phy_tbl tbl[], int num) { int i; const struct eusb_phy_tbl *t = tbl; for (i = 0 ; i < num; i++, t++) { dev_dbg(phy->phy.dev, "Offset:%x BitMask:%x Value:%x", t->offset, t->bit_mask, t->val); msm_m31_eusb2_write_readback(phy->base, t->offset, t->bit_mask, t->val << __ffs(t->bit_mask)); } } static int msm_m31_eusb2_phy_init(struct usb_phy *uphy) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); int ret; const struct eusb_phy_cfg *cfg = phy->cfg; dev_dbg(uphy->dev, "phy_flags:%x\n", phy->phy.flags); if (is_eud_debug_mode_active(phy)) { /* if in host mode, disable EUD debug mode */ if (phy->phy.flags & PHY_HOST_MODE) { qcom_scm_io_writel(phy->eud_reg, 0x0); phy->re_enable_eud = true; } else { msm_m31_eusb2_phy_power(phy, true); msm_m31_eusb2_phy_clocks(phy, true); return msm_m31_eusb2_repeater_reset_and_init(phy); } } ret = msm_m31_eusb2_phy_power(phy, true); if (ret) return ret; ret = msm_m31_eusb2_repeater_reset_and_init(phy); if (ret) { dev_err(phy->phy.dev, "repeater powerup failed.\n"); return ret; } msm_m31_eusb2_phy_clocks(phy, true); msm_m31_eusb2_phy_reset(phy); msm_m31_eusb2_phy_write_configs(phy, cfg->init_seq, cfg->init_seq_num); msm_m31_eusb2_ref_clk_init(uphy); msm_m31_eusb2_phy_write_configs(phy, cfg->override_seq, cfg->override_seq_num); msm_m31_eusb2_parameter_override(phy); msm_m31_eusb2_phy_write_configs(phy, cfg->reset_seq, cfg->reset_seq_num); return 0; } static int msm_m31_eusb2_phy_set_suspend(struct usb_phy *uphy, int suspend) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); if (phy->suspended && suspend) { dev_dbg(uphy->dev, "USB PHY is already suspended\n"); return 0; } dev_dbg(uphy->dev, "phy->flags:0x%x\n", phy->phy.flags); if (suspend) { /* Bus suspend handling */ if (phy->cable_connected || (phy->phy.flags & PHY_HOST_MODE)) { msm_m31_eusb2_phy_clocks(phy, false); goto suspend_exit; } /* Cable disconnect handling */ if (phy->re_enable_eud) { dev_dbg(uphy->dev, "re-enabling EUD\n"); qcom_scm_io_writel(phy->eud_reg, 0x1); phy->re_enable_eud = false; } /* With EUD spoof disconnect, keep clk and ldos on */ if (phy->phy.flags & EUD_SPOOF_DISCONNECT || is_eud_debug_mode_active(phy)) goto suspend_exit; msm_m31_eusb2_phy_clocks(phy, false); msm_m31_eusb2_phy_power(phy, false); /* Hold repeater into reset after powering down PHY */ usb_repeater_reset(phy->ur, false); usb_repeater_powerdown(phy->ur); } else { /* Bus resume and cable connect handling */ msm_m31_eusb2_phy_clocks(phy, true); } suspend_exit: phy->suspended = !!suspend; return 0; } static int msm_m31_eusb2_phy_notify_connect(struct usb_phy *uphy, enum usb_device_speed speed) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); phy->cable_connected = true; return 0; } static int msm_m31_eusb2_phy_notify_disconnect(struct usb_phy *uphy, enum usb_device_speed speed) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); phy->cable_connected = false; return 0; } static void msm_m31_eusb2_phy_vbus_draw_work(struct work_struct *w) { struct m31_eusb2_phy *phy = container_of(w, struct m31_eusb2_phy, vbus_draw_work); union power_supply_propval val = {0}; int ret; if (!phy->usb_psy) { phy->usb_psy = power_supply_get_by_name("usb"); if (!phy->usb_psy) { dev_err(phy->phy.dev, "Could not get usb psy\n"); return; } } #if IS_ENABLED(CONFIG_USB_CONFIGFS_F_SS_MON_GADGET) /* USB SUSPEND CURRENT SETTINGS */ if (phy->vbus_draw == 2) { pr_err("[USB] make suspend currrent event\n"); make_suspend_current_event(); } #endif dev_info(phy->phy.dev, "Avail curr from USB = %u\n", phy->vbus_draw); /* Set max current limit in uA */ val.intval = 1000 * phy->vbus_draw; ret = power_supply_set_property(phy->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val); if (ret) { dev_dbg(phy->phy.dev, "Error setting ICL:(%d)\n", ret); return; } } static int msm_m31_eusb2_phy_set_power(struct usb_phy *uphy, unsigned int mA) { struct m31_eusb2_phy *phy = container_of(uphy, struct m31_eusb2_phy, phy); if (phy->cable_connected && (mA == 0)) return 0; phy->vbus_draw = mA; schedule_work(&phy->vbus_draw_work); return 0; } static void msm_m31_eusb2_phy_create_debugfs(struct m31_eusb2_phy *phy) { phy->root = debugfs_create_dir(dev_name(phy->phy.dev), NULL); debugfs_create_x8("xcfgi_39_32", 0644, phy->root, &phy->xcfgi_39_32); phy->xcfgi_39_32 = 0xFF; debugfs_create_x8("xcfgi_71_64", 0644, phy->root, &phy->xcfgi_71_64); phy->xcfgi_71_64 = 0xFF; debugfs_create_x8("xcfgi_31_24", 0644, phy->root, &phy->xcfgi_31_24); phy->xcfgi_31_24 = 0xFF; debugfs_create_x8("xcfgi_7_0", 0644, phy->root, &phy->xcfgi_7_0); phy->xcfgi_7_0 = 0xFF; } static int msm_m31_eusb2_phy_probe(struct platform_device *pdev) { struct m31_eusb2_phy *phy; struct device *dev = &pdev->dev; struct resource *res; int ret; struct usb_repeater *ur; pr_info("%s\n", __func__); phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); if (!phy) { ret = -ENOMEM; goto err_ret; } phy->cfg = of_device_get_match_data(dev); if (!phy->cfg) { ret = -ENODEV; goto err_ret; } ur = devm_usb_get_repeater_by_phandle(dev, "usb-repeater", 0); if (IS_ERR(ur)) { dev_dbg(dev, "Repeater not available!\n"); ret = PTR_ERR(ur); goto err_ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eusb2_phy_base"); if (!res) { dev_err(dev, "missing eusb2phy memory resource\n"); ret = -ENODEV; goto err_ret; } phy->base = devm_ioremap_resource(dev, res); if (IS_ERR(phy->base)) { dev_err(dev, "ioremap failed\n"); ret = PTR_ERR(phy->base); goto err_ret; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eud_enable_reg"); if (res) { phy->eud_enable_reg = devm_ioremap_resource(dev, res); if (IS_ERR(phy->eud_enable_reg)) { ret = PTR_ERR(phy->eud_enable_reg); dev_err(dev, "eud_enable_reg ioremap err:%d\n", ret); goto err_ret; } phy->eud_reg = res->start; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eud_detect_reg"); if (!res) { dev_err(dev, "missing eud_detect register address\n"); ret = -ENODEV; goto err_ret; } phy->eud_detect_reg = devm_ioremap_resource(dev, res); if (IS_ERR(phy->eud_detect_reg)) { ret = PTR_ERR(phy->eud_detect_reg); dev_err(dev, "eud_detect_reg ioremap err:%d\n", ret); goto err_ret; } phy->ref_clk_src = devm_clk_get(dev, "ref_clk_src"); if (IS_ERR(phy->ref_clk_src)) { dev_dbg(dev, "clk get failed for ref_clk_src\n"); ret = PTR_ERR(phy->ref_clk_src); goto err_ret; } phy->ref_clk = devm_clk_get_optional(dev, "ref_clk"); if (IS_ERR(phy->ref_clk)) { dev_dbg(dev, "clk get failed for ref_clk\n"); ret = PTR_ERR(phy->ref_clk); goto err_ret; } phy->phy_reset = devm_reset_control_get(dev, "phy_reset"); if (IS_ERR(phy->phy_reset)) { ret = PTR_ERR(phy->phy_reset); goto err_ret; } ret = of_property_read_variable_u32_array(dev->of_node, "qcom,vdd-voltage-level", (u32 *) phy->vdd_levels, 0, ARRAY_SIZE(phy->vdd_levels)); if (ret < 2) { dev_err(dev, "error reading qcom,vdd-voltage-level property\n"); goto err_ret; } phy->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(phy->vdd)) { dev_err(dev, "unable to get vdd supply\n"); ret = PTR_ERR(phy->vdd); goto err_ret; } phy->vdda12 = devm_regulator_get(dev, "vdda12"); if (IS_ERR(phy->vdda12)) { dev_err(dev, "unable to get vdda12 supply\n"); ret = PTR_ERR(phy->vdda12); goto err_ret; } phy->vdd_refgen = devm_regulator_get(dev, "vdd_refgen"); if (IS_ERR(phy->vdd_refgen)) { dev_err(dev, "unable to get vdd_refgen supply\n"); ret = PTR_ERR(phy->vdd_refgen); goto err_ret; } phy->param_override_seq_cnt = of_property_count_elems_of_size( dev->of_node, "qcom,param-override-seq", sizeof(*phy->param_override_seq)); if (phy->param_override_seq_cnt > 0) { if (phy->param_override_seq_cnt % 2) { dev_err(dev, "invalid param_override_seq_len\n"); ret = -EINVAL; goto err_ret; } phy->param_override_seq = devm_kcalloc(dev, phy->param_override_seq_cnt, sizeof(*phy->param_override_seq), GFP_KERNEL); if (!phy->param_override_seq) { ret = -ENOMEM; goto err_ret; } ret = of_property_read_variable_u32_array(dev->of_node, "qcom,param-override-seq", phy->param_override_seq, 0, phy->param_override_seq_cnt); if (ret % 2) { dev_err(dev, "qcom,param-override-seq read failed %d\n", ret); goto err_ret; } } phy->ur = ur; phy->phy.dev = dev; platform_set_drvdata(pdev, phy); phy->phy.init = msm_m31_eusb2_phy_init; phy->phy.set_suspend = msm_m31_eusb2_phy_set_suspend; phy->phy.notify_connect = msm_m31_eusb2_phy_notify_connect; phy->phy.notify_disconnect = msm_m31_eusb2_phy_notify_disconnect; phy->phy.set_power = msm_m31_eusb2_phy_set_power; phy->phy.type = USB_PHY_TYPE_USB2; phy->phy.label = "M31 eUSB2"; ret = usb_add_phy_dev(&phy->phy); if (ret) goto err_ret; INIT_WORK(&phy->vbus_draw_work, msm_m31_eusb2_phy_vbus_draw_work); msm_m31_eusb2_phy_create_debugfs(phy); /* * EUD may be enabled in boot loader and to keep EUD session alive across * kernel boot till USB phy driver is initialized based on cable status, * keep LDOs and clocks on here, and intiialize the USB repeater. */ if (is_eud_debug_mode_active(phy)) { msm_m31_eusb2_phy_power(phy, true); msm_m31_eusb2_phy_clocks(phy, true); msm_m31_eusb2_repeater_reset_and_init(phy); } dev_dbg(dev, "M31 Phy Probed"); return 0; err_ret: pr_info("%s failed. ret(%d)\n", __func__, ret); return ret; } static int msm_m31_eusb2_phy_remove(struct platform_device *pdev) { struct m31_eusb2_phy *phy = platform_get_drvdata(pdev); flush_work(&phy->vbus_draw_work); if (phy->usb_psy) power_supply_put(phy->usb_psy); debugfs_remove_recursive(phy->root); usb_remove_phy(&phy->phy); if (phy->ref_clk) clk_disable_unprepare(phy->ref_clk); msm_m31_eusb2_phy_clocks(phy, false); msm_m31_eusb2_phy_power(phy, false); return 0; } static const struct of_device_id msm_usb_id_table[] = { { .compatible = "qcom,usb-m31-eusb2-phy", .data = &m31_eusb_phy_cfg, }, { }, }; MODULE_DEVICE_TABLE(of, msm_usb_id_table); static struct platform_driver msm_m31_eusb2_phy_driver = { .probe = msm_m31_eusb2_phy_probe, .remove = msm_m31_eusb2_phy_remove, .driver = { .name = "msm_m31_eusb2_phy", .of_match_table = of_match_ptr(msm_usb_id_table), }, }; module_platform_driver(msm_m31_eusb2_phy_driver); MODULE_DESCRIPTION("MSM USB M31 eUSB2 PHY driver"); MODULE_LICENSE("GPL");