^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, ®val);
^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) ®val);
^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, ®val);
^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, ®val);
^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, ®val);
^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, ®val);
^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, ®val);
^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");