forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 072de836f53be56a70cecf70b43ae43b7ce17376
kernel/drivers/platform/mellanox/mlxreg-hotplug.c
....@@ -1,34 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0+
12 /*
2
- * Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved.
3
- * Copyright (c) 2016-2018 Vadim Pasternak <vadimp@mellanox.com>
3
+ * Mellanox hotplug driver
44 *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * 1. Redistributions of source code must retain the above copyright
9
- * notice, this list of conditions and the following disclaimer.
10
- * 2. Redistributions in binary form must reproduce the above copyright
11
- * notice, this list of conditions and the following disclaimer in the
12
- * documentation and/or other materials provided with the distribution.
13
- * 3. Neither the names of the copyright holders nor the names of its
14
- * contributors may be used to endorse or promote products derived from
15
- * this software without specific prior written permission.
16
- *
17
- * Alternatively, this software may be distributed under the terms of the
18
- * GNU General Public License ("GPL") version 2 as published by the Free
19
- * Software Foundation.
20
- *
21
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
- * POSSIBILITY OF SUCH DAMAGE.
5
+ * Copyright (C) 2016-2020 Mellanox Technologies
326 */
337
348 #include <linux/bitops.h>
....@@ -42,6 +16,7 @@
4216 #include <linux/platform_data/mlxreg.h>
4317 #include <linux/platform_device.h>
4418 #include <linux/spinlock.h>
19
+#include <linux/string_helpers.h>
4520 #include <linux/regmap.h>
4621 #include <linux/workqueue.h>
4722
....@@ -97,13 +72,31 @@
9772 u8 not_asserted;
9873 };
9974
75
+/* Environment variables array for udev. */
76
+static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
77
+
78
+static int
79
+mlxreg_hotplug_udev_event_send(struct kobject *kobj,
80
+ struct mlxreg_core_data *data, bool action)
81
+{
82
+ char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
83
+ char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
84
+
85
+ mlxreg_hotplug_udev_envp[0] = event_str;
86
+ string_upper(label, data->label);
87
+ snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
88
+
89
+ return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
90
+}
91
+
10092 static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
10193 struct mlxreg_core_data *data)
10294 {
10395 struct mlxreg_core_hotplug_platform_data *pdata;
96
+ struct i2c_client *client;
10497
10598 /* Notify user by sending hwmon uevent. */
106
- kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
99
+ mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
107100
108101 /*
109102 * Return if adapter number is negative. It could be in case hotplug
....@@ -121,17 +114,19 @@
121114 return -EFAULT;
122115 }
123116
124
- data->hpdev.client = i2c_new_device(data->hpdev.adapter,
125
- data->hpdev.brdinfo);
126
- if (!data->hpdev.client) {
117
+ client = i2c_new_client_device(data->hpdev.adapter,
118
+ data->hpdev.brdinfo);
119
+ if (IS_ERR(client)) {
127120 dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
128121 data->hpdev.brdinfo->type, data->hpdev.nr +
129122 pdata->shift_nr, data->hpdev.brdinfo->addr);
130123
131124 i2c_put_adapter(data->hpdev.adapter);
132125 data->hpdev.adapter = NULL;
133
- return -EFAULT;
126
+ return PTR_ERR(client);
134127 }
128
+
129
+ data->hpdev.client = client;
135130
136131 return 0;
137132 }
....@@ -141,7 +136,7 @@
141136 struct mlxreg_core_data *data)
142137 {
143138 /* Notify user by sending hwmon uevent. */
144
- kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
139
+ mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
145140
146141 if (data->hpdev.client) {
147142 i2c_unregister_device(data->hpdev.client);
....@@ -196,17 +191,49 @@
196191 struct mlxreg_core_hotplug_platform_data *pdata;
197192 struct mlxreg_core_item *item;
198193 struct mlxreg_core_data *data;
199
- int num_attrs = 0, id = 0, i, j;
194
+ unsigned long mask;
195
+ u32 regval;
196
+ int num_attrs = 0, id = 0, i, j, k, ret;
200197
201198 pdata = dev_get_platdata(&priv->pdev->dev);
202199 item = pdata->items;
203200
204201 /* Go over all kinds of items - psu, pwr, fan. */
205202 for (i = 0; i < pdata->counter; i++, item++) {
206
- num_attrs += item->count;
203
+ if (item->capability) {
204
+ /*
205
+ * Read group capability register to get actual number
206
+ * of interrupt capable components and set group mask
207
+ * accordingly.
208
+ */
209
+ ret = regmap_read(priv->regmap, item->capability,
210
+ &regval);
211
+ if (ret)
212
+ return ret;
213
+
214
+ item->mask = GENMASK((regval & item->mask) - 1, 0);
215
+ }
216
+
207217 data = item->data;
208
- /* Go over all units within the item. */
209
- for (j = 0; j < item->count; j++, data++, id++) {
218
+
219
+ /* Go over all unmasked units within item. */
220
+ mask = item->mask;
221
+ k = 0;
222
+ for_each_set_bit(j, &mask, item->count) {
223
+ if (data->capability) {
224
+ /*
225
+ * Read capability register and skip non
226
+ * relevant attributes.
227
+ */
228
+ ret = regmap_read(priv->regmap,
229
+ data->capability, &regval);
230
+ if (ret)
231
+ return ret;
232
+ if (!(regval & data->bit)) {
233
+ data++;
234
+ continue;
235
+ }
236
+ }
210237 PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
211238 PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
212239 GFP_KERNEL,
....@@ -224,9 +251,13 @@
224251 PRIV_DEV_ATTR(id).dev_attr.show =
225252 mlxreg_hotplug_attr_show;
226253 PRIV_DEV_ATTR(id).nr = i;
227
- PRIV_DEV_ATTR(id).index = j;
254
+ PRIV_DEV_ATTR(id).index = k;
228255 sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
256
+ data++;
257
+ id++;
258
+ k++;
229259 }
260
+ num_attrs += k;
230261 }
231262
232263 priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
....@@ -496,7 +527,9 @@
496527 {
497528 struct mlxreg_core_hotplug_platform_data *pdata;
498529 struct mlxreg_core_item *item;
499
- int i, ret;
530
+ struct mlxreg_core_data *data;
531
+ u32 regval;
532
+ int i, j, ret;
500533
501534 pdata = dev_get_platdata(&priv->pdev->dev);
502535 item = pdata->items;
....@@ -507,6 +540,25 @@
507540 MLXREG_HOTPLUG_EVENT_OFF, 0);
508541 if (ret)
509542 goto out;
543
+
544
+ /*
545
+ * Verify if hardware configuration requires to disable
546
+ * interrupt capability for some of components.
547
+ */
548
+ data = item->data;
549
+ for (j = 0; j < item->count; j++, data++) {
550
+ /* Verify if the attribute has capability register. */
551
+ if (data->capability) {
552
+ /* Read capability register. */
553
+ ret = regmap_read(priv->regmap,
554
+ data->capability, &regval);
555
+ if (ret)
556
+ goto out;
557
+
558
+ if (!(regval & data->bit))
559
+ item->mask &= ~BIT(j);
560
+ }
561
+ }
510562
511563 /* Set group initial status as mask and unmask group event. */
512564 if (item->inversed) {
....@@ -621,11 +673,8 @@
621673 priv->irq = pdata->irq;
622674 } else {
623675 priv->irq = platform_get_irq(pdev, 0);
624
- if (priv->irq < 0) {
625
- dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
626
- priv->irq);
676
+ if (priv->irq < 0)
627677 return priv->irq;
628
- }
629678 }
630679
631680 priv->regmap = pdata->regmap;