Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/phy/samsung/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  phy-exynos5250-sata.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Samsung SATA SerDes(PHY) driver
 *
 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
 * Authors: Girish K S <ks.giri@samsung.com>
 *         Yuvaraj Kumar C D <yuvaraj.cd@samsung.com>
 */


#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <linux/mfd/syscon.h>

#define SATAPHY_CONTROL_OFFSET  0x0724
#define EXYNOS5_SATAPHY_PMU_ENABLE BIT(0)
#define EXYNOS5_SATA_RESET  0x4
#define RESET_GLOBAL_RST_N  BIT(0)
#define RESET_CMN_RST_N   BIT(1)
#define RESET_CMN_BLOCK_RST_N  BIT(2)
#define RESET_CMN_I2C_RST_N  BIT(3)
#define RESET_TX_RX_PIPE_RST_N  BIT(4)
#define RESET_TX_RX_BLOCK_RST_N  BIT(5)
#define RESET_TX_RX_I2C_RST_N  (BIT(6) | BIT(7))
#define LINK_RESET   0xf0000
#define EXYNOS5_SATA_MODE0  0x10
#define SATA_SPD_GEN3   BIT(1)
#define EXYNOS5_SATA_CTRL0  0x14
#define CTRL0_P0_PHY_CALIBRATED_SEL BIT(9)
#define CTRL0_P0_PHY_CALIBRATED  BIT(8)
#define EXYNOS5_SATA_PHSATA_CTRLM 0xe0
#define PHCTRLM_REF_RATE  BIT(1)
#define PHCTRLM_HIGH_SPEED  BIT(0)
#define EXYNOS5_SATA_PHSATA_STATM 0xf0
#define PHSTATM_PLL_LOCKED  BIT(0)

#define PHY_PLL_TIMEOUT (usecs_to_jiffies(1000))

struct exynos_sata_phy {
 struct phy *phy;
 struct clk *phyclk;
 void __iomem *regs;
 struct regmap *pmureg;
 struct i2c_client *client;
};

static int wait_for_reg_status(void __iomem *base, u32 reg, u32 checkbit,
    u32 status)
{
 unsigned long timeout = jiffies + PHY_PLL_TIMEOUT;

 while (time_before(jiffies, timeout)) {
  if ((readl(base + reg) & checkbit) == status)
   return 0;
 }

 return -EFAULT;
}

static int exynos_sata_phy_power_on(struct phy *phy)
{
 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);

 return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
   EXYNOS5_SATAPHY_PMU_ENABLE, true);

}

static int exynos_sata_phy_power_off(struct phy *phy)
{
 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);

 return regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
   EXYNOS5_SATAPHY_PMU_ENABLE, false);

}

static int exynos_sata_phy_init(struct phy *phy)
{
 u32 val = 0;
 int ret = 0;
 u8 buf[] = { 0x3a, 0x0b };
 struct exynos_sata_phy *sata_phy = phy_get_drvdata(phy);

 ret = regmap_update_bits(sata_phy->pmureg, SATAPHY_CONTROL_OFFSET,
   EXYNOS5_SATAPHY_PMU_ENABLE, true);
 if (ret != 0)
  dev_err(&sata_phy->phy->dev, "phy init failed\n");

 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
 val |= RESET_GLOBAL_RST_N | RESET_CMN_RST_N | RESET_CMN_BLOCK_RST_N
  | RESET_CMN_I2C_RST_N | RESET_TX_RX_PIPE_RST_N
  | RESET_TX_RX_BLOCK_RST_N | RESET_TX_RX_I2C_RST_N;
 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
 val |= LINK_RESET;
 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
 val |= RESET_CMN_RST_N;
 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
 val &= ~PHCTRLM_REF_RATE;
 writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);

 /* High speed enable for Gen3 */
 val = readl(sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);
 val |= PHCTRLM_HIGH_SPEED;
 writel(val, sata_phy->regs + EXYNOS5_SATA_PHSATA_CTRLM);

 val = readl(sata_phy->regs + EXYNOS5_SATA_CTRL0);
 val |= CTRL0_P0_PHY_CALIBRATED_SEL | CTRL0_P0_PHY_CALIBRATED;
 writel(val, sata_phy->regs + EXYNOS5_SATA_CTRL0);

 val = readl(sata_phy->regs + EXYNOS5_SATA_MODE0);
 val |= SATA_SPD_GEN3;
 writel(val, sata_phy->regs + EXYNOS5_SATA_MODE0);

 ret = i2c_master_send(sata_phy->client, buf, sizeof(buf));
 if (ret < 0)
  return ret;

 /* release cmu reset */
 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
 val &= ~RESET_CMN_RST_N;
 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 val = readl(sata_phy->regs + EXYNOS5_SATA_RESET);
 val |= RESET_CMN_RST_N;
 writel(val, sata_phy->regs + EXYNOS5_SATA_RESET);

 ret = wait_for_reg_status(sata_phy->regs,
    EXYNOS5_SATA_PHSATA_STATM,
    PHSTATM_PLL_LOCKED, 1);
 if (ret < 0)
  dev_err(&sata_phy->phy->dev,
   "PHY PLL locking failed\n");
 return ret;
}

static const struct phy_ops exynos_sata_phy_ops = {
 .init  = exynos_sata_phy_init,
 .power_on = exynos_sata_phy_power_on,
 .power_off = exynos_sata_phy_power_off,
 .owner  = THIS_MODULE,
};

static int exynos_sata_phy_probe(struct platform_device *pdev)
{
 struct exynos_sata_phy *sata_phy;
 struct device *dev = &pdev->dev;
 struct phy_provider *phy_provider;
 struct device_node *node;
 int ret = 0;

 sata_phy = devm_kzalloc(dev, sizeof(*sata_phy), GFP_KERNEL);
 if (!sata_phy)
  return -ENOMEM;

 sata_phy->regs = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(sata_phy->regs))
  return PTR_ERR(sata_phy->regs);

 sata_phy->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
     "samsung,syscon-phandle");
 if (IS_ERR(sata_phy->pmureg)) {
  dev_err(dev, "syscon regmap lookup failed.\n");
  return PTR_ERR(sata_phy->pmureg);
 }

 node = of_parse_phandle(dev->of_node,
   "samsung,exynos-sataphy-i2c-phandle", 0);
 if (!node)
  return -EINVAL;

 sata_phy->client = of_find_i2c_device_by_node(node);
 of_node_put(node);
 if (!sata_phy->client)
  return -EPROBE_DEFER;

 dev_set_drvdata(dev, sata_phy);

 sata_phy->phyclk = devm_clk_get(dev, "sata_phyctrl");
 if (IS_ERR(sata_phy->phyclk)) {
  dev_err(dev, "failed to get clk for PHY\n");
  ret = PTR_ERR(sata_phy->phyclk);
  goto put_dev;
 }

 ret = clk_prepare_enable(sata_phy->phyclk);
 if (ret < 0) {
  dev_err(dev, "failed to enable source clk\n");
  goto put_dev;
 }

 sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
 if (IS_ERR(sata_phy->phy)) {
  dev_err(dev, "failed to create PHY\n");
  ret = PTR_ERR(sata_phy->phy);
  goto clk_disable;
 }

 phy_set_drvdata(sata_phy->phy, sata_phy);

 phy_provider = devm_of_phy_provider_register(dev,
     of_phy_simple_xlate);
 if (IS_ERR(phy_provider)) {
  ret = PTR_ERR(phy_provider);
  goto clk_disable;
 }

 return 0;

clk_disable:
 clk_disable_unprepare(sata_phy->phyclk);
put_dev:
 put_device(&sata_phy->client->dev);

 return ret;
}

static const struct of_device_id exynos_sata_phy_of_match[] = {
 { .compatible = "samsung,exynos5250-sata-phy" },
 { },
};
MODULE_DEVICE_TABLE(of, exynos_sata_phy_of_match);

static struct platform_driver exynos_sata_phy_driver = {
 .probe = exynos_sata_phy_probe,
 .driver = {
  .of_match_table = exynos_sata_phy_of_match,
  .name  = "samsung,sata-phy",
  .suppress_bind_attrs = true,
 }
};
module_platform_driver(exynos_sata_phy_driver);

MODULE_DESCRIPTION("Samsung SerDes PHY driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Girish K S ");
MODULE_AUTHOR("Yuvaraj C D ");

Messung V0.5
C=94 H=93 G=93

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.