Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Mellanox hotplug driver
0004  *
0005  * Copyright (C) 2016-2020 Mellanox Technologies
0006  */
0007 
0008 #include <linux/bitops.h>
0009 #include <linux/device.h>
0010 #include <linux/hwmon.h>
0011 #include <linux/hwmon-sysfs.h>
0012 #include <linux/i2c.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/module.h>
0015 #include <linux/of_device.h>
0016 #include <linux/platform_data/mlxreg.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/spinlock.h>
0019 #include <linux/string_helpers.h>
0020 #include <linux/regmap.h>
0021 #include <linux/workqueue.h>
0022 
0023 /* Offset of event and mask registers from status register. */
0024 #define MLXREG_HOTPLUG_EVENT_OFF    1
0025 #define MLXREG_HOTPLUG_MASK_OFF     2
0026 #define MLXREG_HOTPLUG_AGGR_MASK_OFF    1
0027 
0028 /* ASIC good health mask. */
0029 #define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02
0030 
0031 #define MLXREG_HOTPLUG_ATTRS_MAX    128
0032 #define MLXREG_HOTPLUG_NOT_ASSERT   3
0033 
0034 /**
0035  * struct mlxreg_hotplug_priv_data - platform private data:
0036  * @irq: platform device interrupt number;
0037  * @dev: basic device;
0038  * @pdev: platform device;
0039  * @plat: platform data;
0040  * @regmap: register map handle;
0041  * @dwork_irq: delayed work template;
0042  * @lock: spin lock;
0043  * @hwmon: hwmon device;
0044  * @mlxreg_hotplug_attr: sysfs attributes array;
0045  * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
0046  * @group: sysfs attribute group;
0047  * @groups: list of sysfs attribute group for hwmon registration;
0048  * @cell: location of top aggregation interrupt register;
0049  * @mask: top aggregation interrupt common mask;
0050  * @aggr_cache: last value of aggregation register status;
0051  * @after_probe: flag indication probing completion;
0052  * @not_asserted: number of entries in workqueue with no signal assertion;
0053  */
0054 struct mlxreg_hotplug_priv_data {
0055     int irq;
0056     struct device *dev;
0057     struct platform_device *pdev;
0058     struct mlxreg_hotplug_platform_data *plat;
0059     struct regmap *regmap;
0060     struct delayed_work dwork_irq;
0061     spinlock_t lock; /* sync with interrupt */
0062     struct device *hwmon;
0063     struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
0064     struct sensor_device_attribute_2
0065             mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
0066     struct attribute_group group;
0067     const struct attribute_group *groups[2];
0068     u32 cell;
0069     u32 mask;
0070     u32 aggr_cache;
0071     bool after_probe;
0072     u8 not_asserted;
0073 };
0074 
0075 /* Environment variables array for udev. */
0076 static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
0077 
0078 static int
0079 mlxreg_hotplug_udev_event_send(struct kobject *kobj,
0080                    struct mlxreg_core_data *data, bool action)
0081 {
0082     char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
0083     char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
0084 
0085     mlxreg_hotplug_udev_envp[0] = event_str;
0086     string_upper(label, data->label);
0087     snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
0088 
0089     return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
0090 }
0091 
0092 static void
0093 mlxreg_hotplug_pdata_export(void *pdata, void *regmap)
0094 {
0095     struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata;
0096 
0097     /* Export regmap to underlying device. */
0098     dev_pdata->regmap = regmap;
0099 }
0100 
0101 static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
0102                     struct mlxreg_core_data *data,
0103                     enum mlxreg_hotplug_kind kind)
0104 {
0105     struct i2c_board_info *brdinfo = data->hpdev.brdinfo;
0106     struct mlxreg_core_hotplug_platform_data *pdata;
0107     struct i2c_client *client;
0108 
0109     /* Notify user by sending hwmon uevent. */
0110     mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
0111 
0112     /*
0113      * Return if adapter number is negative. It could be in case hotplug
0114      * event is not associated with hotplug device.
0115      */
0116     if (data->hpdev.nr < 0)
0117         return 0;
0118 
0119     pdata = dev_get_platdata(&priv->pdev->dev);
0120     switch (data->hpdev.action) {
0121     case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
0122         data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
0123                               pdata->shift_nr);
0124         if (!data->hpdev.adapter) {
0125             dev_err(priv->dev, "Failed to get adapter for bus %d\n",
0126                 data->hpdev.nr + pdata->shift_nr);
0127             return -EFAULT;
0128         }
0129 
0130         /* Export platform data to underlying device. */
0131         if (brdinfo->platform_data)
0132             mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap);
0133 
0134         client = i2c_new_client_device(data->hpdev.adapter,
0135                            brdinfo);
0136         if (IS_ERR(client)) {
0137             dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
0138                 brdinfo->type, data->hpdev.nr +
0139                 pdata->shift_nr, brdinfo->addr);
0140 
0141             i2c_put_adapter(data->hpdev.adapter);
0142             data->hpdev.adapter = NULL;
0143             return PTR_ERR(client);
0144         }
0145 
0146         data->hpdev.client = client;
0147         break;
0148     case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
0149         /* Export platform data to underlying device. */
0150         if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data)
0151             mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data,
0152                             pdata->regmap);
0153         /* Pass parent hotplug device handle to underlying device. */
0154         data->notifier = data->hpdev.notifier;
0155         data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev,
0156                                      brdinfo->type,
0157                                      data->hpdev.nr,
0158                                      NULL, 0, data,
0159                                      sizeof(*data));
0160         if (IS_ERR(data->hpdev.pdev))
0161             return PTR_ERR(data->hpdev.pdev);
0162 
0163         break;
0164     default:
0165         break;
0166     }
0167 
0168     if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
0169         return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1);
0170 
0171     return 0;
0172 }
0173 
0174 static void
0175 mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
0176                   struct mlxreg_core_data *data,
0177                   enum mlxreg_hotplug_kind kind)
0178 {
0179     /* Notify user by sending hwmon uevent. */
0180     mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
0181     if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
0182         data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0);
0183 
0184     switch (data->hpdev.action) {
0185     case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
0186         if (data->hpdev.client) {
0187             i2c_unregister_device(data->hpdev.client);
0188             data->hpdev.client = NULL;
0189         }
0190 
0191         if (data->hpdev.adapter) {
0192             i2c_put_adapter(data->hpdev.adapter);
0193             data->hpdev.adapter = NULL;
0194         }
0195         break;
0196     case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
0197         if (data->hpdev.pdev)
0198             platform_device_unregister(data->hpdev.pdev);
0199         break;
0200     default:
0201         break;
0202     }
0203 }
0204 
0205 static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
0206                     struct device_attribute *attr,
0207                     char *buf)
0208 {
0209     struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
0210     struct mlxreg_core_hotplug_platform_data *pdata;
0211     int index = to_sensor_dev_attr_2(attr)->index;
0212     int nr = to_sensor_dev_attr_2(attr)->nr;
0213     struct mlxreg_core_item *item;
0214     struct mlxreg_core_data *data;
0215     u32 regval;
0216     int ret;
0217 
0218     pdata = dev_get_platdata(&priv->pdev->dev);
0219     item = pdata->items + nr;
0220     data = item->data + index;
0221 
0222     ret = regmap_read(priv->regmap, data->reg, &regval);
0223     if (ret)
0224         return ret;
0225 
0226     if (item->health) {
0227         regval &= data->mask;
0228     } else {
0229         /* Bit = 0 : functional if item->inversed is true. */
0230         if (item->inversed)
0231             regval = !(regval & data->mask);
0232         else
0233             regval = !!(regval & data->mask);
0234     }
0235 
0236     return sprintf(buf, "%u\n", regval);
0237 }
0238 
0239 #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
0240 #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
0241 
0242 static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
0243 {
0244     struct mlxreg_core_hotplug_platform_data *pdata;
0245     struct mlxreg_core_item *item;
0246     struct mlxreg_core_data *data;
0247     unsigned long mask;
0248     u32 regval;
0249     int num_attrs = 0, id = 0, i, j, k, ret;
0250 
0251     pdata = dev_get_platdata(&priv->pdev->dev);
0252     item = pdata->items;
0253 
0254     /* Go over all kinds of items - psu, pwr, fan. */
0255     for (i = 0; i < pdata->counter; i++, item++) {
0256         if (item->capability) {
0257             /*
0258              * Read group capability register to get actual number
0259              * of interrupt capable components and set group mask
0260              * accordingly.
0261              */
0262             ret = regmap_read(priv->regmap, item->capability,
0263                       &regval);
0264             if (ret)
0265                 return ret;
0266 
0267             item->mask = GENMASK((regval & item->mask) - 1, 0);
0268         }
0269 
0270         data = item->data;
0271 
0272         /* Go over all unmasked units within item. */
0273         mask = item->mask;
0274         k = 0;
0275         for_each_set_bit(j, &mask, item->count) {
0276             if (data->capability) {
0277                 /*
0278                  * Read capability register and skip non
0279                  * relevant attributes.
0280                  */
0281                 ret = regmap_read(priv->regmap,
0282                           data->capability, &regval);
0283                 if (ret)
0284                     return ret;
0285                 if (!(regval & data->bit)) {
0286                     data++;
0287                     continue;
0288                 }
0289             }
0290             PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
0291             PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
0292                                  GFP_KERNEL,
0293                                  data->label);
0294 
0295             if (!PRIV_ATTR(id)->name) {
0296                 dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
0297                     id);
0298                 return -ENOMEM;
0299             }
0300 
0301             PRIV_DEV_ATTR(id).dev_attr.attr.name =
0302                             PRIV_ATTR(id)->name;
0303             PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
0304             PRIV_DEV_ATTR(id).dev_attr.show =
0305                         mlxreg_hotplug_attr_show;
0306             PRIV_DEV_ATTR(id).nr = i;
0307             PRIV_DEV_ATTR(id).index = k;
0308             sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
0309             data++;
0310             id++;
0311             k++;
0312         }
0313         num_attrs += k;
0314     }
0315 
0316     priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
0317                      num_attrs,
0318                      sizeof(struct attribute *),
0319                      GFP_KERNEL);
0320     if (!priv->group.attrs)
0321         return -ENOMEM;
0322 
0323     priv->group.attrs = priv->mlxreg_hotplug_attr;
0324     priv->groups[0] = &priv->group;
0325     priv->groups[1] = NULL;
0326 
0327     return 0;
0328 }
0329 
0330 static void
0331 mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
0332                struct mlxreg_core_item *item)
0333 {
0334     struct mlxreg_core_data *data;
0335     unsigned long asserted;
0336     u32 regval, bit;
0337     int ret;
0338 
0339     /*
0340      * Validate if item related to received signal type is valid.
0341      * It should never happen, excepted the situation when some
0342      * piece of hardware is broken. In such situation just produce
0343      * error message and return. Caller must continue to handle the
0344      * signals from other devices if any.
0345      */
0346     if (unlikely(!item)) {
0347         dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
0348             item->reg, item->mask);
0349 
0350         return;
0351     }
0352 
0353     /* Mask event. */
0354     ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
0355                0);
0356     if (ret)
0357         goto out;
0358 
0359     /* Read status. */
0360     ret = regmap_read(priv->regmap, item->reg, &regval);
0361     if (ret)
0362         goto out;
0363 
0364     /* Set asserted bits and save last status. */
0365     regval &= item->mask;
0366     asserted = item->cache ^ regval;
0367     item->cache = regval;
0368 
0369     for_each_set_bit(bit, &asserted, 8) {
0370         data = item->data + bit;
0371         if (regval & BIT(bit)) {
0372             if (item->inversed)
0373                 mlxreg_hotplug_device_destroy(priv, data, item->kind);
0374             else
0375                 mlxreg_hotplug_device_create(priv, data, item->kind);
0376         } else {
0377             if (item->inversed)
0378                 mlxreg_hotplug_device_create(priv, data, item->kind);
0379             else
0380                 mlxreg_hotplug_device_destroy(priv, data, item->kind);
0381         }
0382     }
0383 
0384     /* Acknowledge event. */
0385     ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
0386                0);
0387     if (ret)
0388         goto out;
0389 
0390     /* Unmask event. */
0391     ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
0392                item->mask);
0393 
0394  out:
0395     if (ret)
0396         dev_err(priv->dev, "Failed to complete workqueue.\n");
0397 }
0398 
0399 static void
0400 mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
0401                   struct mlxreg_core_item *item)
0402 {
0403     struct mlxreg_core_data *data = item->data;
0404     u32 regval;
0405     int i, ret = 0;
0406 
0407     for (i = 0; i < item->count; i++, data++) {
0408         /* Mask event. */
0409         ret = regmap_write(priv->regmap, data->reg +
0410                    MLXREG_HOTPLUG_MASK_OFF, 0);
0411         if (ret)
0412             goto out;
0413 
0414         /* Read status. */
0415         ret = regmap_read(priv->regmap, data->reg, &regval);
0416         if (ret)
0417             goto out;
0418 
0419         regval &= data->mask;
0420 
0421         if (item->cache == regval)
0422             goto ack_event;
0423 
0424         /*
0425          * ASIC health indication is provided through two bits. Bits
0426          * value 0x2 indicates that ASIC reached the good health, value
0427          * 0x0 indicates ASIC the bad health or dormant state and value
0428          * 0x3 indicates the booting state. During ASIC reset it should
0429          * pass the following states: dormant -> booting -> good.
0430          */
0431         if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
0432             if (!data->attached) {
0433                 /*
0434                  * ASIC is in steady state. Connect associated
0435                  * device, if configured.
0436                  */
0437                 mlxreg_hotplug_device_create(priv, data, item->kind);
0438                 data->attached = true;
0439             }
0440         } else {
0441             if (data->attached) {
0442                 /*
0443                  * ASIC health is failed after ASIC has been
0444                  * in steady state. Disconnect associated
0445                  * device, if it has been connected.
0446                  */
0447                 mlxreg_hotplug_device_destroy(priv, data, item->kind);
0448                 data->attached = false;
0449                 data->health_cntr = 0;
0450             }
0451         }
0452         item->cache = regval;
0453 ack_event:
0454         /* Acknowledge event. */
0455         ret = regmap_write(priv->regmap, data->reg +
0456                    MLXREG_HOTPLUG_EVENT_OFF, 0);
0457         if (ret)
0458             goto out;
0459 
0460         /* Unmask event. */
0461         ret = regmap_write(priv->regmap, data->reg +
0462                    MLXREG_HOTPLUG_MASK_OFF, data->mask);
0463         if (ret)
0464             goto out;
0465     }
0466 
0467  out:
0468     if (ret)
0469         dev_err(priv->dev, "Failed to complete workqueue.\n");
0470 }
0471 
0472 /*
0473  * mlxreg_hotplug_work_handler - performs traversing of device interrupt
0474  * registers according to the below hierarchy schema:
0475  *
0476  *              Aggregation registers (status/mask)
0477  * PSU registers:       *---*
0478  * *-----------------*      |   |
0479  * |status/event/mask|----->    | * |
0480  * *-----------------*      |   |
0481  * Power registers:     |   |
0482  * *-----------------*      |   |
0483  * |status/event/mask|----->    | * |
0484  * *-----------------*      |   |
0485  * FAN registers:       |   |--> CPU
0486  * *-----------------*      |   |
0487  * |status/event/mask|----->    | * |
0488  * *-----------------*      |   |
0489  * ASIC registers:      |   |
0490  * *-----------------*      |   |
0491  * |status/event/mask|----->    | * |
0492  * *-----------------*      |   |
0493  *              *---*
0494  *
0495  * In case some system changed are detected: FAN in/out, PSU in/out, power
0496  * cable attached/detached, ASIC health good/bad, relevant device is created
0497  * or destroyed.
0498  */
0499 static void mlxreg_hotplug_work_handler(struct work_struct *work)
0500 {
0501     struct mlxreg_core_hotplug_platform_data *pdata;
0502     struct mlxreg_hotplug_priv_data *priv;
0503     struct mlxreg_core_item *item;
0504     u32 regval, aggr_asserted;
0505     unsigned long flags;
0506     int i, ret;
0507 
0508     priv = container_of(work, struct mlxreg_hotplug_priv_data,
0509                 dwork_irq.work);
0510     pdata = dev_get_platdata(&priv->pdev->dev);
0511     item = pdata->items;
0512 
0513     /* Mask aggregation event. */
0514     ret = regmap_write(priv->regmap, pdata->cell +
0515                MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
0516     if (ret < 0)
0517         goto out;
0518 
0519     /* Read aggregation status. */
0520     ret = regmap_read(priv->regmap, pdata->cell, &regval);
0521     if (ret)
0522         goto out;
0523 
0524     regval &= pdata->mask;
0525     aggr_asserted = priv->aggr_cache ^ regval;
0526     priv->aggr_cache = regval;
0527 
0528     /*
0529      * Handler is invoked, but no assertion is detected at top aggregation
0530      * status level. Set aggr_asserted to mask value to allow handler extra
0531      * run over all relevant signals to recover any missed signal.
0532      */
0533     if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
0534         priv->not_asserted = 0;
0535         aggr_asserted = pdata->mask;
0536     }
0537     if (!aggr_asserted)
0538         goto unmask_event;
0539 
0540     /* Handle topology and health configuration changes. */
0541     for (i = 0; i < pdata->counter; i++, item++) {
0542         if (aggr_asserted & item->aggr_mask) {
0543             if (item->health)
0544                 mlxreg_hotplug_health_work_helper(priv, item);
0545             else
0546                 mlxreg_hotplug_work_helper(priv, item);
0547         }
0548     }
0549 
0550     spin_lock_irqsave(&priv->lock, flags);
0551 
0552     /*
0553      * It is possible, that some signals have been inserted, while
0554      * interrupt has been masked by mlxreg_hotplug_work_handler. In this
0555      * case such signals will be missed. In order to handle these signals
0556      * delayed work is canceled and work task re-scheduled for immediate
0557      * execution. It allows to handle missed signals, if any. In other case
0558      * work handler just validates that no new signals have been received
0559      * during masking.
0560      */
0561     cancel_delayed_work(&priv->dwork_irq);
0562     schedule_delayed_work(&priv->dwork_irq, 0);
0563 
0564     spin_unlock_irqrestore(&priv->lock, flags);
0565 
0566     return;
0567 
0568 unmask_event:
0569     priv->not_asserted++;
0570     /* Unmask aggregation event (no need acknowledge). */
0571     ret = regmap_write(priv->regmap, pdata->cell +
0572                MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
0573 
0574  out:
0575     if (ret)
0576         dev_err(priv->dev, "Failed to complete workqueue.\n");
0577 }
0578 
0579 static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
0580 {
0581     struct mlxreg_core_hotplug_platform_data *pdata;
0582     struct mlxreg_core_item *item;
0583     struct mlxreg_core_data *data;
0584     u32 regval;
0585     int i, j, ret;
0586 
0587     pdata = dev_get_platdata(&priv->pdev->dev);
0588     item = pdata->items;
0589 
0590     for (i = 0; i < pdata->counter; i++, item++) {
0591         /* Clear group presense event. */
0592         ret = regmap_write(priv->regmap, item->reg +
0593                    MLXREG_HOTPLUG_EVENT_OFF, 0);
0594         if (ret)
0595             goto out;
0596 
0597         /*
0598          * Verify if hardware configuration requires to disable
0599          * interrupt capability for some of components.
0600          */
0601         data = item->data;
0602         for (j = 0; j < item->count; j++, data++) {
0603             /* Verify if the attribute has capability register. */
0604             if (data->capability) {
0605                 /* Read capability register. */
0606                 ret = regmap_read(priv->regmap,
0607                           data->capability, &regval);
0608                 if (ret)
0609                     goto out;
0610 
0611                 if (!(regval & data->bit))
0612                     item->mask &= ~BIT(j);
0613             }
0614         }
0615 
0616         /* Set group initial status as mask and unmask group event. */
0617         if (item->inversed) {
0618             item->cache = item->mask;
0619             ret = regmap_write(priv->regmap, item->reg +
0620                        MLXREG_HOTPLUG_MASK_OFF,
0621                        item->mask);
0622             if (ret)
0623                 goto out;
0624         }
0625     }
0626 
0627     /* Keep aggregation initial status as zero and unmask events. */
0628     ret = regmap_write(priv->regmap, pdata->cell +
0629                MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
0630     if (ret)
0631         goto out;
0632 
0633     /* Keep low aggregation initial status as zero and unmask events. */
0634     if (pdata->cell_low) {
0635         ret = regmap_write(priv->regmap, pdata->cell_low +
0636                    MLXREG_HOTPLUG_AGGR_MASK_OFF,
0637                    pdata->mask_low);
0638         if (ret)
0639             goto out;
0640     }
0641 
0642     /* Invoke work handler for initializing hot plug devices setting. */
0643     mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
0644 
0645  out:
0646     if (ret)
0647         dev_err(priv->dev, "Failed to set interrupts.\n");
0648     enable_irq(priv->irq);
0649     return ret;
0650 }
0651 
0652 static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
0653 {
0654     struct mlxreg_core_hotplug_platform_data *pdata;
0655     struct mlxreg_core_item *item;
0656     struct mlxreg_core_data *data;
0657     int count, i, j;
0658 
0659     pdata = dev_get_platdata(&priv->pdev->dev);
0660     item = pdata->items;
0661     disable_irq(priv->irq);
0662     cancel_delayed_work_sync(&priv->dwork_irq);
0663 
0664     /* Mask low aggregation event, if defined. */
0665     if (pdata->cell_low)
0666         regmap_write(priv->regmap, pdata->cell_low +
0667                  MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
0668 
0669     /* Mask aggregation event. */
0670     regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
0671              0);
0672 
0673     /* Clear topology configurations. */
0674     for (i = 0; i < pdata->counter; i++, item++) {
0675         data = item->data;
0676         /* Mask group presense event. */
0677         regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
0678                  0);
0679         /* Clear group presense event. */
0680         regmap_write(priv->regmap, data->reg +
0681                  MLXREG_HOTPLUG_EVENT_OFF, 0);
0682 
0683         /* Remove all the attached devices in group. */
0684         count = item->count;
0685         for (j = 0; j < count; j++, data++)
0686             mlxreg_hotplug_device_destroy(priv, data, item->kind);
0687     }
0688 }
0689 
0690 static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
0691 {
0692     struct mlxreg_hotplug_priv_data *priv;
0693 
0694     priv = (struct mlxreg_hotplug_priv_data *)dev;
0695 
0696     /* Schedule work task for immediate execution.*/
0697     schedule_delayed_work(&priv->dwork_irq, 0);
0698 
0699     return IRQ_HANDLED;
0700 }
0701 
0702 static int mlxreg_hotplug_probe(struct platform_device *pdev)
0703 {
0704     struct mlxreg_core_hotplug_platform_data *pdata;
0705     struct mlxreg_hotplug_priv_data *priv;
0706     struct i2c_adapter *deferred_adap;
0707     int err;
0708 
0709     pdata = dev_get_platdata(&pdev->dev);
0710     if (!pdata) {
0711         dev_err(&pdev->dev, "Failed to get platform data.\n");
0712         return -EINVAL;
0713     }
0714 
0715     /* Defer probing if the necessary adapter is not configured yet. */
0716     deferred_adap = i2c_get_adapter(pdata->deferred_nr);
0717     if (!deferred_adap)
0718         return -EPROBE_DEFER;
0719     i2c_put_adapter(deferred_adap);
0720 
0721     priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0722     if (!priv)
0723         return -ENOMEM;
0724 
0725     if (pdata->irq) {
0726         priv->irq = pdata->irq;
0727     } else {
0728         priv->irq = platform_get_irq(pdev, 0);
0729         if (priv->irq < 0)
0730             return priv->irq;
0731     }
0732 
0733     priv->regmap = pdata->regmap;
0734     priv->dev = pdev->dev.parent;
0735     priv->pdev = pdev;
0736 
0737     err = devm_request_irq(&pdev->dev, priv->irq,
0738                    mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
0739                    | IRQF_SHARED, "mlxreg-hotplug", priv);
0740     if (err) {
0741         dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
0742         return err;
0743     }
0744 
0745     disable_irq(priv->irq);
0746     spin_lock_init(&priv->lock);
0747     INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
0748     dev_set_drvdata(&pdev->dev, priv);
0749 
0750     err = mlxreg_hotplug_attr_init(priv);
0751     if (err) {
0752         dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
0753             err);
0754         return err;
0755     }
0756 
0757     priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
0758                     "mlxreg_hotplug", priv, priv->groups);
0759     if (IS_ERR(priv->hwmon)) {
0760         dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
0761             PTR_ERR(priv->hwmon));
0762         return PTR_ERR(priv->hwmon);
0763     }
0764 
0765     /* Perform initial interrupts setup. */
0766     mlxreg_hotplug_set_irq(priv);
0767     priv->after_probe = true;
0768 
0769     return 0;
0770 }
0771 
0772 static int mlxreg_hotplug_remove(struct platform_device *pdev)
0773 {
0774     struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
0775 
0776     /* Clean interrupts setup. */
0777     mlxreg_hotplug_unset_irq(priv);
0778     devm_free_irq(&pdev->dev, priv->irq, priv);
0779 
0780     return 0;
0781 }
0782 
0783 static struct platform_driver mlxreg_hotplug_driver = {
0784     .driver = {
0785         .name = "mlxreg-hotplug",
0786     },
0787     .probe = mlxreg_hotplug_probe,
0788     .remove = mlxreg_hotplug_remove,
0789 };
0790 
0791 module_platform_driver(mlxreg_hotplug_driver);
0792 
0793 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
0794 MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
0795 MODULE_LICENSE("Dual BSD/GPL");
0796 MODULE_ALIAS("platform:mlxreg-hotplug");