Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Samsung SATA SerDes(PHY) driver
0004  *
0005  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
0006  * Authors: Girish K S <ks.giri@samsung.com>
0007  *         Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
0008  */
0009 
0010 #include <linux/clk.h>
0011 #include <linux/delay.h>
0012 #include <linux/io.h>
0013 #include <linux/i2c.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/of.h>
0017 #include <linux/of_address.h>
0018 #include <linux/phy/phy.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regmap.h>
0021 #include <linux/spinlock.h>
0022 #include <linux/mfd/syscon.h>
0023 
0024 #define SATAPHY_CONTROL_OFFSET      0x0724
0025 #define EXYNOS5_SATAPHY_PMU_ENABLE  BIT(0)
0026 #define EXYNOS5_SATA_RESET      0x4
0027 #define RESET_GLOBAL_RST_N      BIT(0)
0028 #define RESET_CMN_RST_N         BIT(1)
0029 #define RESET_CMN_BLOCK_RST_N       BIT(2)
0030 #define RESET_CMN_I2C_RST_N     BIT(3)
0031 #define RESET_TX_RX_PIPE_RST_N      BIT(4)
0032 #define RESET_TX_RX_BLOCK_RST_N     BIT(5)
0033 #define RESET_TX_RX_I2C_RST_N       (BIT(6) | BIT(7))
0034 #define LINK_RESET          0xf0000
0035 #define EXYNOS5_SATA_MODE0      0x10
0036 #define SATA_SPD_GEN3           BIT(1)
0037 #define EXYNOS5_SATA_CTRL0      0x14
0038 #define CTRL0_P0_PHY_CALIBRATED_SEL BIT(9)
0039 #define CTRL0_P0_PHY_CALIBRATED     BIT(8)
0040 #define EXYNOS5_SATA_PHSATA_CTRLM   0xe0
0041 #define PHCTRLM_REF_RATE        BIT(1)
0042 #define PHCTRLM_HIGH_SPEED      BIT(0)
0043 #define EXYNOS5_SATA_PHSATA_STATM   0xf0
0044 #define PHSTATM_PLL_LOCKED      BIT(0)
0045 
0046 #define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))
0047 
0048 struct exynos_sata_phy {
0049     struct phy *phy;
0050     struct clk *phyclk;
0051     void __iomem *regs;
0052     struct regmap *pmureg;
0053     struct i2c_client *client;
0054 };
0055 
0056 static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
0057                 u32 status)
0058 {
0059     unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;
0060 
0061     while (time_before(jiffies, timeout)) {
0062         if ((readl(base + reg) & checkbit) == status)
0063             return 0;
0064     }
0065 
0066     return -EFAULT;
0067 }
0068 
0069 static int exynos_sata_phy_power_on(struct phy *phy)
0070 {
0071     struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
0072 
0073     return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
0074             EXYNOS5_SATAPHY_PMU_ENABLE, true);
0075 
0076 }
0077 
0078 static int exynos_sata_phy_power_off(struct phy *phy)
0079 {
0080     struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
0081 
0082     return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
0083             EXYNOS5_SATAPHY_PMU_ENABLE, false);
0084 
0085 }
0086 
0087 static int exynos_sata_phy_init(struct phy *phy)
0088 {
0089     u32 val = 0;
0090     int ret = 0;
0091     u8 buf[] = { 0x3a, 0x0b };
0092     struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);
0093 
0094     ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
0095             EXYNOS5_SATAPHY_PMU_ENABLE, true);
0096     if (ret != 0)
0097         dev_err(&sata_phy->phy->dev, "phy init failed\n");
0098 
0099     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0100 
0101     val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
0102     val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
0103         | RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
0104         | RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
0105     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0106 
0107     val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
0108     val |= LINK_RESET;
0109     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0110 
0111     val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
0112     val |= RESET_CMN_RST_N;
0113     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0114 
0115     val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
0116     val &= ~PHCTRLM_REF_RATE;
0117     writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
0118 
0119     /* High speed enable for Gen3 */
0120     val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
0121     val |= PHCTRLM_HIGH_SPEED;
0122     writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
0123 
0124     val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
0125     val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
0126     writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);
0127 
0128     val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
0129     val |= SATA_SPD_GEN3;
0130     writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);
0131 
0132     ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
0133     if (ret < 0)
0134         return ret;
0135 
0136     /* release cmu reset */
0137     val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
0138     val &= ~RESET_CMN_RST_N;
0139     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0140 
0141     val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
0142     val |= RESET_CMN_RST_N;
0143     writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);
0144 
0145     ret = wait_for_reg_status(sata_phy->regs,
0146                 EXYNOS5_SATA_PHSATA_STATM,
0147                 PHSTATM_PLL_LOCKED, 1);
0148     if (ret < 0)
0149         dev_err(&sata_phy->phy->dev,
0150             "PHY PLL locking failed\n");
0151     return ret;
0152 }
0153 
0154 static const struct phy_ops exynos_sata_phy_ops = {
0155     .init       = exynos_sata_phy_init,
0156     .power_on   = exynos_sata_phy_power_on,
0157     .power_off  = exynos_sata_phy_power_off,
0158     .owner      = THIS_MODULE,
0159 };
0160 
0161 static int exynos_sata_phy_probe(struct platform_device *pdev)
0162 {
0163     struct exynos_sata_phy *sata_phy;
0164     struct device *dev = &pdev->dev;
0165     struct phy_provider *phy_provider;
0166     struct device_node *node;
0167     int ret = 0;
0168 
0169     sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
0170     if (!sata_phy)
0171         return -ENOMEM;
0172 
0173     sata_phy->regs = devm_platform_ioremap_resource(pdev, 0);
0174     if (IS_ERR(sata_phy->regs))
0175         return PTR_ERR(sata_phy->regs);
0176 
0177     sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
0178                     "samsung,syscon-phandle");
0179     if (IS_ERR(sata_phy->pmureg)) {
0180         dev_err(dev, "syscon regmap lookup failed.\n");
0181         return PTR_ERR(sata_phy->pmureg);
0182     }
0183 
0184     node = of_parse_phandle(dev->of_node,
0185             "samsung,exynos-sataphy-i2c-phandle", 0);
0186     if (!node)
0187         return -EINVAL;
0188 
0189     sata_phy->client = of_find_i2c_device_by_node(node);
0190     of_node_put(node);
0191     if (!sata_phy->client)
0192         return -EPROBE_DEFER;
0193 
0194     dev_set_drvdata(dev, sata_phy);
0195 
0196     sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
0197     if (IS_ERR(sata_phy->phyclk)) {
0198         dev_err(dev, "failed to get clk for PHY\n");
0199         ret = PTR_ERR(sata_phy->phyclk);
0200         goto put_dev;
0201     }
0202 
0203     ret = clk_prepare_enable(sata_phy->phyclk);
0204     if (ret < 0) {
0205         dev_err(dev, "failed to enable source clk\n");
0206         goto put_dev;
0207     }
0208 
0209     sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
0210     if (IS_ERR(sata_phy->phy)) {
0211         dev_err(dev, "failed to create PHY\n");
0212         ret = PTR_ERR(sata_phy->phy);
0213         goto clk_disable;
0214     }
0215 
0216     phy_set_drvdata(sata_phy->phy, sata_phy);
0217 
0218     phy_provider = devm_of_phy_provider_register(dev,
0219                     of_phy_simple_xlate);
0220     if (IS_ERR(phy_provider)) {
0221         ret = PTR_ERR(phy_provider);
0222         goto clk_disable;
0223     }
0224 
0225     return 0;
0226 
0227 clk_disable:
0228     clk_disable_unprepare(sata_phy->phyclk);
0229 put_dev:
0230     put_device(&sata_phy->client->dev);
0231 
0232     return ret;
0233 }
0234 
0235 static const struct of_device_id exynos_sata_phy_of_match[] = {
0236     { .compatible = "samsung,exynos5250-sata-phy" },
0237     { },
0238 };
0239 MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);
0240 
0241 static struct platform_driver exynos_sata_phy_driver = {
0242     .probe  = exynos_sata_phy_probe,
0243     .driver = {
0244         .of_match_table = exynos_sata_phy_of_match,
0245         .name  = "samsung,sata-phy",
0246         .suppress_bind_attrs = true,
0247     }
0248 };
0249 module_platform_driver(exynos_sata_phy_driver);
0250 
0251 MODULE_DESCRIPTION("Samsung SerDes PHY driver");
0252 MODULE_LICENSE("GPL v2");
0253 MODULE_AUTHOR("Girish K S <ks.giri@samsung.com>");
0254 MODULE_AUTHOR("Yuvaraj C D <yuvaraj.cd@samsung.com>");