drivers/phy/phy-pistachio-usb.c

Source file repositories/reference/linux-study-clean/drivers/phy/phy-pistachio-usb.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/phy-pistachio-usb.c
Extension
.c
Size
5121 bytes
Lines
204
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 pistachio_usb_phy {
	struct device *dev;
	struct regmap *cr_top;
	struct clk *phy_clk;
	unsigned int refclk;
};

static const unsigned long fsel_rate_map[] = {
	9600000,
	10000000,
	12000000,
	19200000,
	20000000,
	24000000,
	0,
	50000000,
};

static int pistachio_usb_phy_power_on(struct phy *phy)
{
	struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);
	unsigned long timeout, rate;
	unsigned int i;
	int ret;

	ret = clk_prepare_enable(p_phy->phy_clk);
	if (ret < 0) {
		dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
		return ret;
	}

	regmap_update_bits(p_phy->cr_top, USB_PHY_STRAP_CONTROL,
			   USB_PHY_STRAP_CONTROL_REFCLK_MASK <<
			   USB_PHY_STRAP_CONTROL_REFCLK_SHIFT,
			   p_phy->refclk << USB_PHY_STRAP_CONTROL_REFCLK_SHIFT);

	rate = clk_get_rate(p_phy->phy_clk);
	if (p_phy->refclk == REFCLK_XO_CRYSTAL && rate != 12000000) {
		dev_err(p_phy->dev, "Unsupported rate for XO crystal: %ld\n",
			rate);
		ret = -EINVAL;
		goto disable_clk;
	}

	for (i = 0; i < ARRAY_SIZE(fsel_rate_map); i++) {
		if (rate == fsel_rate_map[i])
			break;
	}
	if (i == ARRAY_SIZE(fsel_rate_map)) {
		dev_err(p_phy->dev, "Unsupported clock rate: %lu\n", rate);
		ret = -EINVAL;
		goto disable_clk;
	}

	regmap_update_bits(p_phy->cr_top, USB_PHY_CONTROL1,
			   USB_PHY_CONTROL1_FSEL_MASK <<
			   USB_PHY_CONTROL1_FSEL_SHIFT,
			   i << USB_PHY_CONTROL1_FSEL_SHIFT);

	timeout = jiffies + msecs_to_jiffies(200);
	while (time_before(jiffies, timeout)) {
		unsigned int val;

		regmap_read(p_phy->cr_top, USB_PHY_STATUS, &val);
		if (val & USB_PHY_STATUS_VBUS_FAULT) {
			dev_err(p_phy->dev, "VBUS fault detected\n");
			ret = -EIO;
			goto disable_clk;
		}
		if ((val & USB_PHY_STATUS_RX_PHY_CLK) &&
		    (val & USB_PHY_STATUS_RX_UTMI_CLK))
			return 0;
		usleep_range(1000, 1500);
	}

	dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n");
	ret = -ETIMEDOUT;

disable_clk:
	clk_disable_unprepare(p_phy->phy_clk);
	return ret;
}

static int pistachio_usb_phy_power_off(struct phy *phy)
{
	struct pistachio_usb_phy *p_phy = phy_get_drvdata(phy);

	clk_disable_unprepare(p_phy->phy_clk);

	return 0;

Annotation

Implementation Notes