drivers/rtc/rtc-armada38x.c

Source file repositories/reference/linux-study-clean/drivers/rtc/rtc-armada38x.c

File Facts

System
Linux kernel
Corpus path
drivers/rtc/rtc-armada38x.c
Extension
.c
Size
15492 bytes
Lines
581
Domain
Driver Families
Bucket
drivers/rtc
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 value_to_freq {
	u32 value;
	u8 freq;
};

struct armada38x_rtc {
	struct rtc_device   *rtc_dev;
	void __iomem	    *regs;
	void __iomem	    *regs_soc;
	spinlock_t	    lock;
	int		    irq;
	bool		    initialized;
	const struct armada38x_rtc_data *data;
	struct value_to_freq val_to_freq[];
};

#define ALARM1	0
#define ALARM2	1

#define ALARM_REG(base, alarm)	 ((base) + (alarm) * sizeof(u32))

struct armada38x_rtc_data {
	/* Initialize the RTC-MBUS bridge timing */
	void (*update_mbus_timing)(struct armada38x_rtc *rtc);
	u32 (*read_rtc_reg)(struct armada38x_rtc *rtc, u8 rtc_reg);
	void (*clear_isr)(struct armada38x_rtc *rtc);
	void (*unmask_interrupt)(struct armada38x_rtc *rtc);
	u32 alarm;
};

/*
 * According to the datasheet, the OS should wait 5us after every
 * register write to the RTC hard macro so that the required update
 * can occur without holding off the system bus
 * According to errata RES-3124064, Write to any RTC register
 * may fail. As a workaround, before writing to RTC
 * register, issue a dummy write of 0x0 twice to RTC Status
 * register.
 */

static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
{
	writel(0, rtc->regs + RTC_STATUS);
	writel(0, rtc->regs + RTC_STATUS);
	writel(val, rtc->regs + offset);
	udelay(5);
}

/* Update RTC-MBUS bridge timing parameters */
static void rtc_update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
{
	u32 reg;

	reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
	reg &= ~RTC_38X_PERIOD_MASK;
	reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
	reg &= ~RTC_38X_READ_DELAY_MASK;
	reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
	writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
}

static void rtc_update_8k_mbus_timing_params(struct armada38x_rtc *rtc)
{
	u32 reg;

	reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0);
	reg &= ~RTC_8K_WRCLK_PERIOD_MASK;
	reg |= 0x3FF << RTC_8K_WRCLK_PERIOD_OFFS;
	reg &= ~RTC_8K_WRCLK_SETUP_MASK;
	reg |= 0x29 << RTC_8K_WRCLK_SETUP_OFFS;
	writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0);

	reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1);
	reg &= ~RTC_8K_READ_DELAY_MASK;
	reg |= 0x3F << RTC_8K_READ_DELAY_OFFS;
	writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1);
}

static u32 read_rtc_register(struct armada38x_rtc *rtc, u8 rtc_reg)
{
	return readl(rtc->regs + rtc_reg);
}

static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
{
	int i, index_max = 0, max = 0;

	for (i = 0; i < SAMPLE_NR; i++) {
		rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg);
		rtc->val_to_freq[i].freq = 0;

Annotation

Implementation Notes