1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * phy-can-transceiver.c - phy driver for CAN transceivers 4 * 5 * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com 6 * 7 */ 8 #include<linux/phy/phy.h> 9 #include<linux/platform_device.h> 10 #include<linux/module.h> 11 #include<linux/gpio.h> 12 #include<linux/gpio/consumer.h> 13 14 struct can_transceiver_data { 15 u32 flags; 16 #define CAN_TRANSCEIVER_STB_PRESENT BIT(0) 17 #define CAN_TRANSCEIVER_EN_PRESENT BIT(1) 18 }; 19 20 struct can_transceiver_phy { 21 struct phy *generic_phy; 22 struct gpio_desc *standby_gpio; 23 struct gpio_desc *enable_gpio; 24 }; 25 26 /* Power on function */ 27 static int can_transceiver_phy_power_on(struct phy *phy) 28 { 29 struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); 30 31 if (can_transceiver_phy->standby_gpio) 32 gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 0); 33 if (can_transceiver_phy->enable_gpio) 34 gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 1); 35 36 return 0; 37 } 38 39 /* Power off function */ 40 static int can_transceiver_phy_power_off(struct phy *phy) 41 { 42 struct can_transceiver_phy *can_transceiver_phy = phy_get_drvdata(phy); 43 44 if (can_transceiver_phy->standby_gpio) 45 gpiod_set_value_cansleep(can_transceiver_phy->standby_gpio, 1); 46 if (can_transceiver_phy->enable_gpio) 47 gpiod_set_value_cansleep(can_transceiver_phy->enable_gpio, 0); 48 49 return 0; 50 } 51 52 static const struct phy_ops can_transceiver_phy_ops = { 53 .power_on = can_transceiver_phy_power_on, 54 .power_off = can_transceiver_phy_power_off, 55 .owner = THIS_MODULE, 56 }; 57 58 static const struct can_transceiver_data tcan1042_drvdata = { 59 .flags = CAN_TRANSCEIVER_STB_PRESENT, 60 }; 61 62 static const struct can_transceiver_data tcan1043_drvdata = { 63 .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT, 64 }; 65 66 static const struct of_device_id can_transceiver_phy_ids[] = { 67 { 68 .compatible = "ti,tcan1042", 69 .data = &tcan1042_drvdata 70 }, 71 { 72 .compatible = "ti,tcan1043", 73 .data = &tcan1043_drvdata 74 }, 75 { } 76 }; 77 MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids); 78 79 static int can_transceiver_phy_probe(struct platform_device *pdev) 80 { 81 struct phy_provider *phy_provider; 82 struct device *dev = &pdev->dev; 83 struct can_transceiver_phy *can_transceiver_phy; 84 const struct can_transceiver_data *drvdata; 85 const struct of_device_id *match; 86 struct phy *phy; 87 struct gpio_desc *standby_gpio; 88 struct gpio_desc *enable_gpio; 89 u32 max_bitrate = 0; 90 91 can_transceiver_phy = devm_kzalloc(dev, sizeof(struct can_transceiver_phy), GFP_KERNEL); 92 if (!can_transceiver_phy) 93 return -ENOMEM; 94 95 match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node); 96 drvdata = match->data; 97 98 phy = devm_phy_create(dev, dev->of_node, 99 &can_transceiver_phy_ops); 100 if (IS_ERR(phy)) { 101 dev_err(dev, "failed to create can transceiver phy\n"); 102 return PTR_ERR(phy); 103 } 104 105 device_property_read_u32(dev, "max-bitrate", &max_bitrate); 106 if (!max_bitrate) 107 dev_warn(dev, "Invalid value for transceiver max bitrate. Ignoring bitrate limit\n"); 108 phy->attrs.max_link_rate = max_bitrate; 109 110 can_transceiver_phy->generic_phy = phy; 111 112 if (drvdata->flags & CAN_TRANSCEIVER_STB_PRESENT) { 113 standby_gpio = devm_gpiod_get_optional(dev, "standby", GPIOD_OUT_HIGH); 114 if (IS_ERR(standby_gpio)) 115 return PTR_ERR(standby_gpio); 116 can_transceiver_phy->standby_gpio = standby_gpio; 117 } 118 119 if (drvdata->flags & CAN_TRANSCEIVER_EN_PRESENT) { 120 enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); 121 if (IS_ERR(enable_gpio)) 122 return PTR_ERR(enable_gpio); 123 can_transceiver_phy->enable_gpio = enable_gpio; 124 } 125 126 phy_set_drvdata(can_transceiver_phy->generic_phy, can_transceiver_phy); 127 128 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 129 130 return PTR_ERR_OR_ZERO(phy_provider); 131 } 132 133 static struct platform_driver can_transceiver_phy_driver = { 134 .probe = can_transceiver_phy_probe, 135 .driver = { 136 .name = "can-transceiver-phy", 137 .of_match_table = can_transceiver_phy_ids, 138 }, 139 }; 140 141 module_platform_driver(can_transceiver_phy_driver); 142 143 MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>"); 144 MODULE_AUTHOR("Aswath Govindraju <a-govindraju@ti.com>"); 145 MODULE_DESCRIPTION("CAN TRANSCEIVER PHY driver"); 146 MODULE_LICENSE("GPL v2"); 147