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

Quellcode-Bibliothek phy-ulpi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Generic ULPI USB transceiver support
 *
 * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
 *
 * Based on sources from
 *
 *   Sascha Hauer <s.hauer@pengutronix.de>
 *   Freescale Semiconductors
 */


#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>


struct ulpi_info {
 unsigned int id;
 char  *name;
};

#define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
#define ULPI_INFO(_id, _name)  \
 {    \
  .id = (_id), \
  .name = (_name), \
 }

/* ULPI hardcoded IDs, used for probing */
static struct ulpi_info ulpi_ids[] = {
 ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
 ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
 ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"),
 ULPI_INFO(ULPI_ID(0x0424, 0x0009), "SMSC USB334x"),
 ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
};

static int ulpi_set_otg_flags(struct usb_phy *phy)
{
 unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
        ULPI_OTG_CTRL_DM_PULLDOWN;

 if (phy->flags & ULPI_OTG_ID_PULLUP)
  flags |= ULPI_OTG_CTRL_ID_PULLUP;

 /*
 * ULPI Specification rev.1.1 default
 * for Dp/DmPulldown is enabled.
 */

 if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
  flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;

 if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
  flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;

 if (phy->flags & ULPI_OTG_EXTVBUSIND)
  flags |= ULPI_OTG_CTRL_EXTVBUSIND;

 return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
}

static int ulpi_set_fc_flags(struct usb_phy *phy)
{
 unsigned int flags = 0;

 /*
 * ULPI Specification rev.1.1 default
 * for XcvrSelect is Full Speed.
 */

 if (phy->flags & ULPI_FC_HS)
  flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
 else if (phy->flags & ULPI_FC_LS)
  flags |= ULPI_FUNC_CTRL_LOW_SPEED;
 else if (phy->flags & ULPI_FC_FS4LS)
  flags |= ULPI_FUNC_CTRL_FS4LS;
 else
  flags |= ULPI_FUNC_CTRL_FULL_SPEED;

 if (phy->flags & ULPI_FC_TERMSEL)
  flags |= ULPI_FUNC_CTRL_TERMSELECT;

 /*
 * ULPI Specification rev.1.1 default
 * for OpMode is Normal Operation.
 */

 if (phy->flags & ULPI_FC_OP_NODRV)
  flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
 else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
  flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
 else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
  flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
 else
  flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;

 /*
 * ULPI Specification rev.1.1 default
 * for SuspendM is Powered.
 */

 flags |= ULPI_FUNC_CTRL_SUSPENDM;

 return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
}

static int ulpi_set_ic_flags(struct usb_phy *phy)
{
 unsigned int flags = 0;

 if (phy->flags & ULPI_IC_AUTORESUME)
  flags |= ULPI_IFC_CTRL_AUTORESUME;

 if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
  flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;

 if (phy->flags & ULPI_IC_IND_PASSTHRU)
  flags |= ULPI_IFC_CTRL_PASSTHRU;

 if (phy->flags & ULPI_IC_PROTECT_DIS)
  flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;

 return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
}

static int ulpi_set_flags(struct usb_phy *phy)
{
 int ret;

 ret = ulpi_set_otg_flags(phy);
 if (ret)
  return ret;

 ret = ulpi_set_ic_flags(phy);
 if (ret)
  return ret;

 return ulpi_set_fc_flags(phy);
}

static int ulpi_check_integrity(struct usb_phy *phy)
{
 int ret, i;
 unsigned int val = 0x55;

 for (i = 0; i < 2; i++) {
  ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
  if (ret < 0)
   return ret;

  ret = usb_phy_io_read(phy, ULPI_SCRATCH);
  if (ret < 0)
   return ret;

  if (ret != val) {
   pr_err("ULPI integrity check: failed!");
   return -ENODEV;
  }
  val = val << 1;
 }

 pr_info("ULPI integrity check: passed.\n");

 return 0;
}

static int ulpi_init(struct usb_phy *phy)
{
 int i, vid, pid, ret;
 u32 ulpi_id = 0;

 for (i = 0; i < 4; i++) {
  ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
  if (ret < 0)
   return ret;
  ulpi_id = (ulpi_id << 8) | ret;
 }
 vid = ulpi_id & 0xffff;
 pid = ulpi_id >> 16;

 pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);

 for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) {
  if (ulpi_ids[i].id == ULPI_ID(vid, pid)) {
   pr_info("Found %s ULPI transceiver.\n",
    ulpi_ids[i].name);
   break;
  }
 }

 ret = ulpi_check_integrity(phy);
 if (ret)
  return ret;

 return ulpi_set_flags(phy);
}

static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
{
 struct usb_phy *phy = otg->usb_phy;
 unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);

 if (!host) {
  otg->host = NULL;
  return 0;
 }

 otg->host = host;

 flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE |
     ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
     ULPI_IFC_CTRL_CARKITMODE);

 if (phy->flags & ULPI_IC_6PIN_SERIAL)
  flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
 else if (phy->flags & ULPI_IC_3PIN_SERIAL)
  flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
 else if (phy->flags & ULPI_IC_CARKIT)
  flags |= ULPI_IFC_CTRL_CARKITMODE;

 return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
}

static int ulpi_set_vbus(struct usb_otg *otg, bool on)
{
 struct usb_phy *phy = otg->usb_phy;
 unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);

 flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);

 if (on) {
  if (phy->flags & ULPI_OTG_DRVVBUS)
   flags |= ULPI_OTG_CTRL_DRVVBUS;

  if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
   flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
 }

 return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
}

static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
     struct usb_phy_io_ops *ops,
     unsigned int flags)
{
 phy->label = "ULPI";
 phy->flags = flags;
 phy->io_ops = ops;
 phy->otg = otg;
 phy->init = ulpi_init;

 otg->usb_phy = phy;
 otg->set_host = ulpi_set_host;
 otg->set_vbus = ulpi_set_vbus;
}

struct usb_phy *
devm_otg_ulpi_create(struct device *dev,
       struct usb_phy_io_ops *ops,
       unsigned int flags)
{
 struct usb_phy *phy;
 struct usb_otg *otg;

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

 otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
 if (!otg) {
  devm_kfree(dev, phy);
  return NULL;
 }

 otg_ulpi_init(phy, otg, ops, flags);

 return phy;
}
EXPORT_SYMBOL_GPL(devm_otg_ulpi_create);

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

¤ 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.0.8Bemerkung:  (vorverarbeitet)  ¤

*Bot Zugriff






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.