drivers/usb/dwc3/dwc3-octeon.c

Source file repositories/reference/linux-study-clean/drivers/usb/dwc3/dwc3-octeon.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/dwc3/dwc3-octeon.c
Extension
.c
Size
16913 bytes
Lines
535
Domain
Driver Families
Bucket
drivers/usb
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 dwc3_octeon {
	struct device *dev;
	void __iomem *base;
};

#define DWC3_GPIO_POWER_NONE	(-1)

#ifdef CONFIG_CAVIUM_OCTEON_SOC
#include <asm/octeon/octeon.h>
static inline uint64_t dwc3_octeon_readq(void __iomem *addr)
{
	return cvmx_readq_csr(addr);
}

static inline void dwc3_octeon_writeq(void __iomem *base, uint64_t val)
{
	cvmx_writeq_csr(base, val);
}

static void dwc3_octeon_config_gpio(int index, int gpio)
{
	union cvmx_gpio_bit_cfgx gpio_bit;

	if ((OCTEON_IS_MODEL(OCTEON_CN73XX) ||
	    OCTEON_IS_MODEL(OCTEON_CNF75XX))
	    && gpio <= 31) {
		gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
		gpio_bit.s.tx_oe = 1;
		gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x15);
		cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
	} else if (gpio <= 15) {
		gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(gpio));
		gpio_bit.s.tx_oe = 1;
		gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x19);
		cvmx_write_csr(CVMX_GPIO_BIT_CFGX(gpio), gpio_bit.u64);
	} else {
		gpio_bit.u64 = cvmx_read_csr(CVMX_GPIO_XBIT_CFGX(gpio));
		gpio_bit.s.tx_oe = 1;
		gpio_bit.s.output_sel = (index == 0 ? 0x14 : 0x19);
		cvmx_write_csr(CVMX_GPIO_XBIT_CFGX(gpio), gpio_bit.u64);
	}
}
#else
static inline uint64_t dwc3_octeon_readq(void __iomem *addr)
{
	return 0;
}

static inline void dwc3_octeon_writeq(void __iomem *base, uint64_t val) { }

static inline void dwc3_octeon_config_gpio(int index, int gpio) { }

static uint64_t octeon_get_io_clock_rate(void)
{
	return 150000000;
}
#endif

static int dwc3_octeon_get_divider(void)
{
	static const uint8_t clk_div[] = { 1, 2, 4, 6, 8, 16, 24, 32 };
	int div = 0;

	while (div < ARRAY_SIZE(clk_div)) {
		uint64_t rate = octeon_get_io_clock_rate() / clk_div[div];
		if (rate <= 300000000 && rate >= 150000000)
			return div;
		div++;
	}

	return -EINVAL;
}

static int dwc3_octeon_setup(struct dwc3_octeon *octeon,
			     int ref_clk_sel, int ref_clk_fsel, int mpll_mul,
			     int power_gpio, int power_active_low)
{
	u64 val;
	int div;
	struct device *dev = octeon->dev;
	void __iomem *uctl_ctl_reg = octeon->base + USBDRD_UCTL_CTL;
	void __iomem *uctl_host_cfg_reg = octeon->base + USBDRD_UCTL_HOST_CFG;

	/*
	 * Step 1: Wait for all voltages to be stable...that surely
	 *         happened before starting the kernel. SKIP
	 */

	/* Step 2: Select GPIO for overcurrent indication, if desired. SKIP */

Annotation

Implementation Notes