root/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun6i_dphy_init
  2. sun6i_dphy_configure
  3. sun6i_dphy_power_on
  4. sun6i_dphy_power_off
  5. sun6i_dphy_exit
  6. sun6i_dphy_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (c) 2016 Allwinnertech Co., Ltd.
   4  * Copyright (C) 2017-2018 Bootlin
   5  *
   6  * Maxime Ripard <maxime.ripard@free-electrons.com>
   7  */
   8 
   9 #include <linux/bitops.h>
  10 #include <linux/clk.h>
  11 #include <linux/module.h>
  12 #include <linux/of_address.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/regmap.h>
  15 #include <linux/reset.h>
  16 
  17 #include <linux/phy/phy.h>
  18 #include <linux/phy/phy-mipi-dphy.h>
  19 
  20 #define SUN6I_DPHY_GCTL_REG             0x00
  21 #define SUN6I_DPHY_GCTL_LANE_NUM(n)             ((((n) - 1) & 3) << 4)
  22 #define SUN6I_DPHY_GCTL_EN                      BIT(0)
  23 
  24 #define SUN6I_DPHY_TX_CTL_REG           0x04
  25 #define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT        BIT(28)
  26 
  27 #define SUN6I_DPHY_TX_TIME0_REG         0x10
  28 #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n)         (((n) & 0xff) << 24)
  29 #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n)       (((n) & 0xff) << 16)
  30 #define SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(n)       ((n) & 0xff)
  31 
  32 #define SUN6I_DPHY_TX_TIME1_REG         0x14
  33 #define SUN6I_DPHY_TX_TIME1_CLK_POST(n)         (((n) & 0xff) << 24)
  34 #define SUN6I_DPHY_TX_TIME1_CLK_PRE(n)          (((n) & 0xff) << 16)
  35 #define SUN6I_DPHY_TX_TIME1_CLK_ZERO(n)         (((n) & 0xff) << 8)
  36 #define SUN6I_DPHY_TX_TIME1_CLK_PREPARE(n)      ((n) & 0xff)
  37 
  38 #define SUN6I_DPHY_TX_TIME2_REG         0x18
  39 #define SUN6I_DPHY_TX_TIME2_CLK_TRAIL(n)        ((n) & 0xff)
  40 
  41 #define SUN6I_DPHY_TX_TIME3_REG         0x1c
  42 
  43 #define SUN6I_DPHY_TX_TIME4_REG         0x20
  44 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n)       (((n) & 0xff) << 8)
  45 #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n)       ((n) & 0xff)
  46 
  47 #define SUN6I_DPHY_ANA0_REG             0x4c
  48 #define SUN6I_DPHY_ANA0_REG_PWS                 BIT(31)
  49 #define SUN6I_DPHY_ANA0_REG_DMPC                BIT(28)
  50 #define SUN6I_DPHY_ANA0_REG_DMPD(n)             (((n) & 0xf) << 24)
  51 #define SUN6I_DPHY_ANA0_REG_SLV(n)              (((n) & 7) << 12)
  52 #define SUN6I_DPHY_ANA0_REG_DEN(n)              (((n) & 0xf) << 8)
  53 
  54 #define SUN6I_DPHY_ANA1_REG             0x50
  55 #define SUN6I_DPHY_ANA1_REG_VTTMODE             BIT(31)
  56 #define SUN6I_DPHY_ANA1_REG_CSMPS(n)            (((n) & 3) << 28)
  57 #define SUN6I_DPHY_ANA1_REG_SVTT(n)             (((n) & 0xf) << 24)
  58 
  59 #define SUN6I_DPHY_ANA2_REG             0x54
  60 #define SUN6I_DPHY_ANA2_EN_P2S_CPU(n)           (((n) & 0xf) << 24)
  61 #define SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK         GENMASK(27, 24)
  62 #define SUN6I_DPHY_ANA2_EN_CK_CPU               BIT(4)
  63 #define SUN6I_DPHY_ANA2_REG_ENIB                BIT(1)
  64 
  65 #define SUN6I_DPHY_ANA3_REG             0x58
  66 #define SUN6I_DPHY_ANA3_EN_VTTD(n)              (((n) & 0xf) << 28)
  67 #define SUN6I_DPHY_ANA3_EN_VTTD_MASK            GENMASK(31, 28)
  68 #define SUN6I_DPHY_ANA3_EN_VTTC                 BIT(27)
  69 #define SUN6I_DPHY_ANA3_EN_DIV                  BIT(26)
  70 #define SUN6I_DPHY_ANA3_EN_LDOC                 BIT(25)
  71 #define SUN6I_DPHY_ANA3_EN_LDOD                 BIT(24)
  72 #define SUN6I_DPHY_ANA3_EN_LDOR                 BIT(18)
  73 
  74 #define SUN6I_DPHY_ANA4_REG             0x5c
  75 #define SUN6I_DPHY_ANA4_REG_DMPLVC              BIT(24)
  76 #define SUN6I_DPHY_ANA4_REG_DMPLVD(n)           (((n) & 0xf) << 20)
  77 #define SUN6I_DPHY_ANA4_REG_CKDV(n)             (((n) & 0x1f) << 12)
  78 #define SUN6I_DPHY_ANA4_REG_TMSC(n)             (((n) & 3) << 10)
  79 #define SUN6I_DPHY_ANA4_REG_TMSD(n)             (((n) & 3) << 8)
  80 #define SUN6I_DPHY_ANA4_REG_TXDNSC(n)           (((n) & 3) << 6)
  81 #define SUN6I_DPHY_ANA4_REG_TXDNSD(n)           (((n) & 3) << 4)
  82 #define SUN6I_DPHY_ANA4_REG_TXPUSC(n)           (((n) & 3) << 2)
  83 #define SUN6I_DPHY_ANA4_REG_TXPUSD(n)           ((n) & 3)
  84 
  85 #define SUN6I_DPHY_DBG5_REG             0xf4
  86 
  87 struct sun6i_dphy {
  88         struct clk                              *bus_clk;
  89         struct clk                              *mod_clk;
  90         struct regmap                           *regs;
  91         struct reset_control                    *reset;
  92 
  93         struct phy                              *phy;
  94         struct phy_configure_opts_mipi_dphy     config;
  95 };
  96 
  97 static int sun6i_dphy_init(struct phy *phy)
  98 {
  99         struct sun6i_dphy *dphy = phy_get_drvdata(phy);
 100 
 101         reset_control_deassert(dphy->reset);
 102         clk_prepare_enable(dphy->mod_clk);
 103         clk_set_rate_exclusive(dphy->mod_clk, 150000000);
 104 
 105         return 0;
 106 }
 107 
 108 static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
 109 {
 110         struct sun6i_dphy *dphy = phy_get_drvdata(phy);
 111         int ret;
 112 
 113         ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy);
 114         if (ret)
 115                 return ret;
 116 
 117         memcpy(&dphy->config, opts, sizeof(dphy->config));
 118 
 119         return 0;
 120 }
 121 
 122 static int sun6i_dphy_power_on(struct phy *phy)
 123 {
 124         struct sun6i_dphy *dphy = phy_get_drvdata(phy);
 125         u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0);
 126 
 127         regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG,
 128                      SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT);
 129 
 130         regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME0_REG,
 131                      SUN6I_DPHY_TX_TIME0_LP_CLK_DIV(14) |
 132                      SUN6I_DPHY_TX_TIME0_HS_PREPARE(6) |
 133                      SUN6I_DPHY_TX_TIME0_HS_TRAIL(10));
 134 
 135         regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME1_REG,
 136                      SUN6I_DPHY_TX_TIME1_CLK_PREPARE(7) |
 137                      SUN6I_DPHY_TX_TIME1_CLK_ZERO(50) |
 138                      SUN6I_DPHY_TX_TIME1_CLK_PRE(3) |
 139                      SUN6I_DPHY_TX_TIME1_CLK_POST(10));
 140 
 141         regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME2_REG,
 142                      SUN6I_DPHY_TX_TIME2_CLK_TRAIL(30));
 143 
 144         regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME3_REG, 0);
 145 
 146         regmap_write(dphy->regs, SUN6I_DPHY_TX_TIME4_REG,
 147                      SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(3) |
 148                      SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(3));
 149 
 150         regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG,
 151                      SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) |
 152                      SUN6I_DPHY_GCTL_EN);
 153 
 154         regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG,
 155                      SUN6I_DPHY_ANA0_REG_PWS |
 156                      SUN6I_DPHY_ANA0_REG_DMPC |
 157                      SUN6I_DPHY_ANA0_REG_SLV(7) |
 158                      SUN6I_DPHY_ANA0_REG_DMPD(lanes_mask) |
 159                      SUN6I_DPHY_ANA0_REG_DEN(lanes_mask));
 160 
 161         regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG,
 162                      SUN6I_DPHY_ANA1_REG_CSMPS(1) |
 163                      SUN6I_DPHY_ANA1_REG_SVTT(7));
 164 
 165         regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG,
 166                      SUN6I_DPHY_ANA4_REG_CKDV(1) |
 167                      SUN6I_DPHY_ANA4_REG_TMSC(1) |
 168                      SUN6I_DPHY_ANA4_REG_TMSD(1) |
 169                      SUN6I_DPHY_ANA4_REG_TXDNSC(1) |
 170                      SUN6I_DPHY_ANA4_REG_TXDNSD(1) |
 171                      SUN6I_DPHY_ANA4_REG_TXPUSC(1) |
 172                      SUN6I_DPHY_ANA4_REG_TXPUSD(1) |
 173                      SUN6I_DPHY_ANA4_REG_DMPLVC |
 174                      SUN6I_DPHY_ANA4_REG_DMPLVD(lanes_mask));
 175 
 176         regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG,
 177                      SUN6I_DPHY_ANA2_REG_ENIB);
 178         udelay(5);
 179 
 180         regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG,
 181                      SUN6I_DPHY_ANA3_EN_LDOR |
 182                      SUN6I_DPHY_ANA3_EN_LDOC |
 183                      SUN6I_DPHY_ANA3_EN_LDOD);
 184         udelay(1);
 185 
 186         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
 187                            SUN6I_DPHY_ANA3_EN_VTTC |
 188                            SUN6I_DPHY_ANA3_EN_VTTD_MASK,
 189                            SUN6I_DPHY_ANA3_EN_VTTC |
 190                            SUN6I_DPHY_ANA3_EN_VTTD(lanes_mask));
 191         udelay(1);
 192 
 193         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA3_REG,
 194                            SUN6I_DPHY_ANA3_EN_DIV,
 195                            SUN6I_DPHY_ANA3_EN_DIV);
 196         udelay(1);
 197 
 198         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
 199                            SUN6I_DPHY_ANA2_EN_CK_CPU,
 200                            SUN6I_DPHY_ANA2_EN_CK_CPU);
 201         udelay(1);
 202 
 203         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
 204                            SUN6I_DPHY_ANA1_REG_VTTMODE,
 205                            SUN6I_DPHY_ANA1_REG_VTTMODE);
 206 
 207         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA2_REG,
 208                            SUN6I_DPHY_ANA2_EN_P2S_CPU_MASK,
 209                            SUN6I_DPHY_ANA2_EN_P2S_CPU(lanes_mask));
 210 
 211         return 0;
 212 }
 213 
 214 static int sun6i_dphy_power_off(struct phy *phy)
 215 {
 216         struct sun6i_dphy *dphy = phy_get_drvdata(phy);
 217 
 218         regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG,
 219                            SUN6I_DPHY_ANA1_REG_VTTMODE, 0);
 220 
 221         return 0;
 222 }
 223 
 224 static int sun6i_dphy_exit(struct phy *phy)
 225 {
 226         struct sun6i_dphy *dphy = phy_get_drvdata(phy);
 227 
 228         clk_rate_exclusive_put(dphy->mod_clk);
 229         clk_disable_unprepare(dphy->mod_clk);
 230         reset_control_assert(dphy->reset);
 231 
 232         return 0;
 233 }
 234 
 235 
 236 static struct phy_ops sun6i_dphy_ops = {
 237         .configure      = sun6i_dphy_configure,
 238         .power_on       = sun6i_dphy_power_on,
 239         .power_off      = sun6i_dphy_power_off,
 240         .init           = sun6i_dphy_init,
 241         .exit           = sun6i_dphy_exit,
 242 };
 243 
 244 static struct regmap_config sun6i_dphy_regmap_config = {
 245         .reg_bits       = 32,
 246         .val_bits       = 32,
 247         .reg_stride     = 4,
 248         .max_register   = SUN6I_DPHY_DBG5_REG,
 249         .name           = "mipi-dphy",
 250 };
 251 
 252 static int sun6i_dphy_probe(struct platform_device *pdev)
 253 {
 254         struct phy_provider *phy_provider;
 255         struct sun6i_dphy *dphy;
 256         struct resource *res;
 257         void __iomem *regs;
 258 
 259         dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
 260         if (!dphy)
 261                 return -ENOMEM;
 262 
 263         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 264         regs = devm_ioremap_resource(&pdev->dev, res);
 265         if (IS_ERR(regs)) {
 266                 dev_err(&pdev->dev, "Couldn't map the DPHY encoder registers\n");
 267                 return PTR_ERR(regs);
 268         }
 269 
 270         dphy->regs = devm_regmap_init_mmio_clk(&pdev->dev, "bus",
 271                                                regs, &sun6i_dphy_regmap_config);
 272         if (IS_ERR(dphy->regs)) {
 273                 dev_err(&pdev->dev, "Couldn't create the DPHY encoder regmap\n");
 274                 return PTR_ERR(dphy->regs);
 275         }
 276 
 277         dphy->reset = devm_reset_control_get_shared(&pdev->dev, NULL);
 278         if (IS_ERR(dphy->reset)) {
 279                 dev_err(&pdev->dev, "Couldn't get our reset line\n");
 280                 return PTR_ERR(dphy->reset);
 281         }
 282 
 283         dphy->mod_clk = devm_clk_get(&pdev->dev, "mod");
 284         if (IS_ERR(dphy->mod_clk)) {
 285                 dev_err(&pdev->dev, "Couldn't get the DPHY mod clock\n");
 286                 return PTR_ERR(dphy->mod_clk);
 287         }
 288 
 289         dphy->phy = devm_phy_create(&pdev->dev, NULL, &sun6i_dphy_ops);
 290         if (IS_ERR(dphy->phy)) {
 291                 dev_err(&pdev->dev, "failed to create PHY\n");
 292                 return PTR_ERR(dphy->phy);
 293         }
 294 
 295         phy_set_drvdata(dphy->phy, dphy);
 296         phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
 297 
 298         return PTR_ERR_OR_ZERO(phy_provider);
 299 }
 300 
 301 static const struct of_device_id sun6i_dphy_of_table[] = {
 302         { .compatible = "allwinner,sun6i-a31-mipi-dphy" },
 303         { }
 304 };
 305 MODULE_DEVICE_TABLE(of, sun6i_dphy_of_table);
 306 
 307 static struct platform_driver sun6i_dphy_platform_driver = {
 308         .probe          = sun6i_dphy_probe,
 309         .driver         = {
 310                 .name           = "sun6i-mipi-dphy",
 311                 .of_match_table = sun6i_dphy_of_table,
 312         },
 313 };
 314 module_platform_driver(sun6i_dphy_platform_driver);
 315 
 316 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin>");
 317 MODULE_DESCRIPTION("Allwinner A31 MIPI D-PHY Driver");
 318 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */