Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Mellanox hotplug driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2016-2020 Mellanox Technologies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/hwmon-sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/platform_data/mlxreg.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/string_helpers.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) /* Offset of event and mask registers from status register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #define MLXREG_HOTPLUG_EVENT_OFF	1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #define MLXREG_HOTPLUG_MASK_OFF		2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #define MLXREG_HOTPLUG_AGGR_MASK_OFF	1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) /* ASIC good health mask. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define MLXREG_HOTPLUG_GOOD_HEALTH_MASK	0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define MLXREG_HOTPLUG_ATTRS_MAX	24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define MLXREG_HOTPLUG_NOT_ASSERT	3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  * struct mlxreg_hotplug_priv_data - platform private data:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  * @irq: platform device interrupt number;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  * @dev: basic device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  * @pdev: platform device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * @plat: platform data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * @regmap: register map handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  * @dwork_irq: delayed work template;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * @lock: spin lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * @hwmon: hwmon device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  * @mlxreg_hotplug_attr: sysfs attributes array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * @group: sysfs attribute group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  * @groups: list of sysfs attribute group for hwmon registration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  * @cell: location of top aggregation interrupt register;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  * @mask: top aggregation interrupt common mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50)  * @aggr_cache: last value of aggregation register status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)  * @after_probe: flag indication probing completion;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)  * @not_asserted: number of entries in workqueue with no signal assertion;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) struct mlxreg_hotplug_priv_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	struct platform_device *pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	struct mlxreg_hotplug_platform_data *plat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	struct delayed_work dwork_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	spinlock_t lock; /* sync with interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	struct device *hwmon;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	struct sensor_device_attribute_2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 			mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	struct attribute_group group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	const struct attribute_group *groups[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	u32 cell;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	u32 aggr_cache;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	bool after_probe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	u8 not_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) /* Environment variables array for udev. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) mlxreg_hotplug_udev_event_send(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 			       struct mlxreg_core_data *data, bool action)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	mlxreg_hotplug_udev_envp[0] = event_str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	string_upper(label, data->label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 					struct mlxreg_core_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	/* Notify user by sending hwmon uevent. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	 * Return if adapter number is negative. It could be in case hotplug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	 * event is not associated with hotplug device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	if (data->hpdev.nr < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 					      pdata->shift_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	if (!data->hpdev.adapter) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		dev_err(priv->dev, "Failed to get adapter for bus %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 			data->hpdev.nr + pdata->shift_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	client = i2c_new_client_device(data->hpdev.adapter,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 				       data->hpdev.brdinfo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	if (IS_ERR(client)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 			data->hpdev.brdinfo->type, data->hpdev.nr +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 			pdata->shift_nr, data->hpdev.brdinfo->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		i2c_put_adapter(data->hpdev.adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		data->hpdev.adapter = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		return PTR_ERR(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	data->hpdev.client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 			      struct mlxreg_core_data *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	/* Notify user by sending hwmon uevent. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	if (data->hpdev.client) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		i2c_unregister_device(data->hpdev.client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		data->hpdev.client = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	if (data->hpdev.adapter) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		i2c_put_adapter(data->hpdev.adapter);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		data->hpdev.adapter = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 					struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 					char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	int index = to_sensor_dev_attr_2(attr)->index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	int nr = to_sensor_dev_attr_2(attr)->nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	struct mlxreg_core_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	struct mlxreg_core_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	u32 regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	item = pdata->items + nr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	data = item->data + index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	ret = regmap_read(priv->regmap, data->reg, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	if (item->health) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		regval &= data->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		/* Bit = 0 : functional if item->inversed is true. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		if (item->inversed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 			regval = !(regval & data->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 			regval = !!(regval & data->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	return sprintf(buf, "%u\n", regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	struct mlxreg_core_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	struct mlxreg_core_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	unsigned long mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	u32 regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	int num_attrs = 0, id = 0, i, j, k, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	item = pdata->items;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	/* Go over all kinds of items - psu, pwr, fan. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	for (i = 0; i < pdata->counter; i++, item++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		if (item->capability) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 			 * Read group capability register to get actual number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			 * of interrupt capable components and set group mask
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 			 * accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			ret = regmap_read(priv->regmap, item->capability,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 					  &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 			if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 				return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 			item->mask = GENMASK((regval & item->mask) - 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		data = item->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		/* Go over all unmasked units within item. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		mask = item->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		k = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		for_each_set_bit(j, &mask, item->count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 			if (data->capability) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 				 * Read capability register and skip non
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 				 * relevant attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 				ret = regmap_read(priv->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 						  data->capability, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 				if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 					return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 				if (!(regval & data->bit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 					data++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 					continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 				}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 			PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 			PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 							     GFP_KERNEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 							     data->label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 			if (!PRIV_ATTR(id)->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 				dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 					id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 				return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 			PRIV_DEV_ATTR(id).dev_attr.attr.name =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 							PRIV_ATTR(id)->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 			PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 			PRIV_DEV_ATTR(id).dev_attr.show =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 						mlxreg_hotplug_attr_show;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			PRIV_DEV_ATTR(id).nr = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			PRIV_DEV_ATTR(id).index = k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 			sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 			data++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 			id++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 			k++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 		num_attrs += k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 					 num_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 					 sizeof(struct attribute *),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 					 GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	if (!priv->group.attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	priv->group.attrs = priv->mlxreg_hotplug_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	priv->groups[0] = &priv->group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	priv->groups[1] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 			   struct mlxreg_core_item *item)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	struct mlxreg_core_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	unsigned long asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	u32 regval, bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	 * Validate if item related to received signal type is valid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	 * It should never happen, excepted the situation when some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	 * piece of hardware is broken. In such situation just produce
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 	 * error message and return. Caller must continue to handle the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	 * signals from other devices if any.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	if (unlikely(!item)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 			item->reg, item->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	/* Mask event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 			   0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	/* Read status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	ret = regmap_read(priv->regmap, item->reg, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	/* Set asserted bits and save last status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	regval &= item->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	asserted = item->cache ^ regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	item->cache = regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	for_each_set_bit(bit, &asserted, 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 		data = item->data + bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		if (regval & BIT(bit)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			if (item->inversed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 				mlxreg_hotplug_device_destroy(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 				mlxreg_hotplug_device_create(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 			if (item->inversed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 				mlxreg_hotplug_device_create(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 				mlxreg_hotplug_device_destroy(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	/* Acknowledge event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 			   0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	/* Unmask event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 			   item->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 		dev_err(priv->dev, "Failed to complete workqueue.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 				  struct mlxreg_core_item *item)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	struct mlxreg_core_data *data = item->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	u32 regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 	int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	for (i = 0; i < item->count; i++, data++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 		/* Mask event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 		ret = regmap_write(priv->regmap, data->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 				   MLXREG_HOTPLUG_MASK_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		/* Read status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		ret = regmap_read(priv->regmap, data->reg, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		regval &= data->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		if (item->cache == regval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			goto ack_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		 * ASIC health indication is provided through two bits. Bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 		 * value 0x2 indicates that ASIC reached the good health, value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		 * 0x0 indicates ASIC the bad health or dormant state and value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 		 * 0x3 indicates the booting state. During ASIC reset it should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 		 * pass the following states: dormant -> booting -> good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 		if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 			if (!data->attached) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 				 * ASIC is in steady state. Connect associated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 				 * device, if configured.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 				mlxreg_hotplug_device_create(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 				data->attached = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 			if (data->attached) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 				/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 				 * ASIC health is failed after ASIC has been
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 				 * in steady state. Disconnect associated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 				 * device, if it has been connected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 				 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 				mlxreg_hotplug_device_destroy(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 				data->attached = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 				data->health_cntr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		item->cache = regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ack_event:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 		/* Acknowledge event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		ret = regmap_write(priv->regmap, data->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 				   MLXREG_HOTPLUG_EVENT_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 		/* Unmask event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		ret = regmap_write(priv->regmap, data->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 				   MLXREG_HOTPLUG_MASK_OFF, data->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 		dev_err(priv->dev, "Failed to complete workqueue.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)  * mlxreg_hotplug_work_handler - performs traversing of device interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)  * registers according to the below hierarchy schema:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)  *				Aggregation registers (status/mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)  * PSU registers:		*---*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)  * |status/event/mask|----->    | * |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)  * Power registers:		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)  * |status/event/mask|----->    | * |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432)  * FAN registers:		|   |--> CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)  * |status/event/mask|----->    | * |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)  * ASIC registers:		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)  * |status/event/mask|----->    | * |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)  * *-----------------*		|   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)  *				*---*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)  * In case some system changed are detected: FAN in/out, PSU in/out, power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)  * cable attached/detached, ASIC health good/bad, relevant device is created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)  * or destroyed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) static void mlxreg_hotplug_work_handler(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	struct mlxreg_hotplug_priv_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 	struct mlxreg_core_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	u32 regval, aggr_asserted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 	int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	priv = container_of(work, struct mlxreg_hotplug_priv_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 			    dwork_irq.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 	item = pdata->items;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	/* Mask aggregation event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	ret = regmap_write(priv->regmap, pdata->cell +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 			   MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	/* Read aggregation status. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	ret = regmap_read(priv->regmap, pdata->cell, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 	regval &= pdata->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	aggr_asserted = priv->aggr_cache ^ regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	priv->aggr_cache = regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	 * Handler is invoked, but no assertion is detected at top aggregation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	 * status level. Set aggr_asserted to mask value to allow handler extra
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	 * run over all relevant signals to recover any missed signal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		priv->not_asserted = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 		aggr_asserted = pdata->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	if (!aggr_asserted)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 		goto unmask_event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	/* Handle topology and health configuration changes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	for (i = 0; i < pdata->counter; i++, item++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 		if (aggr_asserted & item->aggr_mask) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 			if (item->health)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 				mlxreg_hotplug_health_work_helper(priv, item);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 			else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 				mlxreg_hotplug_work_helper(priv, item);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	spin_lock_irqsave(&priv->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	 * It is possible, that some signals have been inserted, while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	 * interrupt has been masked by mlxreg_hotplug_work_handler. In this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	 * case such signals will be missed. In order to handle these signals
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	 * delayed work is canceled and work task re-scheduled for immediate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	 * execution. It allows to handle missed signals, if any. In other case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	 * work handler just validates that no new signals have been received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	 * during masking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	cancel_delayed_work(&priv->dwork_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	schedule_delayed_work(&priv->dwork_irq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	spin_unlock_irqrestore(&priv->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) unmask_event:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	priv->not_asserted++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	/* Unmask aggregation event (no need acknowledge). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	ret = regmap_write(priv->regmap, pdata->cell +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 		dev_err(priv->dev, "Failed to complete workqueue.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	struct mlxreg_core_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	struct mlxreg_core_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	u32 regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	int i, j, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	item = pdata->items;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	for (i = 0; i < pdata->counter; i++, item++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 		/* Clear group presense event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 		ret = regmap_write(priv->regmap, item->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 				   MLXREG_HOTPLUG_EVENT_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		 * Verify if hardware configuration requires to disable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 		 * interrupt capability for some of components.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 		data = item->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 		for (j = 0; j < item->count; j++, data++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 			/* Verify if the attribute has capability register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 			if (data->capability) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 				/* Read capability register. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 				ret = regmap_read(priv->regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 						  data->capability, &regval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 				if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 					goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 				if (!(regval & data->bit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 					item->mask &= ~BIT(j);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		/* Set group initial status as mask and unmask group event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 		if (item->inversed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 			item->cache = item->mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 			ret = regmap_write(priv->regmap, item->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 					   MLXREG_HOTPLUG_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 					   item->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 			if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 				goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 	/* Keep aggregation initial status as zero and unmask events. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	ret = regmap_write(priv->regmap, pdata->cell +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 	/* Keep low aggregation initial status as zero and unmask events. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	if (pdata->cell_low) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 		ret = regmap_write(priv->regmap, pdata->cell_low +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 				   MLXREG_HOTPLUG_AGGR_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 				   pdata->mask_low);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 			goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 	/* Invoke work handler for initializing hot plug devices setting. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 		dev_err(priv->dev, "Failed to set interrupts.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	enable_irq(priv->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 	struct mlxreg_core_item *item;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 	struct mlxreg_core_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	int count, i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 	pdata = dev_get_platdata(&priv->pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) 	item = pdata->items;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	disable_irq(priv->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 	cancel_delayed_work_sync(&priv->dwork_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	/* Mask low aggregation event, if defined. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	if (pdata->cell_low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 		regmap_write(priv->regmap, pdata->cell_low +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 			     MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	/* Mask aggregation event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) 	regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 		     0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 	/* Clear topology configurations. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) 	for (i = 0; i < pdata->counter; i++, item++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 		data = item->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 		/* Mask group presense event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 		regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 			     0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 		/* Clear group presense event. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 		regmap_write(priv->regmap, data->reg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 			     MLXREG_HOTPLUG_EVENT_OFF, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 		/* Remove all the attached devices in group. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 		count = item->count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 		for (j = 0; j < count; j++, data++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 			mlxreg_hotplug_device_destroy(priv, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 	struct mlxreg_hotplug_priv_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 	priv = (struct mlxreg_hotplug_priv_data *)dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 	/* Schedule work task for immediate execution.*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 	schedule_delayed_work(&priv->dwork_irq, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 	return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static int mlxreg_hotplug_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 	struct mlxreg_core_hotplug_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 	struct mlxreg_hotplug_priv_data *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	struct i2c_adapter *deferred_adap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 	pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 	if (!pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 		dev_err(&pdev->dev, "Failed to get platform data.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 	/* Defer probing if the necessary adapter is not configured yet. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 	deferred_adap = i2c_get_adapter(pdata->deferred_nr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	if (!deferred_adap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 		return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	i2c_put_adapter(deferred_adap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 	if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	if (pdata->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 		priv->irq = pdata->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 		priv->irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 		if (priv->irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 			return priv->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 	priv->regmap = pdata->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 	priv->dev = pdev->dev.parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	priv->pdev = pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 	err = devm_request_irq(&pdev->dev, priv->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 			       mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 			       | IRQF_SHARED, "mlxreg-hotplug", priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 		dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) 	disable_irq(priv->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 	spin_lock_init(&priv->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) 	INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) 	dev_set_drvdata(&pdev->dev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	err = mlxreg_hotplug_attr_init(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 		dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 			err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 	priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 					"mlxreg_hotplug", priv, priv->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 	if (IS_ERR(priv->hwmon)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 		dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 			PTR_ERR(priv->hwmon));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 		return PTR_ERR(priv->hwmon);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 	/* Perform initial interrupts setup. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	mlxreg_hotplug_set_irq(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 	priv->after_probe = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static int mlxreg_hotplug_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 	/* Clean interrupts setup. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 	mlxreg_hotplug_unset_irq(priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	devm_free_irq(&pdev->dev, priv->irq, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) static struct platform_driver mlxreg_hotplug_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 		.name = "mlxreg-hotplug",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 	.probe = mlxreg_hotplug_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 	.remove = mlxreg_hotplug_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) module_platform_driver(mlxreg_hotplug_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) MODULE_LICENSE("Dual BSD/GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) MODULE_ALIAS("platform:mlxreg-hotplug");