drivers/soc/tegra/fuse/fuse-tegra20.c

Source file repositories/reference/linux-study-clean/drivers/soc/tegra/fuse/fuse-tegra20.c

File Facts

System
Linux kernel
Corpus path
drivers/soc/tegra/fuse/fuse-tegra20.c
Extension
.c
Size
4952 bytes
Lines
199
Domain
Driver Families
Bucket
drivers/soc
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
 *
 * Based on drivers/misc/eeprom/sunxi_sid.c
 */

#include <linux/device.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h>

#include <soc/tegra/fuse.h>

#include "fuse.h"

#define FUSE_BEGIN	0x100
#define FUSE_UID_LOW	0x08
#define FUSE_UID_HIGH	0x0c

static u32 tegra20_fuse_read_early(struct tegra_fuse *fuse, unsigned int offset)
{
	return readl_relaxed(fuse->base + FUSE_BEGIN + offset);
}

static void apb_dma_complete(void *args)
{
	struct tegra_fuse *fuse = args;

	complete(&fuse->apbdma.wait);
}

static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
{
	unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
	struct dma_async_tx_descriptor *dma_desc;
	unsigned long time_left;
	u32 value = 0;
	int err;

	err = pm_runtime_resume_and_get(fuse->dev);
	if (err)
		return err;

	mutex_lock(&fuse->apbdma.lock);

	fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset;

	err = dmaengine_slave_config(fuse->apbdma.chan, &fuse->apbdma.config);
	if (err)
		goto out;

	dma_desc = dmaengine_prep_slave_single(fuse->apbdma.chan,
					       fuse->apbdma.phys,
					       sizeof(u32), DMA_DEV_TO_MEM,
					       flags);
	if (!dma_desc)
		goto out;

	dma_desc->callback = apb_dma_complete;
	dma_desc->callback_param = fuse;

	reinit_completion(&fuse->apbdma.wait);

	dmaengine_submit(dma_desc);
	dma_async_issue_pending(fuse->apbdma.chan);
	time_left = wait_for_completion_timeout(&fuse->apbdma.wait,
						msecs_to_jiffies(50));

	if (WARN(time_left == 0, "apb read dma timed out"))
		dmaengine_terminate_all(fuse->apbdma.chan);
	else
		value = *fuse->apbdma.virt;

out:
	mutex_unlock(&fuse->apbdma.lock);
	pm_runtime_put(fuse->dev);
	return value;
}

static bool dma_filter(struct dma_chan *chan, void *filter_param)

Annotation

Implementation Notes