drivers/clocksource/timer-tegra.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/timer-tegra.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/timer-tegra.c
Extension
.c
Size
10490 bytes
Lines
416
Domain
Driver Families
Bucket
drivers/clocksource
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

switch (cpu) {
		case 0:
			return TIMER1_BASE;
		case 1:
			return TIMER2_BASE;
		case 2:
			return TIMER3_BASE;
		default:
			return TIMER4_BASE;
		}
	}

	return TIMER10_BASE + cpu * 8;
}

static inline unsigned int tegra_irq_idx_for_cpu(int cpu, bool tegra20)
{
	if (tegra20)
		return TIMER1_IRQ_IDX + cpu;

	return TIMER10_IRQ_IDX + cpu;
}

static inline unsigned long tegra_rate_for_timer(struct timer_of *to,
						 bool tegra20)
{
	/*
	 * TIMER1-9 are fixed to 1MHz, TIMER10-13 are running off the
	 * parent clock.
	 */
	if (tegra20)
		return TIMER_1MHz;

	return timer_of_rate(to);
}

static int __init tegra_init_timer(struct device_node *np, bool tegra20,
				   int rating)
{
	struct timer_of *to;
	int cpu, ret;

	to = this_cpu_ptr(&tegra_to);
	ret = timer_of_init(np, to);
	if (ret)
		goto out;

	timer_reg_base = timer_of_base(to);

	/*
	 * Configure microsecond timers to have 1MHz clock
	 * Config register is 0xqqww, where qq is "dividend", ww is "divisor"
	 * Uses n+1 scheme
	 */
	switch (timer_of_rate(to)) {
	case 12000000:
		usec_config = 0x000b; /* (11+1)/(0+1) */
		break;
	case 12800000:
		usec_config = 0x043f; /* (63+1)/(4+1) */
		break;
	case 13000000:
		usec_config = 0x000c; /* (12+1)/(0+1) */
		break;
	case 16800000:
		usec_config = 0x0453; /* (83+1)/(4+1) */
		break;
	case 19200000:
		usec_config = 0x045f; /* (95+1)/(4+1) */
		break;
	case 26000000:
		usec_config = 0x0019; /* (25+1)/(0+1) */
		break;
	case 38400000:
		usec_config = 0x04bf; /* (191+1)/(4+1) */
		break;
	case 48000000:
		usec_config = 0x002f; /* (47+1)/(0+1) */
		break;
	default:
		ret = -EINVAL;
		goto out;
	}

	writel_relaxed(usec_config, timer_reg_base + TIMERUS_USEC_CFG);

	for_each_possible_cpu(cpu) {
		struct timer_of *cpu_to = per_cpu_ptr(&tegra_to, cpu);
		unsigned long flags = IRQF_TIMER | IRQF_NOBALANCING;
		unsigned long rate = tegra_rate_for_timer(to, tegra20);

Annotation

Implementation Notes