linux/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Amlogic AXG MIPI + PCIE analog PHY driver
   4 *
   5 * Copyright (C) 2019 Remi Pommarel <repk@triplefau.lt>
   6 */
   7#include <linux/module.h>
   8#include <linux/phy/phy.h>
   9#include <linux/regmap.h>
  10#include <linux/platform_device.h>
  11#include <dt-bindings/phy/phy.h>
  12
  13#define HHI_MIPI_CNTL0 0x00
  14#define         HHI_MIPI_CNTL0_COMMON_BLOCK     GENMASK(31, 28)
  15#define         HHI_MIPI_CNTL0_ENABLE           BIT(29)
  16#define         HHI_MIPI_CNTL0_BANDGAP          BIT(26)
  17#define         HHI_MIPI_CNTL0_DECODE_TO_RTERM  GENMASK(15, 12)
  18#define         HHI_MIPI_CNTL0_OUTPUT_EN        BIT(3)
  19
  20#define HHI_MIPI_CNTL1 0x01
  21#define         HHI_MIPI_CNTL1_CH0_CML_PDR_EN   BIT(12)
  22#define         HHI_MIPI_CNTL1_LP_ABILITY       GENMASK(5, 4)
  23#define         HHI_MIPI_CNTL1_LP_RESISTER      BIT(3)
  24#define         HHI_MIPI_CNTL1_INPUT_SETTING    BIT(2)
  25#define         HHI_MIPI_CNTL1_INPUT_SEL        BIT(1)
  26#define         HHI_MIPI_CNTL1_PRBS7_EN         BIT(0)
  27
  28#define HHI_MIPI_CNTL2 0x02
  29#define         HHI_MIPI_CNTL2_CH_PU            GENMASK(31, 25)
  30#define         HHI_MIPI_CNTL2_CH_CTL           GENMASK(24, 19)
  31#define         HHI_MIPI_CNTL2_CH0_DIGDR_EN     BIT(18)
  32#define         HHI_MIPI_CNTL2_CH_DIGDR_EN      BIT(17)
  33#define         HHI_MIPI_CNTL2_LPULPS_EN        BIT(16)
  34#define         HHI_MIPI_CNTL2_CH_EN(n)         BIT(15 - (n))
  35#define         HHI_MIPI_CNTL2_CH0_LP_CTL       GENMASK(10, 1)
  36
  37struct phy_axg_mipi_pcie_analog_priv {
  38        struct phy *phy;
  39        unsigned int mode;
  40        struct regmap *regmap;
  41};
  42
  43static const struct regmap_config phy_axg_mipi_pcie_analog_regmap_conf = {
  44        .reg_bits = 8,
  45        .val_bits = 32,
  46        .reg_stride = 4,
  47        .max_register = HHI_MIPI_CNTL2,
  48};
  49
  50static int phy_axg_mipi_pcie_analog_power_on(struct phy *phy)
  51{
  52        struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
  53
  54        /* MIPI not supported yet */
  55        if (priv->mode != PHY_TYPE_PCIE)
  56                return -EINVAL;
  57
  58        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  59                           HHI_MIPI_CNTL0_BANDGAP, HHI_MIPI_CNTL0_BANDGAP);
  60
  61        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  62                           HHI_MIPI_CNTL0_ENABLE, HHI_MIPI_CNTL0_ENABLE);
  63        return 0;
  64}
  65
  66static int phy_axg_mipi_pcie_analog_power_off(struct phy *phy)
  67{
  68        struct phy_axg_mipi_pcie_analog_priv *priv = phy_get_drvdata(phy);
  69
  70        /* MIPI not supported yet */
  71        if (priv->mode != PHY_TYPE_PCIE)
  72                return -EINVAL;
  73
  74        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  75                           HHI_MIPI_CNTL0_BANDGAP, 0);
  76        regmap_update_bits(priv->regmap, HHI_MIPI_CNTL0,
  77                           HHI_MIPI_CNTL0_ENABLE, 0);
  78        return 0;
  79}
  80
  81static int phy_axg_mipi_pcie_analog_init(struct phy *phy)
  82{
  83        return 0;
  84}
  85
  86static int phy_axg_mipi_pcie_analog_exit(struct phy *phy)
  87{
  88        return 0;
  89}
  90
  91static const struct phy_ops phy_axg_mipi_pcie_analog_ops = {
  92        .init = phy_axg_mipi_pcie_analog_init,
  93        .exit = phy_axg_mipi_pcie_analog_exit,
  94        .power_on = phy_axg_mipi_pcie_analog_power_on,
  95        .power_off = phy_axg_mipi_pcie_analog_power_off,
  96        .owner = THIS_MODULE,
  97};
  98
  99static struct phy *phy_axg_mipi_pcie_analog_xlate(struct device *dev,
 100                                                  struct of_phandle_args *args)
 101{
 102        struct phy_axg_mipi_pcie_analog_priv *priv = dev_get_drvdata(dev);
 103        unsigned int mode;
 104
 105        if (args->args_count != 1) {
 106                dev_err(dev, "invalid number of arguments\n");
 107                return ERR_PTR(-EINVAL);
 108        }
 109
 110        mode = args->args[0];
 111
 112        /* MIPI mode is not supported yet */
 113        if (mode != PHY_TYPE_PCIE) {
 114                dev_err(dev, "invalid phy mode select argument\n");
 115                return ERR_PTR(-EINVAL);
 116        }
 117
 118        priv->mode = mode;
 119        return priv->phy;
 120}
 121
 122static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev)
 123{
 124        struct phy_provider *phy;
 125        struct device *dev = &pdev->dev;
 126        struct phy_axg_mipi_pcie_analog_priv *priv;
 127        struct device_node *np = dev->of_node;
 128        struct regmap *map;
 129        struct resource *res;
 130        void __iomem *base;
 131        int ret;
 132
 133        priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL);
 134        if (!priv)
 135                return -ENOMEM;
 136
 137        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 138        base = devm_ioremap_resource(dev, res);
 139        if (IS_ERR(base)) {
 140                dev_err(dev, "failed to get regmap base\n");
 141                return PTR_ERR(base);
 142        }
 143
 144        map = devm_regmap_init_mmio(dev, base,
 145                                    &phy_axg_mipi_pcie_analog_regmap_conf);
 146        if (IS_ERR(map)) {
 147                dev_err(dev, "failed to get HHI regmap\n");
 148                return PTR_ERR(map);
 149        }
 150        priv->regmap = map;
 151
 152        priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops);
 153        if (IS_ERR(priv->phy)) {
 154                ret = PTR_ERR(priv->phy);
 155                if (ret != -EPROBE_DEFER)
 156                        dev_err(dev, "failed to create PHY\n");
 157                return ret;
 158        }
 159
 160        phy_set_drvdata(priv->phy, priv);
 161        dev_set_drvdata(dev, priv);
 162
 163        phy = devm_of_phy_provider_register(dev,
 164                                            phy_axg_mipi_pcie_analog_xlate);
 165
 166        return PTR_ERR_OR_ZERO(phy);
 167}
 168
 169static const struct of_device_id phy_axg_mipi_pcie_analog_of_match[] = {
 170        {
 171                .compatible = "amlogic,axg-mipi-pcie-analog-phy",
 172        },
 173        { },
 174};
 175MODULE_DEVICE_TABLE(of, phy_axg_mipi_pcie_analog_of_match);
 176
 177static struct platform_driver phy_axg_mipi_pcie_analog_driver = {
 178        .probe = phy_axg_mipi_pcie_analog_probe,
 179        .driver = {
 180                .name = "phy-axg-mipi-pcie-analog",
 181                .of_match_table = phy_axg_mipi_pcie_analog_of_match,
 182        },
 183};
 184module_platform_driver(phy_axg_mipi_pcie_analog_driver);
 185
 186MODULE_AUTHOR("Remi Pommarel <repk@triplefau.lt>");
 187MODULE_DESCRIPTION("Amlogic AXG MIPI + PCIE analog PHY driver");
 188MODULE_LICENSE("GPL v2");
 189