phy: phy-can-transceiver: Add support for setting mux
authorAswath Govindraju <a-govindraju@ti.com>
Fri, 8 Apr 2022 11:13:16 +0000 (16:43 +0530)
committerVinod Koul <vkoul@kernel.org>
Mon, 11 Apr 2022 14:44:10 +0000 (20:14 +0530)
On some boards, for routing CAN signals from controller to transceiver,
muxes might need to be set. Therefore, add support for setting the mux by
reading the mux-states property from the device tree node.

Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
Link: https://lore.kernel.org/r/20220408111316.21189-1-a-govindraju@ti.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/phy/Kconfig
drivers/phy/phy-can-transceiver.c

index 82b63e60c5a226bded68c9fe4a0c469c4049e63f..300b0f2b5f8421e587f05ea1449ec358e013ad0f 100644 (file)
@@ -64,6 +64,7 @@ config USB_LGM_PHY
 config PHY_CAN_TRANSCEIVER
        tristate "CAN transceiver PHY"
        select GENERIC_PHY
+       select MULTIPLEXER
        help
          This option enables support for CAN transceivers as a PHY. This
          driver provides function for putting the transceivers in various
index 6f3fe37dee0e85f3b0c87188ada8417a18f183c6..95c6dbb52da720bffcba85ff9ad037daed688009 100644 (file)
@@ -10,6 +10,7 @@
 #include<linux/module.h>
 #include<linux/gpio.h>
 #include<linux/gpio/consumer.h>
+#include <linux/mux/consumer.h>
 
 struct can_transceiver_data {
        u32 flags;
@@ -21,13 +22,22 @@ struct can_transceiver_phy {
        struct phy *generic_phy;
        struct gpio_desc *standby_gpio;
        struct gpio_desc *enable_gpio;
+       struct mux_state *mux_state;
 };
 
 /* Power on function */
 static int can_transceiver_phy_power_on(struct phy *phy)
 {
        struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy);
-
+       int ret;
+
+       if (can_transceiver_phy->mux_state) {
+               ret = mux_state_select(can_transceiver_phy->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)
@@ -45,6 +55,8 @@ static int can_transceiver_phy_power_off(struct phy *phy)
                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);
 
        return 0;
 }
@@ -95,6 +107,16 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
        match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
        drvdata = match->data;
 
+       if (of_property_read_bool(dev->of_node, "mux-states")) {
+               struct mux_state *mux_state;
+
+               mux_state = devm_mux_state_get(dev, NULL);
+               if (IS_ERR(mux_state))
+                       return dev_err_probe(&pdev->dev, PTR_ERR(mux_state),
+                                            "failed to get mux\n");
+               can_transceiver_phy->mux_state = mux_state;
+       }
+
        phy = devm_phy_create(dev, dev->of_node,
                              &can_transceiver_phy_ops);
        if (IS_ERR(phy)) {