162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2023, Linaro Limited 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/platform_device.h> 862306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 962306a36Sopenharmony_ci#include <linux/regmap.h> 1062306a36Sopenharmony_ci#include <linux/of.h> 1162306a36Sopenharmony_ci#include <linux/phy/phy.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* eUSB2 status registers */ 1462306a36Sopenharmony_ci#define EUSB2_RPTR_STATUS 0x08 1562306a36Sopenharmony_ci#define RPTR_OK BIT(7) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* eUSB2 control registers */ 1862306a36Sopenharmony_ci#define EUSB2_EN_CTL1 0x46 1962306a36Sopenharmony_ci#define EUSB2_RPTR_EN BIT(7) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define EUSB2_FORCE_EN_5 0xe8 2262306a36Sopenharmony_ci#define F_CLK_19P2M_EN BIT(6) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define EUSB2_FORCE_VAL_5 0xeD 2562306a36Sopenharmony_ci#define V_CLK_19P2M_EN BIT(6) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define EUSB2_TUNE_USB2_CROSSOVER 0x50 2862306a36Sopenharmony_ci#define EUSB2_TUNE_IUSB2 0x51 2962306a36Sopenharmony_ci#define EUSB2_TUNE_RES_FSDIF 0x52 3062306a36Sopenharmony_ci#define EUSB2_TUNE_HSDISC 0x53 3162306a36Sopenharmony_ci#define EUSB2_TUNE_SQUELCH_U 0x54 3262306a36Sopenharmony_ci#define EUSB2_TUNE_USB2_SLEW 0x55 3362306a36Sopenharmony_ci#define EUSB2_TUNE_USB2_EQU 0x56 3462306a36Sopenharmony_ci#define EUSB2_TUNE_USB2_PREEM 0x57 3562306a36Sopenharmony_ci#define EUSB2_TUNE_USB2_HS_COMP_CUR 0x58 3662306a36Sopenharmony_ci#define EUSB2_TUNE_EUSB_SLEW 0x59 3762306a36Sopenharmony_ci#define EUSB2_TUNE_EUSB_EQU 0x5A 3862306a36Sopenharmony_ci#define EUSB2_TUNE_EUSB_HS_COMP_CUR 0x5B 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define QCOM_EUSB2_REPEATER_INIT_CFG(r, v) \ 4162306a36Sopenharmony_ci { \ 4262306a36Sopenharmony_ci .reg = r, \ 4362306a36Sopenharmony_ci .val = v, \ 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cienum reg_fields { 4762306a36Sopenharmony_ci F_TUNE_EUSB_HS_COMP_CUR, 4862306a36Sopenharmony_ci F_TUNE_EUSB_EQU, 4962306a36Sopenharmony_ci F_TUNE_EUSB_SLEW, 5062306a36Sopenharmony_ci F_TUNE_USB2_HS_COMP_CUR, 5162306a36Sopenharmony_ci F_TUNE_USB2_PREEM, 5262306a36Sopenharmony_ci F_TUNE_USB2_EQU, 5362306a36Sopenharmony_ci F_TUNE_USB2_SLEW, 5462306a36Sopenharmony_ci F_TUNE_SQUELCH_U, 5562306a36Sopenharmony_ci F_TUNE_HSDISC, 5662306a36Sopenharmony_ci F_TUNE_RES_FSDIF, 5762306a36Sopenharmony_ci F_TUNE_IUSB2, 5862306a36Sopenharmony_ci F_TUNE_USB2_CROSSOVER, 5962306a36Sopenharmony_ci F_NUM_TUNE_FIELDS, 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci F_FORCE_VAL_5 = F_NUM_TUNE_FIELDS, 6262306a36Sopenharmony_ci F_FORCE_EN_5, 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci F_EN_CTL1, 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci F_RPTR_STATUS, 6762306a36Sopenharmony_ci F_NUM_FIELDS, 6862306a36Sopenharmony_ci}; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct reg_field eusb2_repeater_tune_reg_fields[F_NUM_FIELDS] = { 7162306a36Sopenharmony_ci [F_TUNE_EUSB_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_EUSB_HS_COMP_CUR, 0, 1), 7262306a36Sopenharmony_ci [F_TUNE_EUSB_EQU] = REG_FIELD(EUSB2_TUNE_EUSB_EQU, 0, 1), 7362306a36Sopenharmony_ci [F_TUNE_EUSB_SLEW] = REG_FIELD(EUSB2_TUNE_EUSB_SLEW, 0, 1), 7462306a36Sopenharmony_ci [F_TUNE_USB2_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_USB2_HS_COMP_CUR, 0, 1), 7562306a36Sopenharmony_ci [F_TUNE_USB2_PREEM] = REG_FIELD(EUSB2_TUNE_USB2_PREEM, 0, 2), 7662306a36Sopenharmony_ci [F_TUNE_USB2_EQU] = REG_FIELD(EUSB2_TUNE_USB2_EQU, 0, 1), 7762306a36Sopenharmony_ci [F_TUNE_USB2_SLEW] = REG_FIELD(EUSB2_TUNE_USB2_SLEW, 0, 1), 7862306a36Sopenharmony_ci [F_TUNE_SQUELCH_U] = REG_FIELD(EUSB2_TUNE_SQUELCH_U, 0, 2), 7962306a36Sopenharmony_ci [F_TUNE_HSDISC] = REG_FIELD(EUSB2_TUNE_HSDISC, 0, 2), 8062306a36Sopenharmony_ci [F_TUNE_RES_FSDIF] = REG_FIELD(EUSB2_TUNE_RES_FSDIF, 0, 2), 8162306a36Sopenharmony_ci [F_TUNE_IUSB2] = REG_FIELD(EUSB2_TUNE_IUSB2, 0, 3), 8262306a36Sopenharmony_ci [F_TUNE_USB2_CROSSOVER] = REG_FIELD(EUSB2_TUNE_USB2_CROSSOVER, 0, 2), 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci [F_FORCE_VAL_5] = REG_FIELD(EUSB2_FORCE_VAL_5, 0, 7), 8562306a36Sopenharmony_ci [F_FORCE_EN_5] = REG_FIELD(EUSB2_FORCE_EN_5, 0, 7), 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci [F_EN_CTL1] = REG_FIELD(EUSB2_EN_CTL1, 0, 7), 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci [F_RPTR_STATUS] = REG_FIELD(EUSB2_RPTR_STATUS, 0, 7), 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct eusb2_repeater_cfg { 9362306a36Sopenharmony_ci const u32 *init_tbl; 9462306a36Sopenharmony_ci int init_tbl_num; 9562306a36Sopenharmony_ci const char * const *vreg_list; 9662306a36Sopenharmony_ci int num_vregs; 9762306a36Sopenharmony_ci}; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistruct eusb2_repeater { 10062306a36Sopenharmony_ci struct device *dev; 10162306a36Sopenharmony_ci struct regmap_field *regs[F_NUM_FIELDS]; 10262306a36Sopenharmony_ci struct phy *phy; 10362306a36Sopenharmony_ci struct regulator_bulk_data *vregs; 10462306a36Sopenharmony_ci const struct eusb2_repeater_cfg *cfg; 10562306a36Sopenharmony_ci enum phy_mode mode; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const char * const pm8550b_vreg_l[] = { 10962306a36Sopenharmony_ci "vdd18", "vdd3", 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic const u32 pm8550b_init_tbl[F_NUM_TUNE_FIELDS] = { 11362306a36Sopenharmony_ci [F_TUNE_IUSB2] = 0x8, 11462306a36Sopenharmony_ci [F_TUNE_SQUELCH_U] = 0x3, 11562306a36Sopenharmony_ci [F_TUNE_USB2_PREEM] = 0x5, 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { 11962306a36Sopenharmony_ci .init_tbl = pm8550b_init_tbl, 12062306a36Sopenharmony_ci .init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl), 12162306a36Sopenharmony_ci .vreg_list = pm8550b_vreg_l, 12262306a36Sopenharmony_ci .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci int num = rptr->cfg->num_vregs; 12862306a36Sopenharmony_ci struct device *dev = rptr->dev; 12962306a36Sopenharmony_ci int i; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci rptr->vregs = devm_kcalloc(dev, num, sizeof(*rptr->vregs), GFP_KERNEL); 13262306a36Sopenharmony_ci if (!rptr->vregs) 13362306a36Sopenharmony_ci return -ENOMEM; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci for (i = 0; i < num; i++) 13662306a36Sopenharmony_ci rptr->vregs[i].supply = rptr->cfg->vreg_list[i]; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return devm_regulator_bulk_get(dev, num, rptr->vregs); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int eusb2_repeater_init(struct phy *phy) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct reg_field *regfields = eusb2_repeater_tune_reg_fields; 14462306a36Sopenharmony_ci struct eusb2_repeater *rptr = phy_get_drvdata(phy); 14562306a36Sopenharmony_ci const u32 *init_tbl = rptr->cfg->init_tbl; 14662306a36Sopenharmony_ci u32 val; 14762306a36Sopenharmony_ci int ret; 14862306a36Sopenharmony_ci int i; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs); 15162306a36Sopenharmony_ci if (ret) 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[F_EN_CTL1], EUSB2_RPTR_EN, EUSB2_RPTR_EN); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; i < F_NUM_TUNE_FIELDS; i++) { 15762306a36Sopenharmony_ci if (init_tbl[i]) { 15862306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]); 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci /* Write 0 if there's no value set */ 16162306a36Sopenharmony_ci u32 mask = GENMASK(regfields[i].msb, regfields[i].lsb); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[i], mask, 0); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = regmap_field_read_poll_timeout(rptr->regs[F_RPTR_STATUS], 16862306a36Sopenharmony_ci val, val & RPTR_OK, 10, 5); 16962306a36Sopenharmony_ci if (ret) 17062306a36Sopenharmony_ci dev_err(rptr->dev, "initialization timed-out\n"); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int eusb2_repeater_set_mode(struct phy *phy, 17662306a36Sopenharmony_ci enum phy_mode mode, int submode) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct eusb2_repeater *rptr = phy_get_drvdata(phy); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci switch (mode) { 18162306a36Sopenharmony_ci case PHY_MODE_USB_HOST: 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * CM.Lx is prohibited when repeater is already into Lx state as 18462306a36Sopenharmony_ci * per eUSB 1.2 Spec. Below implement software workaround until 18562306a36Sopenharmony_ci * PHY and controller is fixing seen observation. 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[F_FORCE_EN_5], 18862306a36Sopenharmony_ci F_CLK_19P2M_EN, F_CLK_19P2M_EN); 18962306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5], 19062306a36Sopenharmony_ci V_CLK_19P2M_EN, V_CLK_19P2M_EN); 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci case PHY_MODE_USB_DEVICE: 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * In device mode clear host mode related workaround as there 19562306a36Sopenharmony_ci * is no repeater reset available, and enable/disable of 19662306a36Sopenharmony_ci * repeater doesn't clear previous value due to shared 19762306a36Sopenharmony_ci * regulators (say host <-> device mode switch). 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[F_FORCE_EN_5], 20062306a36Sopenharmony_ci F_CLK_19P2M_EN, 0); 20162306a36Sopenharmony_ci regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5], 20262306a36Sopenharmony_ci V_CLK_19P2M_EN, 0); 20362306a36Sopenharmony_ci break; 20462306a36Sopenharmony_ci default: 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic int eusb2_repeater_exit(struct phy *phy) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct eusb2_repeater *rptr = phy_get_drvdata(phy); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return regulator_bulk_disable(rptr->cfg->num_vregs, rptr->vregs); 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic const struct phy_ops eusb2_repeater_ops = { 21962306a36Sopenharmony_ci .init = eusb2_repeater_init, 22062306a36Sopenharmony_ci .exit = eusb2_repeater_exit, 22162306a36Sopenharmony_ci .set_mode = eusb2_repeater_set_mode, 22262306a36Sopenharmony_ci .owner = THIS_MODULE, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int eusb2_repeater_probe(struct platform_device *pdev) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci struct eusb2_repeater *rptr; 22862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 22962306a36Sopenharmony_ci struct phy_provider *phy_provider; 23062306a36Sopenharmony_ci struct device_node *np = dev->of_node; 23162306a36Sopenharmony_ci struct regmap *regmap; 23262306a36Sopenharmony_ci int i, ret; 23362306a36Sopenharmony_ci u32 res; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL); 23662306a36Sopenharmony_ci if (!rptr) 23762306a36Sopenharmony_ci return -ENOMEM; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci rptr->dev = dev; 24062306a36Sopenharmony_ci dev_set_drvdata(dev, rptr); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci rptr->cfg = of_device_get_match_data(dev); 24362306a36Sopenharmony_ci if (!rptr->cfg) 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci regmap = dev_get_regmap(dev->parent, NULL); 24762306a36Sopenharmony_ci if (!regmap) 24862306a36Sopenharmony_ci return -ENODEV; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ret = of_property_read_u32(np, "reg", &res); 25162306a36Sopenharmony_ci if (ret < 0) 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci for (i = 0; i < F_NUM_FIELDS; i++) 25562306a36Sopenharmony_ci eusb2_repeater_tune_reg_fields[i].reg += res; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = devm_regmap_field_bulk_alloc(dev, regmap, rptr->regs, 25862306a36Sopenharmony_ci eusb2_repeater_tune_reg_fields, 25962306a36Sopenharmony_ci F_NUM_FIELDS); 26062306a36Sopenharmony_ci if (ret) 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci ret = eusb2_repeater_init_vregs(rptr); 26462306a36Sopenharmony_ci if (ret < 0) { 26562306a36Sopenharmony_ci dev_err(dev, "unable to get supplies\n"); 26662306a36Sopenharmony_ci return ret; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci rptr->phy = devm_phy_create(dev, np, &eusb2_repeater_ops); 27062306a36Sopenharmony_ci if (IS_ERR(rptr->phy)) { 27162306a36Sopenharmony_ci dev_err(dev, "failed to create PHY: %d\n", ret); 27262306a36Sopenharmony_ci return PTR_ERR(rptr->phy); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci phy_set_drvdata(rptr->phy, rptr); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 27862306a36Sopenharmony_ci if (IS_ERR(phy_provider)) 27962306a36Sopenharmony_ci return PTR_ERR(phy_provider); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci dev_info(dev, "Registered Qcom-eUSB2 repeater\n"); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void eusb2_repeater_remove(struct platform_device *pdev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct eusb2_repeater *rptr = platform_get_drvdata(pdev); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!rptr) 29162306a36Sopenharmony_ci return; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci eusb2_repeater_exit(rptr->phy); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic const struct of_device_id eusb2_repeater_of_match_table[] = { 29762306a36Sopenharmony_ci { 29862306a36Sopenharmony_ci .compatible = "qcom,pm8550b-eusb2-repeater", 29962306a36Sopenharmony_ci .data = &pm8550b_eusb2_cfg, 30062306a36Sopenharmony_ci }, 30162306a36Sopenharmony_ci { }, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic struct platform_driver eusb2_repeater_driver = { 30662306a36Sopenharmony_ci .probe = eusb2_repeater_probe, 30762306a36Sopenharmony_ci .remove_new = eusb2_repeater_remove, 30862306a36Sopenharmony_ci .driver = { 30962306a36Sopenharmony_ci .name = "qcom-eusb2-repeater", 31062306a36Sopenharmony_ci .of_match_table = eusb2_repeater_of_match_table, 31162306a36Sopenharmony_ci }, 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cimodule_platform_driver(eusb2_repeater_driver); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm PMIC eUSB2 Repeater driver"); 31762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 318