From: Peng Fan Date: Wed, 1 Oct 2025 13:22:34 +0000 (+0800) Subject: phy: phy-can-transceiver: Add dual channel support for TJA1048 X-Git-Tag: v6.19-rc1~55^2~33^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e9fe9409e10ed25b43928062832037752630979;p=thirdparty%2Fkernel%2Flinux.git phy: phy-can-transceiver: Add dual channel support for TJA1048 - Introduce new flag CAN_TRANSCEIVER_DUAL_CH to indicate the phy has two channels. - Alloc a phy for each channel - Support TJA1048 which is a dual high-speed CAN transceiver with sleep mode supported. - Add can_transceiver_phy_xlate for parsing phy Reviewed-by: Frank Li Signed-off-by: Peng Fan Acked-by: Marc Kleine-Budde Link: https://patch.msgid.link/20251001-can-v7-3-fad29efc3884@nxp.com Signed-off-by: Vinod Koul --- diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index b06ba42854c19..09d1684895568 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -17,6 +17,7 @@ struct can_transceiver_data { u32 flags; #define CAN_TRANSCEIVER_STB_PRESENT BIT(0) #define CAN_TRANSCEIVER_EN_PRESENT BIT(1) +#define CAN_TRANSCEIVER_DUAL_CH BIT(2) }; struct can_transceiver_phy { @@ -84,6 +85,10 @@ static const struct can_transceiver_data tcan1043_drvdata = { .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT, }; +static const struct can_transceiver_data tja1048_drvdata = { + .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_DUAL_CH, +}; + static const struct of_device_id can_transceiver_phy_ids[] = { { .compatible = "ti,tcan1042", @@ -93,6 +98,10 @@ static const struct of_device_id can_transceiver_phy_ids[] = { .compatible = "ti,tcan1043", .data = &tcan1043_drvdata }, + { + .compatible = "nxp,tja1048", + .data = &tja1048_drvdata + }, { .compatible = "nxp,tjr1443", .data = &tcan1043_drvdata @@ -111,6 +120,25 @@ devm_mux_state_get_optional(struct device *dev, const char *mux_name) return devm_mux_state_get(dev, mux_name); } +static struct phy *can_transceiver_phy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct can_transceiver_priv *priv = dev_get_drvdata(dev); + u32 idx; + + if (priv->num_ch == 1) + return priv->can_transceiver_phy[0].generic_phy; + + if (args->args_count != 1) + return ERR_PTR(-EINVAL); + + idx = args->args[0]; + if (idx >= priv->num_ch) + return ERR_PTR(-EINVAL); + + return priv->can_transceiver_phy[idx].generic_phy; +} + static int can_transceiver_phy_probe(struct platform_device *pdev) { struct phy_provider *phy_provider; @@ -124,10 +152,12 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) struct gpio_desc *enable_gpio; struct mux_state *mux_state; u32 max_bitrate = 0; - int err, num_ch = 1; + int err, i, num_ch = 1; match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node); drvdata = match->data; + if (drvdata->flags & CAN_TRANSCEIVER_DUAL_CH) + num_ch = 2; priv = devm_kzalloc(dev, struct_size(priv, can_transceiver_phy, num_ch), GFP_KERNEL); if (!priv) @@ -135,8 +165,6 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) priv->num_ch = num_ch; platform_set_drvdata(pdev, priv); - can_transceiver_phy = &priv->can_transceiver_phy[0]; - can_transceiver_phy->priv = priv; mux_state = devm_mux_state_get_optional(dev, NULL); if (IS_ERR(mux_state)) @@ -144,37 +172,45 @@ static int can_transceiver_phy_probe(struct platform_device *pdev) priv->mux_state = mux_state; - phy = devm_phy_create(dev, dev->of_node, - &can_transceiver_phy_ops); - if (IS_ERR(phy)) { - dev_err(dev, "failed to create can transceiver phy\n"); - return PTR_ERR(phy); - } - err = device_property_read_u32(dev, "max-bitrate", &max_bitrate); if ((err != -EINVAL) && !max_bitrate) dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); - phy->attrs.max_link_rate = max_bitrate; - can_transceiver_phy->generic_phy = phy; + for (i = 0; i < num_ch; i++) { + can_transceiver_phy = &priv->can_transceiver_phy[i]; + can_transceiver_phy->priv = priv; - if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) { - standby_gpio = devm_gpiod_get_optional(dev, "standby", GPIOD_OUT_HIGH); - if (IS_ERR(standby_gpio)) - return PTR_ERR(standby_gpio); - can_transceiver_phy->standby_gpio = standby_gpio; - } + phy = devm_phy_create(dev, dev->of_node, &can_transceiver_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create can transceiver phy\n"); + return PTR_ERR(phy); + } - if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) { - enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); - if (IS_ERR(enable_gpio)) - return PTR_ERR(enable_gpio); - can_transceiver_phy->enable_gpio = enable_gpio; - } + phy->attrs.max_link_rate = max_bitrate; + + can_transceiver_phy->generic_phy = phy; + can_transceiver_phy->priv = priv; - phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); + if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) { + standby_gpio = devm_gpiod_get_index_optional(dev, "standby", i, + GPIOD_OUT_HIGH); + if (IS_ERR(standby_gpio)) + return PTR_ERR(standby_gpio); + can_transceiver_phy->standby_gpio = standby_gpio; + } + + if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) { + enable_gpio = devm_gpiod_get_index_optional(dev, "enable", i, + GPIOD_OUT_LOW); + if (IS_ERR(enable_gpio)) + return PTR_ERR(enable_gpio); + can_transceiver_phy->enable_gpio = enable_gpio; + } + + phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); + } - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + phy_provider = devm_of_phy_provider_register(dev, can_transceiver_phy_xlate); return PTR_ERR_OR_ZERO(phy_provider); }