drivers/platform/mellanox/mlxreg-hotplug.c

Source file repositories/reference/linux-study-clean/drivers/platform/mellanox/mlxreg-hotplug.c

File Facts

System
Linux kernel
Corpus path
drivers/platform/mellanox/mlxreg-hotplug.c
Extension
.c
Size
21588 bytes
Lines
798
Domain
Driver Families
Bucket
drivers/platform
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 mlxreg_hotplug_priv_data {
	int irq;
	struct device *dev;
	struct platform_device *pdev;
	struct mlxreg_hotplug_platform_data *plat;
	struct regmap *regmap;
	struct delayed_work dwork_irq;
	spinlock_t lock; /* sync with interrupt */
	struct device *hwmon;
	struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
	struct sensor_device_attribute_2
			mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
	struct attribute_group group;
	const struct attribute_group *groups[2];
	u32 cell;
	u32 mask;
	u32 aggr_cache;
	bool after_probe;
	u8 not_asserted;
};

/* Environment variables array for udev. */
static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };

static int
mlxreg_hotplug_udev_event_send(struct kobject *kobj,
			       struct mlxreg_core_data *data, bool action)
{
	char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
	char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };

	mlxreg_hotplug_udev_envp[0] = event_str;
	string_upper(label, data->label);
	snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);

	return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
}

static void
mlxreg_hotplug_pdata_export(void *pdata, void *regmap)
{
	struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata;

	/* Export regmap to underlying device. */
	dev_pdata->regmap = regmap;
}

static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
					struct mlxreg_core_data *data,
					enum mlxreg_hotplug_kind kind)
{
	struct i2c_board_info *brdinfo = data->hpdev.brdinfo;
	struct mlxreg_core_hotplug_platform_data *pdata;
	struct i2c_client *client;

	/* Notify user by sending hwmon uevent. */
	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);

	/*
	 * Return if adapter number is negative. It could be in case hotplug
	 * event is not associated with hotplug device.
	 */
	if (data->hpdev.nr < 0 && data->hpdev.action != MLXREG_HOTPLUG_DEVICE_NO_ACTION)
		return 0;

	pdata = dev_get_platdata(&priv->pdev->dev);
	switch (data->hpdev.action) {
	case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
		data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
						      pdata->shift_nr);
		if (!data->hpdev.adapter) {
			dev_err(priv->dev, "Failed to get adapter for bus %d\n",
				data->hpdev.nr + pdata->shift_nr);
			return -EFAULT;
		}

		/* Export platform data to underlying device. */
		if (brdinfo->platform_data)
			mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap);

		client = i2c_new_client_device(data->hpdev.adapter,
					       brdinfo);
		if (IS_ERR(client)) {
			dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
				brdinfo->type, data->hpdev.nr +
				pdata->shift_nr, brdinfo->addr);

			i2c_put_adapter(data->hpdev.adapter);
			data->hpdev.adapter = NULL;
			return PTR_ERR(client);

Annotation

Implementation Notes