Some Qualcomm PMICs integrate an USB Repeater device, used to
convert between eUSB2 and USB 2.0 signaling levels, reachable
in a specific address range over SPMI.
Instead of using the parent SPMI device (the main PMIC) as a kind
of syscon in this driver, register a new SPMI sub-device for EUSB2
and initialize its own regmap with this sub-device's specific base
address, retrieved from the devicetree.
This allows to stop manually adding the register base address to
every R/W call in this driver, as this can be, and is now, handled
by the regmap API instead.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../phy/qualcomm/phy-qcom-eusb2-repeater.c | 51 ++++++++++++-------
1 file changed, 33 insertions(+), 18 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
index e0f2acc8109c..50eeebfb51a9 100644
--- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
+++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
@@ -9,6 +9,7 @@
#include <linux/regmap.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
+#include <linux/spmi.h>
/* eUSB2 status registers */
#define EUSB2_RPTR_STATUS 0x08
@@ -55,7 +56,6 @@ struct eusb2_repeater {
struct phy *phy;
struct regulator_bulk_data *vregs;
const struct eusb2_repeater_cfg *cfg;
- u32 base;
enum phy_mode mode;
};
@@ -110,7 +110,6 @@ static int eusb2_repeater_init(struct phy *phy)
struct eusb2_repeater *rptr = phy_get_drvdata(phy);
struct device_node *np = rptr->dev->of_node;
struct regmap *regmap = rptr->regmap;
- u32 base = rptr->base;
u32 poll_val;
int ret;
u8 val;
@@ -119,25 +118,25 @@ static int eusb2_repeater_init(struct phy *phy)
if (ret)
return ret;
- regmap_write(regmap, base + EUSB2_EN_CTL1, EUSB2_RPTR_EN);
+ regmap_write(regmap, EUSB2_EN_CTL1, EUSB2_RPTR_EN);
/* Write registers from init table */
for (int i = 0; i < rptr->cfg->init_tbl_num; i++)
- regmap_write(regmap, base + rptr->cfg->init_tbl[i].reg,
+ regmap_write(regmap, rptr->cfg->init_tbl[i].reg,
rptr->cfg->init_tbl[i].value);
/* Override registers from devicetree values */
if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &val))
- regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, val);
+ regmap_write(regmap, EUSB2_TUNE_USB2_PREEM, val);
if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &val))
- regmap_write(regmap, base + EUSB2_TUNE_HSDISC, val);
+ regmap_write(regmap, EUSB2_TUNE_HSDISC, val);
if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &val))
- regmap_write(regmap, base + EUSB2_TUNE_IUSB2, val);
+ regmap_write(regmap, EUSB2_TUNE_IUSB2, val);
/* Wait for status OK */
- ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, poll_val,
+ ret = regmap_read_poll_timeout(regmap, EUSB2_RPTR_STATUS, poll_val,
poll_val & RPTR_OK, 10, 5);
if (ret)
dev_err(rptr->dev, "initialization timed-out\n");
@@ -150,7 +149,6 @@ static int eusb2_repeater_set_mode(struct phy *phy,
{
struct eusb2_repeater *rptr = phy_get_drvdata(phy);
struct regmap *regmap = rptr->regmap;
- u32 base = rptr->base;
switch (mode) {
case PHY_MODE_USB_HOST:
@@ -159,8 +157,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
* per eUSB 1.2 Spec. Below implement software workaround until
* PHY and controller is fixing seen observation.
*/
- regmap_write(regmap, base + EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
- regmap_write(regmap, base + EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
+ regmap_write(regmap, EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
+ regmap_write(regmap, EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
break;
case PHY_MODE_USB_DEVICE:
/*
@@ -169,8 +167,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
* repeater doesn't clear previous value due to shared
* regulators (say host <-> device mode switch).
*/
- regmap_write(regmap, base + EUSB2_FORCE_EN_5, 0);
- regmap_write(regmap, base + EUSB2_FORCE_VAL_5, 0);
+ regmap_write(regmap, EUSB2_FORCE_EN_5, 0);
+ regmap_write(regmap, EUSB2_FORCE_VAL_5, 0);
break;
default:
return -EINVAL;
@@ -195,13 +193,23 @@ static const struct phy_ops eusb2_repeater_ops = {
static int eusb2_repeater_probe(struct platform_device *pdev)
{
+ struct regmap_config eusb2_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .max_register = 0x100,
+ .fast_io = true,
+ };
+ struct spmi_device *sparent;
struct eusb2_repeater *rptr;
+ struct spmi_subdevice *sub_sdev;
struct device *dev = &pdev->dev;
struct phy_provider *phy_provider;
struct device_node *np = dev->of_node;
- u32 res;
int ret;
+ if (!dev->parent)
+ return -ENODEV;
+
rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
if (!rptr)
return -ENOMEM;
@@ -213,15 +221,21 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
if (!rptr->cfg)
return -EINVAL;
- rptr->regmap = dev_get_regmap(dev->parent, NULL);
- if (!rptr->regmap)
+ sparent = to_spmi_device(dev->parent);
+ if (!sparent)
return -ENODEV;
- ret = of_property_read_u32(np, "reg", &res);
+ sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent);
+ if (IS_ERR(sub_sdev))
+ return PTR_ERR(sub_sdev);
+
+ ret = of_property_read_u32(np, "reg", &eusb2_regmap_config.reg_base);
if (ret < 0)
return ret;
- rptr->base = res;
+ rptr->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &eusb2_regmap_config);
+ if (IS_ERR(rptr->regmap))
+ return -ENODEV;
ret = eusb2_repeater_init_vregs(rptr);
if (ret < 0) {
@@ -280,3 +294,4 @@ module_platform_driver(eusb2_repeater_driver);
MODULE_DESCRIPTION("Qualcomm PMIC eUSB2 Repeater driver");
MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SPMI");
--
2.50.1
Hi AngeloGioacchino, kernel test robot noticed the following build errors: [auto build test ERROR on next-20250722] [cannot apply to jic23-iio/togreg sre-power-supply/for-next char-misc/char-misc-testing char-misc/char-misc-next char-misc/char-misc-linus linus/master v6.16-rc7 v6.16-rc6 v6.16-rc5 v6.16-rc7] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/AngeloGioacchino-Del-Regno/spmi-Implement-spmi_subdevice_alloc_and_add-and-devm-variant/20250722-181911 base: next-20250722 patch link: https://lore.kernel.org/r/20250722101317.76729-5-angelogioacchino.delregno%40collabora.com patch subject: [PATCH v2 4/7] phy: qualcomm: eusb2-repeater: Migrate to devm_spmi_subdevice_alloc_and_add() config: sparc-randconfig-001-20250723 (https://download.01.org/0day-ci/archive/20250723/202507231743.Z1ToUg4r-lkp@intel.com/config) compiler: sparc-linux-gcc (GCC) 8.5.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250723/202507231743.Z1ToUg4r-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202507231743.Z1ToUg4r-lkp@intel.com/ All errors (new ones prefixed by >>): sparc-linux-ld: drivers/phy/qualcomm/phy-qcom-eusb2-repeater.o: in function `eusb2_repeater_probe': >> drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c:228: undefined reference to `devm_spmi_subdevice_alloc_and_add' >> sparc-linux-ld: drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c:236: undefined reference to `__devm_regmap_init_spmi_ext' vim +228 drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c 193 194 static int eusb2_repeater_probe(struct platform_device *pdev) 195 { 196 struct regmap_config eusb2_regmap_config = { 197 .reg_bits = 16, 198 .val_bits = 8, 199 .max_register = 0x100, 200 .fast_io = true, 201 }; 202 struct spmi_device *sparent; 203 struct eusb2_repeater *rptr; 204 struct spmi_subdevice *sub_sdev; 205 struct device *dev = &pdev->dev; 206 struct phy_provider *phy_provider; 207 struct device_node *np = dev->of_node; 208 int ret; 209 210 if (!dev->parent) 211 return -ENODEV; 212 213 rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL); 214 if (!rptr) 215 return -ENOMEM; 216 217 rptr->dev = dev; 218 dev_set_drvdata(dev, rptr); 219 220 rptr->cfg = of_device_get_match_data(dev); 221 if (!rptr->cfg) 222 return -EINVAL; 223 224 sparent = to_spmi_device(dev->parent); 225 if (!sparent) 226 return -ENODEV; 227 > 228 sub_sdev = devm_spmi_subdevice_alloc_and_add(dev, sparent); 229 if (IS_ERR(sub_sdev)) 230 return PTR_ERR(sub_sdev); 231 232 ret = of_property_read_u32(np, "reg", &eusb2_regmap_config.reg_base); 233 if (ret < 0) 234 return ret; 235 > 236 rptr->regmap = devm_regmap_init_spmi_ext(&sub_sdev->sdev, &eusb2_regmap_config); 237 if (IS_ERR(rptr->regmap)) 238 return -ENODEV; 239 240 ret = eusb2_repeater_init_vregs(rptr); 241 if (ret < 0) { 242 dev_err(dev, "unable to get supplies\n"); 243 return ret; 244 } 245 246 rptr->phy = devm_phy_create(dev, np, &eusb2_repeater_ops); 247 if (IS_ERR(rptr->phy)) { 248 dev_err(dev, "failed to create PHY: %d\n", ret); 249 return PTR_ERR(rptr->phy); 250 } 251 252 phy_set_drvdata(rptr->phy, rptr); 253 254 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 255 if (IS_ERR(phy_provider)) 256 return PTR_ERR(phy_provider); 257 258 return 0; 259 } 260 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.