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

Quelle  cdns3-ti.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * cdns3-ti.c - TI specific Glue layer for Cadence USB Controller
 *
 * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com
 */


#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include "core.h"

/* USB Wrapper register offsets */
#define USBSS_PID  0x0
#define USBSS_W1  0x4
#define USBSS_STATIC_CONFIG 0x8
#define USBSS_PHY_TEST  0xc
#define USBSS_DEBUG_CTRL 0x10
#define USBSS_DEBUG_INFO 0x14
#define USBSS_DEBUG_LINK_STATE 0x18
#define USBSS_DEVICE_CTRL 0x1c

/* Wrapper 1 register bits */
#define USBSS_W1_PWRUP_RST  BIT(0)
#define USBSS_W1_OVERCURRENT_SEL BIT(8)
#define USBSS_W1_MODESTRAP_SEL  BIT(9)
#define USBSS_W1_OVERCURRENT  BIT(16)
#define USBSS_W1_MODESTRAP_MASK  GENMASK(18, 17)
#define USBSS_W1_MODESTRAP_SHIFT 17
#define USBSS_W1_USB2_ONLY  BIT(19)

/* Static config register bits */
#define USBSS1_STATIC_PLL_REF_SEL_MASK GENMASK(8, 5)
#define USBSS1_STATIC_PLL_REF_SEL_SHIFT 5
#define USBSS1_STATIC_LOOPBACK_MODE_MASK GENMASK(4, 3)
#define USBSS1_STATIC_LOOPBACK_MODE_SHIFT 3
#define USBSS1_STATIC_VBUS_SEL_MASK GENMASK(2, 1)
#define USBSS1_STATIC_VBUS_SEL_SHIFT 1
#define USBSS1_STATIC_LANE_REVERSE BIT(0)

/* Modestrap modes */
enum modestrap_mode { USBSS_MODESTRAP_MODE_NONE,
        USBSS_MODESTRAP_MODE_HOST,
        USBSS_MODESTRAP_MODE_PERIPHERAL};

struct cdns_ti {
 struct device *dev;
 void __iomem *usbss;
 unsigned usb2_only:1;
 unsigned vbus_divider:1;
 struct clk *usb2_refclk;
 struct clk *lpm_clk;
 int usb2_refclk_rate_code;
};

static const int cdns_ti_rate_table[] = { /* in KHZ */
 9600,
 10000,
 12000,
 19200,
 20000,
 24000,
 25000,
 26000,
 38400,
 40000,
 58000,
 50000,
 52000,
};

static inline u32 cdns_ti_readl(struct cdns_ti *data, u32 offset)
{
 return readl(data->usbss + offset);
}

static inline void cdns_ti_writel(struct cdns_ti *data, u32 offset, u32 value)
{
 writel(value, data->usbss + offset);
}

static struct cdns3_platform_data cdns_ti_pdata = {
 .quirks = CDNS3_DRD_SUSPEND_RESIDENCY_ENABLE,   /* Errata i2409 */
};

static const struct of_dev_auxdata cdns_ti_auxdata[] = {
 {
  .compatible = "cdns,usb3",
  .platform_data = &cdns_ti_pdata,
 },
 {},
};

static void cdns_ti_reset_and_init_hw(struct cdns_ti *data)
{
 u32 reg;

 /* assert RESET */
 reg = cdns_ti_readl(data, USBSS_W1);
 reg &= ~USBSS_W1_PWRUP_RST;
 cdns_ti_writel(data, USBSS_W1, reg);

 /* set static config */
 reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);
 reg &= ~USBSS1_STATIC_PLL_REF_SEL_MASK;
 reg |= data->usb2_refclk_rate_code << USBSS1_STATIC_PLL_REF_SEL_SHIFT;

 reg &= ~USBSS1_STATIC_VBUS_SEL_MASK;
 if (data->vbus_divider)
  reg |= 1 << USBSS1_STATIC_VBUS_SEL_SHIFT;

 cdns_ti_writel(data, USBSS_STATIC_CONFIG, reg);
 reg = cdns_ti_readl(data, USBSS_STATIC_CONFIG);

 /* set USB2_ONLY mode if requested */
 reg = cdns_ti_readl(data, USBSS_W1);
 if (data->usb2_only)
  reg |= USBSS_W1_USB2_ONLY;

 /* set default modestrap */
 reg |= USBSS_W1_MODESTRAP_SEL;
 reg &= ~USBSS_W1_MODESTRAP_MASK;
 reg |= USBSS_MODESTRAP_MODE_NONE << USBSS_W1_MODESTRAP_SHIFT;
 cdns_ti_writel(data, USBSS_W1, reg);

 /* de-assert RESET */
 reg |= USBSS_W1_PWRUP_RST;
 cdns_ti_writel(data, USBSS_W1, reg);
}

static int cdns_ti_probe(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;
 struct device_node *node = pdev->dev.of_node;
 struct cdns_ti *data;
 unsigned long rate;
 int error, i;

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

 platform_set_drvdata(pdev, data);

 data->dev = dev;

 data->usbss = devm_platform_ioremap_resource(pdev, 0);
 if (IS_ERR(data->usbss)) {
  dev_err(dev, "can't map IOMEM resource\n");
  return PTR_ERR(data->usbss);
 }

 data->usb2_refclk = devm_clk_get(dev, "ref");
 if (IS_ERR(data->usb2_refclk)) {
  dev_err(dev, "can't get usb2_refclk\n");
  return PTR_ERR(data->usb2_refclk);
 }

 data->lpm_clk = devm_clk_get(dev, "lpm");
 if (IS_ERR(data->lpm_clk)) {
  dev_err(dev, "can't get lpm_clk\n");
  return PTR_ERR(data->lpm_clk);
 }

 rate = clk_get_rate(data->usb2_refclk);
 rate /= 1000; /* To KHz */
 for (i = 0; i < ARRAY_SIZE(cdns_ti_rate_table); i++) {
  if (cdns_ti_rate_table[i] == rate)
   break;
 }

 if (i == ARRAY_SIZE(cdns_ti_rate_table)) {
  dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
  return -EINVAL;
 }

 data->usb2_refclk_rate_code = i;
 data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
 data->usb2_only = device_property_read_bool(dev, "ti,usb2-only");

 /*
 * The call below to pm_runtime_get_sync() MIGHT reset hardware, if it
 * detects it as uninitialised. We want to enforce a reset at probe,
 * and so do it manually here. This means the first runtime_resume()
 * will be a no-op.
 */

 cdns_ti_reset_and_init_hw(data);

 pm_runtime_enable(dev);
 error = pm_runtime_get_sync(dev);
 if (error < 0) {
  dev_err(dev, "pm_runtime_get_sync failed: %d\n", error);
  goto err;
 }

 error = of_platform_populate(node, NULL, cdns_ti_auxdata, dev);
 if (error) {
  dev_err(dev, "failed to create children: %d\n", error);
  goto err;
 }

 return 0;

err:
 pm_runtime_put_sync(data->dev);
 pm_runtime_disable(data->dev);

 return error;
}

static int cdns_ti_remove_core(struct device *dev, void *c)
{
 struct platform_device *pdev = to_platform_device(dev);

 platform_device_unregister(pdev);

 return 0;
}

static void cdns_ti_remove(struct platform_device *pdev)
{
 struct device *dev = &pdev->dev;

 device_for_each_child(dev, NULL, cdns_ti_remove_core);
 pm_runtime_put_sync(dev);
 pm_runtime_disable(dev);

 platform_set_drvdata(pdev, NULL);
}

static int cdns_ti_runtime_resume(struct device *dev)
{
 const u32 mask = USBSS_W1_PWRUP_RST | USBSS_W1_MODESTRAP_SEL;
 struct cdns_ti *data = dev_get_drvdata(dev);
 u32 w1;

 w1 = cdns_ti_readl(data, USBSS_W1);
 if ((w1 & mask) != mask)
  cdns_ti_reset_and_init_hw(data);

 return 0;
}

static const struct dev_pm_ops cdns_ti_pm_ops = {
 RUNTIME_PM_OPS(NULL, cdns_ti_runtime_resume, NULL)
 SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
};

static const struct of_device_id cdns_ti_of_match[] = {
 { .compatible = "ti,j721e-usb", },
 { .compatible = "ti,am64-usb", },
 {},
};
MODULE_DEVICE_TABLE(of, cdns_ti_of_match);

static struct platform_driver cdns_ti_driver = {
 .probe  = cdns_ti_probe,
 .remove  = cdns_ti_remove,
 .driver  = {
  .name = "cdns3-ti",
  .of_match_table = cdns_ti_of_match,
  .pm     = pm_ptr(&cdns_ti_pm_ops),
 },
};

module_platform_driver(cdns_ti_driver);

MODULE_ALIAS("platform:cdns3-ti");
MODULE_AUTHOR("Roger Quadros ");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Cadence USB3 TI Glue Layer");

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

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© 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.