drivers/clk/sunxi/clk-sun9i-mmc.c

Source file repositories/reference/linux-study-clean/drivers/clk/sunxi/clk-sun9i-mmc.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/sunxi/clk-sun9i-mmc.c
Extension
.c
Size
4957 bytes
Lines
203
Domain
Driver Families
Bucket
drivers/clk
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 sun9i_mmc_clk_data {
	spinlock_t			lock;
	void __iomem			*membase;
	struct clk			*clk;
	struct reset_control		*reset;
	struct clk_onecell_data		clk_data;
	struct reset_controller_dev	rcdev;
};

static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
			      unsigned long id)
{
	struct sun9i_mmc_clk_data *data = container_of(rcdev,
						       struct sun9i_mmc_clk_data,
						       rcdev);
	unsigned long flags;
	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
	u32 val;

	clk_prepare_enable(data->clk);
	spin_lock_irqsave(&data->lock, flags);

	val = readl(reg);
	writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);

	spin_unlock_irqrestore(&data->lock, flags);
	clk_disable_unprepare(data->clk);

	return 0;
}

static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
				unsigned long id)
{
	struct sun9i_mmc_clk_data *data = container_of(rcdev,
						       struct sun9i_mmc_clk_data,
						       rcdev);
	unsigned long flags;
	void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
	u32 val;

	clk_prepare_enable(data->clk);
	spin_lock_irqsave(&data->lock, flags);

	val = readl(reg);
	writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);

	spin_unlock_irqrestore(&data->lock, flags);
	clk_disable_unprepare(data->clk);

	return 0;
}

static int sun9i_mmc_reset_reset(struct reset_controller_dev *rcdev,
				 unsigned long id)
{
	sun9i_mmc_reset_assert(rcdev, id);
	udelay(10);
	sun9i_mmc_reset_deassert(rcdev, id);

	return 0;
}

static const struct reset_control_ops sun9i_mmc_reset_ops = {
	.assert		= sun9i_mmc_reset_assert,
	.deassert	= sun9i_mmc_reset_deassert,
	.reset		= sun9i_mmc_reset_reset,
};

static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct sun9i_mmc_clk_data *data;
	struct clk_onecell_data *clk_data;
	const char *clk_name = np->name;
	const char *clk_parent;
	struct resource *r;
	int count, i, ret;

	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	spin_lock_init(&data->lock);

	data->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
	if (IS_ERR(data->membase))
		return PTR_ERR(data->membase);

	/* one clock/reset pair per word */

Annotation

Implementation Notes