156d77c9aSAbel Vesa // SPDX-License-Identifier: GPL-2.0 256d77c9aSAbel Vesa /* 356d77c9aSAbel Vesa * Copyright (c) 2023, Linaro Limited 456d77c9aSAbel Vesa */ 556d77c9aSAbel Vesa 656d77c9aSAbel Vesa #include <linux/module.h> 756d77c9aSAbel Vesa #include <linux/platform_device.h> 856d77c9aSAbel Vesa #include <linux/regulator/consumer.h> 956d77c9aSAbel Vesa #include <linux/regmap.h> 1056d77c9aSAbel Vesa #include <linux/of.h> 1156d77c9aSAbel Vesa #include <linux/of_device.h> 1256d77c9aSAbel Vesa #include <linux/phy/phy.h> 1356d77c9aSAbel Vesa 1456d77c9aSAbel Vesa /* eUSB2 status registers */ 1556d77c9aSAbel Vesa #define EUSB2_RPTR_STATUS 0x08 1656d77c9aSAbel Vesa #define RPTR_OK BIT(7) 1756d77c9aSAbel Vesa 1856d77c9aSAbel Vesa /* eUSB2 control registers */ 1956d77c9aSAbel Vesa #define EUSB2_EN_CTL1 0x46 2056d77c9aSAbel Vesa #define EUSB2_RPTR_EN BIT(7) 2156d77c9aSAbel Vesa 2256d77c9aSAbel Vesa #define EUSB2_FORCE_EN_5 0xe8 2356d77c9aSAbel Vesa #define F_CLK_19P2M_EN BIT(6) 2456d77c9aSAbel Vesa 2556d77c9aSAbel Vesa #define EUSB2_FORCE_VAL_5 0xeD 2656d77c9aSAbel Vesa #define V_CLK_19P2M_EN BIT(6) 2756d77c9aSAbel Vesa 2856d77c9aSAbel Vesa #define EUSB2_TUNE_IUSB2 0x51 2956d77c9aSAbel Vesa #define EUSB2_TUNE_SQUELCH_U 0x54 3056d77c9aSAbel Vesa #define EUSB2_TUNE_USB2_PREEM 0x57 3156d77c9aSAbel Vesa 3256d77c9aSAbel Vesa #define QCOM_EUSB2_REPEATER_INIT_CFG(o, v) \ 3356d77c9aSAbel Vesa { \ 3456d77c9aSAbel Vesa .offset = o, \ 3556d77c9aSAbel Vesa .val = v, \ 3656d77c9aSAbel Vesa } 3756d77c9aSAbel Vesa 3856d77c9aSAbel Vesa struct eusb2_repeater_init_tbl { 3956d77c9aSAbel Vesa unsigned int offset; 4056d77c9aSAbel Vesa unsigned int val; 4156d77c9aSAbel Vesa }; 4256d77c9aSAbel Vesa 4356d77c9aSAbel Vesa struct eusb2_repeater_cfg { 4456d77c9aSAbel Vesa const struct eusb2_repeater_init_tbl *init_tbl; 4556d77c9aSAbel Vesa int init_tbl_num; 4656d77c9aSAbel Vesa const char * const *vreg_list; 4756d77c9aSAbel Vesa int num_vregs; 4856d77c9aSAbel Vesa }; 4956d77c9aSAbel Vesa 5056d77c9aSAbel Vesa struct eusb2_repeater { 5156d77c9aSAbel Vesa struct device *dev; 5256d77c9aSAbel Vesa struct regmap *regmap; 5356d77c9aSAbel Vesa struct phy *phy; 5456d77c9aSAbel Vesa struct regulator_bulk_data *vregs; 5556d77c9aSAbel Vesa const struct eusb2_repeater_cfg *cfg; 5656d77c9aSAbel Vesa u16 base; 5756d77c9aSAbel Vesa enum phy_mode mode; 5856d77c9aSAbel Vesa }; 5956d77c9aSAbel Vesa 6056d77c9aSAbel Vesa static const char * const pm8550b_vreg_l[] = { 6156d77c9aSAbel Vesa "vdd18", "vdd3", 6256d77c9aSAbel Vesa }; 6356d77c9aSAbel Vesa 6456d77c9aSAbel Vesa static const struct eusb2_repeater_init_tbl pm8550b_init_tbl[] = { 6556d77c9aSAbel Vesa QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_IUSB2, 0x8), 6656d77c9aSAbel Vesa QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_SQUELCH_U, 0x3), 6756d77c9aSAbel Vesa QCOM_EUSB2_REPEATER_INIT_CFG(EUSB2_TUNE_USB2_PREEM, 0x5), 6856d77c9aSAbel Vesa }; 6956d77c9aSAbel Vesa 7056d77c9aSAbel Vesa static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { 7156d77c9aSAbel Vesa .init_tbl = pm8550b_init_tbl, 7256d77c9aSAbel Vesa .init_tbl_num = ARRAY_SIZE(pm8550b_init_tbl), 7356d77c9aSAbel Vesa .vreg_list = pm8550b_vreg_l, 7456d77c9aSAbel Vesa .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), 7556d77c9aSAbel Vesa }; 7656d77c9aSAbel Vesa 7756d77c9aSAbel Vesa static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr) 7856d77c9aSAbel Vesa { 7956d77c9aSAbel Vesa int num = rptr->cfg->num_vregs; 8056d77c9aSAbel Vesa struct device *dev = rptr->dev; 8156d77c9aSAbel Vesa int i; 8256d77c9aSAbel Vesa 8356d77c9aSAbel Vesa rptr->vregs = devm_kcalloc(dev, num, sizeof(*rptr->vregs), GFP_KERNEL); 8456d77c9aSAbel Vesa if (!rptr->vregs) 8556d77c9aSAbel Vesa return -ENOMEM; 8656d77c9aSAbel Vesa 8756d77c9aSAbel Vesa for (i = 0; i < num; i++) 8856d77c9aSAbel Vesa rptr->vregs[i].supply = rptr->cfg->vreg_list[i]; 8956d77c9aSAbel Vesa 9056d77c9aSAbel Vesa return devm_regulator_bulk_get(dev, num, rptr->vregs); 9156d77c9aSAbel Vesa } 9256d77c9aSAbel Vesa 9356d77c9aSAbel Vesa static int eusb2_repeater_init(struct phy *phy) 9456d77c9aSAbel Vesa { 9556d77c9aSAbel Vesa struct eusb2_repeater *rptr = phy_get_drvdata(phy); 9656d77c9aSAbel Vesa const struct eusb2_repeater_init_tbl *init_tbl = rptr->cfg->init_tbl; 9756d77c9aSAbel Vesa int num = rptr->cfg->init_tbl_num; 9856d77c9aSAbel Vesa u32 val; 9956d77c9aSAbel Vesa int ret; 10056d77c9aSAbel Vesa int i; 10156d77c9aSAbel Vesa 10256d77c9aSAbel Vesa ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs); 10356d77c9aSAbel Vesa if (ret) 10456d77c9aSAbel Vesa return ret; 10556d77c9aSAbel Vesa 10656d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, rptr->base + EUSB2_EN_CTL1, 10756d77c9aSAbel Vesa EUSB2_RPTR_EN, EUSB2_RPTR_EN); 10856d77c9aSAbel Vesa 10956d77c9aSAbel Vesa for (i = 0; i < num; i++) 11056d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, 11156d77c9aSAbel Vesa rptr->base + init_tbl[i].offset, 11256d77c9aSAbel Vesa init_tbl[i].val, init_tbl[i].val); 11356d77c9aSAbel Vesa 11456d77c9aSAbel Vesa ret = regmap_read_poll_timeout(rptr->regmap, 11556d77c9aSAbel Vesa rptr->base + EUSB2_RPTR_STATUS, val, 11656d77c9aSAbel Vesa val & RPTR_OK, 10, 5); 11756d77c9aSAbel Vesa if (ret) 11856d77c9aSAbel Vesa dev_err(rptr->dev, "initialization timed-out\n"); 11956d77c9aSAbel Vesa 12056d77c9aSAbel Vesa return ret; 12156d77c9aSAbel Vesa } 12256d77c9aSAbel Vesa 12356d77c9aSAbel Vesa static int eusb2_repeater_set_mode(struct phy *phy, 12456d77c9aSAbel Vesa enum phy_mode mode, int submode) 12556d77c9aSAbel Vesa { 12656d77c9aSAbel Vesa struct eusb2_repeater *rptr = phy_get_drvdata(phy); 12756d77c9aSAbel Vesa 12856d77c9aSAbel Vesa switch (mode) { 12956d77c9aSAbel Vesa case PHY_MODE_USB_HOST: 13056d77c9aSAbel Vesa /* 13156d77c9aSAbel Vesa * CM.Lx is prohibited when repeater is already into Lx state as 13256d77c9aSAbel Vesa * per eUSB 1.2 Spec. Below implement software workaround until 13356d77c9aSAbel Vesa * PHY and controller is fixing seen observation. 13456d77c9aSAbel Vesa */ 13556d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5, 13656d77c9aSAbel Vesa F_CLK_19P2M_EN, F_CLK_19P2M_EN); 13756d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5, 13856d77c9aSAbel Vesa V_CLK_19P2M_EN, V_CLK_19P2M_EN); 13956d77c9aSAbel Vesa break; 14056d77c9aSAbel Vesa case PHY_MODE_USB_DEVICE: 14156d77c9aSAbel Vesa /* 14256d77c9aSAbel Vesa * In device mode clear host mode related workaround as there 14356d77c9aSAbel Vesa * is no repeater reset available, and enable/disable of 14456d77c9aSAbel Vesa * repeater doesn't clear previous value due to shared 14556d77c9aSAbel Vesa * regulators (say host <-> device mode switch). 14656d77c9aSAbel Vesa */ 14756d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_EN_5, 14856d77c9aSAbel Vesa F_CLK_19P2M_EN, 0); 14956d77c9aSAbel Vesa regmap_update_bits(rptr->regmap, rptr->base + EUSB2_FORCE_VAL_5, 15056d77c9aSAbel Vesa V_CLK_19P2M_EN, 0); 15156d77c9aSAbel Vesa break; 15256d77c9aSAbel Vesa default: 15356d77c9aSAbel Vesa return -EINVAL; 15456d77c9aSAbel Vesa } 15556d77c9aSAbel Vesa 15656d77c9aSAbel Vesa return 0; 15756d77c9aSAbel Vesa } 15856d77c9aSAbel Vesa 15956d77c9aSAbel Vesa static int eusb2_repeater_exit(struct phy *phy) 16056d77c9aSAbel Vesa { 16156d77c9aSAbel Vesa struct eusb2_repeater *rptr = phy_get_drvdata(phy); 16256d77c9aSAbel Vesa 16356d77c9aSAbel Vesa return regulator_bulk_disable(rptr->cfg->num_vregs, rptr->vregs); 16456d77c9aSAbel Vesa } 16556d77c9aSAbel Vesa 16656d77c9aSAbel Vesa static const struct phy_ops eusb2_repeater_ops = { 16756d77c9aSAbel Vesa .init = eusb2_repeater_init, 16856d77c9aSAbel Vesa .exit = eusb2_repeater_exit, 16956d77c9aSAbel Vesa .set_mode = eusb2_repeater_set_mode, 17056d77c9aSAbel Vesa .owner = THIS_MODULE, 17156d77c9aSAbel Vesa }; 17256d77c9aSAbel Vesa 17356d77c9aSAbel Vesa static int eusb2_repeater_probe(struct platform_device *pdev) 17456d77c9aSAbel Vesa { 17556d77c9aSAbel Vesa struct eusb2_repeater *rptr; 17656d77c9aSAbel Vesa struct device *dev = &pdev->dev; 17756d77c9aSAbel Vesa struct phy_provider *phy_provider; 17856d77c9aSAbel Vesa struct device_node *np = dev->of_node; 17956d77c9aSAbel Vesa u32 res; 18056d77c9aSAbel Vesa int ret; 18156d77c9aSAbel Vesa 18256d77c9aSAbel Vesa rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL); 18356d77c9aSAbel Vesa if (!rptr) 18456d77c9aSAbel Vesa return -ENOMEM; 18556d77c9aSAbel Vesa 18656d77c9aSAbel Vesa rptr->dev = dev; 18756d77c9aSAbel Vesa dev_set_drvdata(dev, rptr); 18856d77c9aSAbel Vesa 18956d77c9aSAbel Vesa rptr->cfg = of_device_get_match_data(dev); 19056d77c9aSAbel Vesa if (!rptr->cfg) 19156d77c9aSAbel Vesa return -EINVAL; 19256d77c9aSAbel Vesa 19356d77c9aSAbel Vesa rptr->regmap = dev_get_regmap(dev->parent, NULL); 19456d77c9aSAbel Vesa if (!rptr->regmap) 19556d77c9aSAbel Vesa return -ENODEV; 19656d77c9aSAbel Vesa 19756d77c9aSAbel Vesa ret = of_property_read_u32(np, "reg", &res); 19856d77c9aSAbel Vesa if (ret < 0) 19956d77c9aSAbel Vesa return ret; 20056d77c9aSAbel Vesa 20156d77c9aSAbel Vesa rptr->base = res; 20256d77c9aSAbel Vesa 20356d77c9aSAbel Vesa ret = eusb2_repeater_init_vregs(rptr); 20456d77c9aSAbel Vesa if (ret < 0) { 20556d77c9aSAbel Vesa dev_err(dev, "unable to get supplies\n"); 20656d77c9aSAbel Vesa return ret; 20756d77c9aSAbel Vesa } 20856d77c9aSAbel Vesa 20956d77c9aSAbel Vesa rptr->phy = devm_phy_create(dev, np, &eusb2_repeater_ops); 21056d77c9aSAbel Vesa if (IS_ERR(rptr->phy)) { 21156d77c9aSAbel Vesa dev_err(dev, "failed to create PHY: %d\n", ret); 21256d77c9aSAbel Vesa return PTR_ERR(rptr->phy); 21356d77c9aSAbel Vesa } 21456d77c9aSAbel Vesa 21556d77c9aSAbel Vesa phy_set_drvdata(rptr->phy, rptr); 21656d77c9aSAbel Vesa 21756d77c9aSAbel Vesa phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 21856d77c9aSAbel Vesa if (IS_ERR(phy_provider)) 21956d77c9aSAbel Vesa return PTR_ERR(phy_provider); 22056d77c9aSAbel Vesa 22156d77c9aSAbel Vesa dev_info(dev, "Registered Qcom-eUSB2 repeater\n"); 22256d77c9aSAbel Vesa 22356d77c9aSAbel Vesa return 0; 22456d77c9aSAbel Vesa } 22556d77c9aSAbel Vesa 226*e5ce6d9dSUwe Kleine-König static void eusb2_repeater_remove(struct platform_device *pdev) 22756d77c9aSAbel Vesa { 22856d77c9aSAbel Vesa struct eusb2_repeater *rptr = platform_get_drvdata(pdev); 22956d77c9aSAbel Vesa 23056d77c9aSAbel Vesa if (!rptr) 231*e5ce6d9dSUwe Kleine-König return; 23256d77c9aSAbel Vesa 23356d77c9aSAbel Vesa eusb2_repeater_exit(rptr->phy); 23456d77c9aSAbel Vesa } 23556d77c9aSAbel Vesa 23656d77c9aSAbel Vesa static const struct of_device_id eusb2_repeater_of_match_table[] = { 23756d77c9aSAbel Vesa { 23856d77c9aSAbel Vesa .compatible = "qcom,pm8550b-eusb2-repeater", 23956d77c9aSAbel Vesa .data = &pm8550b_eusb2_cfg, 24056d77c9aSAbel Vesa }, 24156d77c9aSAbel Vesa { }, 24256d77c9aSAbel Vesa }; 24356d77c9aSAbel Vesa MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); 24456d77c9aSAbel Vesa 24556d77c9aSAbel Vesa static struct platform_driver eusb2_repeater_driver = { 24656d77c9aSAbel Vesa .probe = eusb2_repeater_probe, 247*e5ce6d9dSUwe Kleine-König .remove_new = eusb2_repeater_remove, 24856d77c9aSAbel Vesa .driver = { 24956d77c9aSAbel Vesa .name = "qcom-eusb2-repeater", 25056d77c9aSAbel Vesa .of_match_table = eusb2_repeater_of_match_table, 25156d77c9aSAbel Vesa }, 25256d77c9aSAbel Vesa }; 25356d77c9aSAbel Vesa 25456d77c9aSAbel Vesa module_platform_driver(eusb2_repeater_driver); 25556d77c9aSAbel Vesa 25656d77c9aSAbel Vesa MODULE_DESCRIPTION("Qualcomm PMIC eUSB2 Repeater driver"); 25756d77c9aSAbel Vesa MODULE_LICENSE("GPL"); 258