linux/drivers/phy/phy-can-transceiver.c
<<
>>
Prefs
   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
  14struct can_transceiver_data {
  15        u32 flags;
  16#define CAN_TRANSCEIVER_STB_PRESENT     BIT(0)
  17#define CAN_TRANSCEIVER_EN_PRESENT      BIT(1)
  18};
  19
  20struct 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 */
  27static 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 */
  40static 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
  52static 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
  58static const struct can_transceiver_data tcan1042_drvdata = {
  59        .flags = CAN_TRANSCEIVER_STB_PRESENT,
  60};
  61
  62static const struct can_transceiver_data tcan1043_drvdata = {
  63        .flags = CAN_TRANSCEIVER_STB_PRESENT | CAN_TRANSCEIVER_EN_PRESENT,
  64};
  65
  66static 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};
  77MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
  78
  79static 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(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(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
 133static 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
 141module_platform_driver(can_transceiver_phy_driver);
 142
 143MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
 144MODULE_AUTHOR("Aswath Govindraju <a-govindraju@ti.com>");
 145MODULE_DESCRIPTION("CAN TRANSCEIVER PHY driver");
 146MODULE_LICENSE("GPL v2");
 147