diff options
Diffstat (limited to 'drivers/phy/phy-can-transceiver.c')
| -rw-r--r-- | drivers/phy/phy-can-transceiver.c | 158 |
1 files changed, 117 insertions, 41 deletions
diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c index f59caff4b3d4..330356706ad7 100644 --- a/drivers/phy/phy-can-transceiver.c +++ b/drivers/phy/phy-can-transceiver.c @@ -17,32 +17,41 @@ 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) +#define CAN_TRANSCEIVER_SILENT_PRESENT BIT(3) }; struct can_transceiver_phy { struct phy *generic_phy; + struct gpio_desc *silent_gpio; struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; + struct can_transceiver_priv *priv; +}; + +struct can_transceiver_priv { struct mux_state *mux_state; + int num_ch; + struct can_transceiver_phy can_transceiver_phy[] __counted_by(num_ch); }; /* Power on function */ static int can_transceiver_phy_power_on(struct phy *phy) { struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); + struct can_transceiver_priv *priv = can_transceiver_phy->priv; int ret; - if (can_transceiver_phy->mux_state) { - ret = mux_state_select(can_transceiver_phy->mux_state); + if (priv->mux_state) { + ret = mux_state_select(priv->mux_state); if (ret) { dev_err(&phy->dev, "Failed to select CAN mux: %d\n", ret); return ret; } } - if (can_transceiver_phy->standby_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); - if (can_transceiver_phy->enable_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 0); + gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); + gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1); return 0; } @@ -51,13 +60,13 @@ static int can_transceiver_phy_power_on(struct phy *phy) static int can_transceiver_phy_power_off(struct phy *phy) { struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); + struct can_transceiver_priv *priv = can_transceiver_phy->priv; - if (can_transceiver_phy->standby_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); - if (can_transceiver_phy->enable_gpio) - gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); - if (can_transceiver_phy->mux_state) - mux_state_deselect(can_transceiver_phy->mux_state); + gpiod_set_value_cansleep(can_transceiver_phy->silent_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); + gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); + if (priv->mux_state) + mux_state_deselect(priv->mux_state); return 0; } @@ -76,6 +85,18 @@ 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 can_transceiver_data tja1051_drvdata = { + .flags = CAN_TRANSCEIVER_SILENT_PRESENT | CAN_TRANSCEIVER_EN_PRESENT, +}; + +static const struct can_transceiver_data tja1057_drvdata = { + .flags = CAN_TRANSCEIVER_SILENT_PRESENT, +}; + static const struct of_device_id can_transceiver_phy_ids[] = { { .compatible = "ti,tcan1042", @@ -86,6 +107,18 @@ static const struct of_device_id can_transceiver_phy_ids[] = { .data = &tcan1043_drvdata }, { + .compatible = "nxp,tja1048", + .data = &tja1048_drvdata + }, + { + .compatible = "nxp,tja1051", + .data = &tja1051_drvdata + }, + { + .compatible = "nxp,tja1057", + .data = &tja1057_drvdata + }, + { .compatible = "nxp,tjr1443", .data = &tcan1043_drvdata }, @@ -103,64 +136,107 @@ 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; struct device *dev = &pdev->dev; struct can_transceiver_phy *can_transceiver_phy; + struct can_transceiver_priv *priv; const struct can_transceiver_data *drvdata; const struct of_device_id *match; struct phy *phy; + struct gpio_desc *silent_gpio; struct gpio_desc *standby_gpio; struct gpio_desc *enable_gpio; struct mux_state *mux_state; u32 max_bitrate = 0; - int err; - - can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL); - if (!can_transceiver_phy) - return -ENOMEM; + 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) + return -ENOMEM; + + priv->num_ch = num_ch; + platform_set_drvdata(pdev, priv); mux_state = devm_mux_state_get_optional(dev, NULL); if (IS_ERR(mux_state)) return PTR_ERR(mux_state); - can_transceiver_phy->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); - } + priv->mux_state = mux_state; 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; + + 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; + } + + if (drvdata->flags & CAN_TRANSCEIVER_SILENT_PRESENT) { + silent_gpio = devm_gpiod_get_index_optional(dev, "silent", i, + GPIOD_OUT_LOW); + if (IS_ERR(silent_gpio)) + return PTR_ERR(silent_gpio); + can_transceiver_phy->silent_gpio = silent_gpio; + } - phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); + 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); } |
