drivers/phy/broadcom/phy-bcm-cygnus-pcie.c

Source file repositories/reference/linux-study-clean/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/broadcom/phy-bcm-cygnus-pcie.c
Extension
.c
Size
4652 bytes
Lines
202
Domain
Driver Families
Bucket
drivers/phy
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct cygnus_pcie_phy {
	struct cygnus_pcie_phy_core *core;
	enum cygnus_pcie_phy_id id;
	struct phy *phy;
};

/**
 * struct cygnus_pcie_phy_core - Cygnus PCIe PHY core control
 * @dev: pointer to device
 * @base: base register
 * @lock: mutex to protect access to individual PHYs
 * @phys: pointer to Cygnus PHY device
 */
struct cygnus_pcie_phy_core {
	struct device *dev;
	void __iomem *base;
	struct mutex lock;
	struct cygnus_pcie_phy phys[MAX_NUM_PHYS];
};

static int cygnus_pcie_power_config(struct cygnus_pcie_phy *phy, bool enable)
{
	struct cygnus_pcie_phy_core *core = phy->core;
	unsigned shift;
	u32 val;

	mutex_lock(&core->lock);

	switch (phy->id) {
	case CYGNUS_PHY_PCIE0:
		shift = PCIE0_PHY_IDDQ_SHIFT;
		break;

	case CYGNUS_PHY_PCIE1:
		shift = PCIE1_PHY_IDDQ_SHIFT;
		break;

	default:
		mutex_unlock(&core->lock);
		dev_err(core->dev, "PCIe PHY %d invalid\n", phy->id);
		return -EINVAL;
	}

	if (enable) {
		val = readl(core->base + PCIE_CFG_OFFSET);
		val &= ~BIT(shift);
		writel(val, core->base + PCIE_CFG_OFFSET);
		/*
		 * Wait 50 ms for the PCIe Serdes to stabilize after the analog
		 * front end is brought up
		 */
		msleep(50);
	} else {
		val = readl(core->base + PCIE_CFG_OFFSET);
		val |= BIT(shift);
		writel(val, core->base + PCIE_CFG_OFFSET);
	}

	mutex_unlock(&core->lock);
	dev_dbg(core->dev, "PCIe PHY %d %s\n", phy->id,
		enable ? "enabled" : "disabled");
	return 0;
}

static int cygnus_pcie_phy_power_on(struct phy *p)
{
	struct cygnus_pcie_phy *phy = phy_get_drvdata(p);

	return cygnus_pcie_power_config(phy, true);
}

static int cygnus_pcie_phy_power_off(struct phy *p)
{
	struct cygnus_pcie_phy *phy = phy_get_drvdata(p);

	return cygnus_pcie_power_config(phy, false);
}

static const struct phy_ops cygnus_pcie_phy_ops = {
	.power_on = cygnus_pcie_phy_power_on,
	.power_off = cygnus_pcie_phy_power_off,
	.owner = THIS_MODULE,
};

static int cygnus_pcie_phy_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *node = dev->of_node;
	struct cygnus_pcie_phy_core *core;
	struct phy_provider *provider;

Annotation

Implementation Notes