drivers/reset/reset-lpc18xx.c

Source file repositories/reference/linux-study-clean/drivers/reset/reset-lpc18xx.c

File Facts

System
Linux kernel
Corpus path
drivers/reset/reset-lpc18xx.c
Extension
.c
Size
5277 bytes
Lines
200
Domain
Driver Families
Bucket
drivers/reset
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 lpc18xx_rgu_data {
	struct reset_controller_dev rcdev;
	struct clk *clk_delay;
	struct clk *clk_reg;
	void __iomem *base;
	spinlock_t lock;
	u32 delay_us;
};

#define to_rgu_data(p) container_of(p, struct lpc18xx_rgu_data, rcdev)

static int lpc18xx_rgu_restart(struct sys_off_data *data)
{
	struct lpc18xx_rgu_data *rc = data->cb_data;

	writel(BIT(LPC18XX_RGU_CORE_RST), rc->base + LPC18XX_RGU_CTRL0);
	mdelay(2000);

	pr_emerg("%s: unable to restart system\n", __func__);

	return NOTIFY_DONE;
}

/*
 * The LPC18xx RGU has mostly self-deasserting resets except for the
 * two reset lines going to the internal Cortex-M0 cores.
 *
 * To prevent the M0 core resets from accidentally getting deasserted
 * status register must be check and bits in control register set to
 * preserve the state.
 */
static int lpc18xx_rgu_setclear_reset(struct reset_controller_dev *rcdev,
				      unsigned long id, bool set)
{
	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
	u32 stat_offset = LPC18XX_RGU_ACTIVE_STATUS0;
	u32 ctrl_offset = LPC18XX_RGU_CTRL0;
	unsigned long flags;
	u32 stat, rst_bit;

	stat_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
	ctrl_offset += (id / LPC18XX_RGU_RESETS_PER_REG) * sizeof(u32);
	rst_bit = 1 << (id % LPC18XX_RGU_RESETS_PER_REG);

	spin_lock_irqsave(&rc->lock, flags);
	stat = ~readl(rc->base + stat_offset);
	if (set)
		writel(stat | rst_bit, rc->base + ctrl_offset);
	else
		writel(stat & ~rst_bit, rc->base + ctrl_offset);
	spin_unlock_irqrestore(&rc->lock, flags);

	return 0;
}

static int lpc18xx_rgu_assert(struct reset_controller_dev *rcdev,
			      unsigned long id)
{
	return lpc18xx_rgu_setclear_reset(rcdev, id, true);
}

static int lpc18xx_rgu_deassert(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	return lpc18xx_rgu_setclear_reset(rcdev, id, false);
}

/* Only M0 cores require explicit reset deassert */
static int lpc18xx_rgu_reset(struct reset_controller_dev *rcdev,
			     unsigned long id)
{
	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);

	lpc18xx_rgu_assert(rcdev, id);
	udelay(rc->delay_us);

	switch (id) {
	case LPC43XX_RGU_M0SUB_RST:
	case LPC43XX_RGU_M0APP_RST:
		lpc18xx_rgu_setclear_reset(rcdev, id, false);
	}

	return 0;
}

static int lpc18xx_rgu_status(struct reset_controller_dev *rcdev,
			      unsigned long id)
{
	struct lpc18xx_rgu_data *rc = to_rgu_data(rcdev);
	u32 bit, offset = LPC18XX_RGU_ACTIVE_STATUS0;

Annotation

Implementation Notes