drivers/hwmon/pmbus/pmbus_core.c

Source file repositories/reference/linux-study-clean/drivers/hwmon/pmbus/pmbus_core.c

File Facts

System
Linux kernel
Corpus path
drivers/hwmon/pmbus/pmbus_core.c
Extension
.c
Size
96892 bytes
Lines
3860
Domain
Driver Families
Bucket
drivers/hwmon
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations pmbus_debugfs_block_ops = {
	.llseek = noop_llseek,
	.read = pmbus_debugfs_block_read,
	.write = NULL,
	.open = simple_open,
};

static void pmbus_remove_symlink(void *symlink)
{
	debugfs_remove(symlink);
}

struct pmbus_debugfs_data {
	u8 reg;
	u32 flag;
	const char *name;
};

static const struct pmbus_debugfs_data pmbus_debugfs_block_data[] = {
	{ .reg = PMBUS_MFR_ID, .name = "mfr_id" },
	{ .reg = PMBUS_MFR_MODEL, .name = "mfr_model" },
	{ .reg = PMBUS_MFR_REVISION, .name = "mfr_revision" },
	{ .reg = PMBUS_MFR_LOCATION, .name = "mfr_location" },
	{ .reg = PMBUS_MFR_DATE, .name = "mfr_date" },
	{ .reg = PMBUS_MFR_SERIAL, .name = "mfr_serial" },
};

static const struct pmbus_debugfs_data pmbus_debugfs_status_data[] = {
	{ .reg = PMBUS_STATUS_VOUT, .flag = PMBUS_HAVE_STATUS_VOUT, .name = "status%d_vout" },
	{ .reg = PMBUS_STATUS_IOUT, .flag = PMBUS_HAVE_STATUS_IOUT, .name = "status%d_iout" },
	{ .reg = PMBUS_STATUS_INPUT, .flag = PMBUS_HAVE_STATUS_INPUT, .name = "status%d_input" },
	{ .reg = PMBUS_STATUS_TEMPERATURE, .flag = PMBUS_HAVE_STATUS_TEMP,
	  .name = "status%d_temp" },
	{ .reg = PMBUS_STATUS_FAN_12, .flag = PMBUS_HAVE_STATUS_FAN12, .name = "status%d_fan12" },
	{ .reg = PMBUS_STATUS_FAN_34, .flag = PMBUS_HAVE_STATUS_FAN34, .name = "status%d_fan34" },
	{ .reg = PMBUS_STATUS_CML, .name = "status%d_cml" },
	{ .reg = PMBUS_STATUS_OTHER, .name = "status%d_other" },
	{ .reg = PMBUS_STATUS_MFR_SPECIFIC, .name = "status%d_mfr" },
};

static void pmbus_init_debugfs(struct i2c_client *client,
			       struct pmbus_data *data)
{
	struct dentry *symlink_d, *debugfs = client->debugfs;
	struct pmbus_debugfs_entry *entries;
	const char *pathname, *symlink;
	char name[PMBUS_NAME_SIZE];
	int page, i, idx = 0;

	/*
	 * client->debugfs may be NULL or an ERR_PTR(). dentry_path_raw()
	 * does not check if its parameters are valid, so validate
	 * client->debugfs before using it.
	 */
	if (!pmbus_debugfs_dir || IS_ERR_OR_NULL(debugfs))
		return;

	/*
	 * Backwards compatibility: Create symlink from /pmbus/<hwmon_device>
	 * to i2c debugfs directory.
	 */
	pathname = dentry_path_raw(debugfs, name, sizeof(name));
	if (IS_ERR(pathname))
		return;

	/*
	 * The path returned by dentry_path_raw() starts with '/'. Prepend it
	 * with ".." to get the symlink relative to the pmbus root directory.
	 */
	symlink = kasprintf(GFP_KERNEL, "..%s", pathname);
	if (!symlink)
		return;

	symlink_d = debugfs_create_symlink(dev_name(data->hwmon_dev),
					   pmbus_debugfs_dir, symlink);
	kfree(symlink);

	devm_add_action_or_reset(data->dev, pmbus_remove_symlink, symlink_d);

	/*
	 * Allocate the max possible entries we need.
	 * device specific:
	 *	ARRAY_SIZE(pmbus_debugfs_block_data) + 2
	 * page specific:
	 *	ARRAY_SIZE(pmbus_debugfs_status_data) + 1
	 */
	entries = devm_kcalloc(data->dev,
			       ARRAY_SIZE(pmbus_debugfs_block_data) + 2 +
			       data->info->pages * (ARRAY_SIZE(pmbus_debugfs_status_data) + 1),
			       sizeof(*entries), GFP_KERNEL);

Annotation

Implementation Notes