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

Quelle  phy-sun9i-usb.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Allwinner sun9i USB phy driver
 *
 * Copyright (C) 2014-2015 Chen-Yu Tsai <wens@csie.org>
 *
 * Based on phy-sun4i-usb.c from
 * Hans de Goede <hdegoede@redhat.com>
 *
 * and code from
 * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
 */


#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/usb/of.h>
#include <linux/platform_device.h>
#include <linux/reset.h>

#define SUNXI_AHB_INCR16_BURST_EN BIT(11)
#define SUNXI_AHB_INCR8_BURST_EN BIT(10)
#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
#define SUNXI_ULPI_BYPASS_EN  BIT(0)

/* usb1 HSIC specific bits */
#define SUNXI_EHCI_HS_FORCE  BIT(20)
#define SUNXI_HSIC_CONNECT_DET  BIT(17)
#define SUNXI_HSIC_CONNECT_INT  BIT(16)
#define SUNXI_HSIC   BIT(1)

struct sun9i_usb_phy {
 struct phy *phy;
 void __iomem *pmu;
 struct reset_control *reset;
 struct clk *clk;
 struct clk *hsic_clk;
 enum usb_phy_interface type;
};

static void sun9i_usb_phy_passby(struct sun9i_usb_phy *phy, int enable)
{
 u32 bits, reg_value;

 bits = SUNXI_AHB_INCR16_BURST_EN | SUNXI_AHB_INCR8_BURST_EN |
  SUNXI_AHB_INCR4_BURST_EN | SUNXI_AHB_INCRX_ALIGN_EN |
  SUNXI_ULPI_BYPASS_EN;

 if (phy->type == USBPHY_INTERFACE_MODE_HSIC)
  bits |= SUNXI_HSIC | SUNXI_EHCI_HS_FORCE |
   SUNXI_HSIC_CONNECT_DET | SUNXI_HSIC_CONNECT_INT;

 reg_value = readl(phy->pmu);

 if (enable)
  reg_value |= bits;
 else
  reg_value &= ~bits;

 writel(reg_value, phy->pmu);
}

static int sun9i_usb_phy_init(struct phy *_phy)
{
 struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);
 int ret;

 ret = clk_prepare_enable(phy->clk);
 if (ret)
  goto err_clk;

 ret = clk_prepare_enable(phy->hsic_clk);
 if (ret)
  goto err_hsic_clk;

 ret = reset_control_deassert(phy->reset);
 if (ret)
  goto err_reset;

 sun9i_usb_phy_passby(phy, 1);
 return 0;

err_reset:
 clk_disable_unprepare(phy->hsic_clk);

err_hsic_clk:
 clk_disable_unprepare(phy->clk);

err_clk:
 return ret;
}

static int sun9i_usb_phy_exit(struct phy *_phy)
{
 struct sun9i_usb_phy *phy = phy_get_drvdata(_phy);

 sun9i_usb_phy_passby(phy, 0);
 reset_control_assert(phy->reset);
 clk_disable_unprepare(phy->hsic_clk);
 clk_disable_unprepare(phy->clk);

 return 0;
}

static const struct phy_ops sun9i_usb_phy_ops = {
 .init  = sun9i_usb_phy_init,
 .exit  = sun9i_usb_phy_exit,
 .owner  = THIS_MODULE,
};

static int sun9i_usb_phy_probe(struct platform_device *pdev)
{
 struct sun9i_usb_phy *phy;
 struct device *dev = &pdev->dev;
 struct device_node *np = dev->of_node;
 struct phy_provider *phy_provider;

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

 phy->type = of_usb_get_phy_mode(np);
 if (phy->type == USBPHY_INTERFACE_MODE_HSIC) {
  phy->clk = devm_clk_get(dev, "hsic_480M");
  if (IS_ERR(phy->clk)) {
   dev_err(dev, "failed to get hsic_480M clock\n");
   return PTR_ERR(phy->clk);
  }

  phy->hsic_clk = devm_clk_get(dev, "hsic_12M");
  if (IS_ERR(phy->hsic_clk)) {
   dev_err(dev, "failed to get hsic_12M clock\n");
   return PTR_ERR(phy->hsic_clk);
  }

  phy->reset = devm_reset_control_get(dev, "hsic");
  if (IS_ERR(phy->reset)) {
   dev_err(dev, "failed to get reset control\n");
   return PTR_ERR(phy->reset);
  }
 } else {
  phy->clk = devm_clk_get(dev, "phy");
  if (IS_ERR(phy->clk)) {
   dev_err(dev, "failed to get phy clock\n");
   return PTR_ERR(phy->clk);
  }

  phy->reset = devm_reset_control_get(dev, "phy");
  if (IS_ERR(phy->reset)) {
   dev_err(dev, "failed to get reset control\n");
   return PTR_ERR(phy->reset);
  }
 }

 phy->pmu = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(phy->pmu))
  return PTR_ERR(phy->pmu);

 phy->phy = devm_phy_create(dev, NULL, &sun9i_usb_phy_ops);
 if (IS_ERR(phy->phy)) {
  dev_err(dev, "failed to create PHY\n");
  return PTR_ERR(phy->phy);
 }

 phy_set_drvdata(phy->phy, phy);
 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);

 return PTR_ERR_OR_ZERO(phy_provider);
}

static const struct of_device_id sun9i_usb_phy_of_match[] = {
 { .compatible = "allwinner,sun9i-a80-usb-phy" },
 { },
};
MODULE_DEVICE_TABLE(of, sun9i_usb_phy_of_match);

static struct platform_driver sun9i_usb_phy_driver = {
 .probe = sun9i_usb_phy_probe,
 .driver = {
  .of_match_table = sun9i_usb_phy_of_match,
  .name  = "sun9i-usb-phy",
 }
};
module_platform_driver(sun9i_usb_phy_driver);

MODULE_DESCRIPTION("Allwinner sun9i USB phy driver");
MODULE_AUTHOR("Chen-Yu Tsai ");
MODULE_LICENSE("GPL");

Messung V0.5
C=97 H=94 G=95

¤ Dauer der Verarbeitung: 0.2 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.