Lines Matching +full:irq +full:- +full:signals

1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright (C) 2016-2020 Mellanox Technologies
11 #include <linux/hwmon-sysfs.h>
34 * struct mlxreg_hotplug_priv_data - platform private data:
35 * @irq: platform device interrupt number;
54 int irq; member
85 string_upper(label, data->label); in mlxreg_hotplug_udev_event_send()
97 dev_pdata->regmap = regmap; in mlxreg_hotplug_pdata_export()
104 struct i2c_board_info *brdinfo = data->hpdev.brdinfo; in mlxreg_hotplug_device_create()
109 mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true); in mlxreg_hotplug_device_create()
115 if (data->hpdev.nr < 0 && data->hpdev.action != MLXREG_HOTPLUG_DEVICE_NO_ACTION) in mlxreg_hotplug_device_create()
118 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_device_create()
119 switch (data->hpdev.action) { in mlxreg_hotplug_device_create()
121 data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + in mlxreg_hotplug_device_create()
122 pdata->shift_nr); in mlxreg_hotplug_device_create()
123 if (!data->hpdev.adapter) { in mlxreg_hotplug_device_create()
124 dev_err(priv->dev, "Failed to get adapter for bus %d\n", in mlxreg_hotplug_device_create()
125 data->hpdev.nr + pdata->shift_nr); in mlxreg_hotplug_device_create()
126 return -EFAULT; in mlxreg_hotplug_device_create()
130 if (brdinfo->platform_data) in mlxreg_hotplug_device_create()
131 mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap); in mlxreg_hotplug_device_create()
133 client = i2c_new_client_device(data->hpdev.adapter, in mlxreg_hotplug_device_create()
136 dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", in mlxreg_hotplug_device_create()
137 brdinfo->type, data->hpdev.nr + in mlxreg_hotplug_device_create()
138 pdata->shift_nr, brdinfo->addr); in mlxreg_hotplug_device_create()
140 i2c_put_adapter(data->hpdev.adapter); in mlxreg_hotplug_device_create()
141 data->hpdev.adapter = NULL; in mlxreg_hotplug_device_create()
145 data->hpdev.client = client; in mlxreg_hotplug_device_create()
149 if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data) in mlxreg_hotplug_device_create()
150 mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data, in mlxreg_hotplug_device_create()
151 pdata->regmap); in mlxreg_hotplug_device_create()
153 data->notifier = data->hpdev.notifier; in mlxreg_hotplug_device_create()
154 data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev, in mlxreg_hotplug_device_create()
155 brdinfo->type, in mlxreg_hotplug_device_create()
156 data->hpdev.nr, in mlxreg_hotplug_device_create()
159 if (IS_ERR(data->hpdev.pdev)) in mlxreg_hotplug_device_create()
160 return PTR_ERR(data->hpdev.pdev); in mlxreg_hotplug_device_create()
167 if (data->hpdev.notifier && data->hpdev.notifier->user_handler) in mlxreg_hotplug_device_create()
168 return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1); in mlxreg_hotplug_device_create()
179 mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false); in mlxreg_hotplug_device_destroy()
180 if (data->hpdev.notifier && data->hpdev.notifier->user_handler) in mlxreg_hotplug_device_destroy()
181 data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0); in mlxreg_hotplug_device_destroy()
183 switch (data->hpdev.action) { in mlxreg_hotplug_device_destroy()
185 if (data->hpdev.client) { in mlxreg_hotplug_device_destroy()
186 i2c_unregister_device(data->hpdev.client); in mlxreg_hotplug_device_destroy()
187 data->hpdev.client = NULL; in mlxreg_hotplug_device_destroy()
190 if (data->hpdev.adapter) { in mlxreg_hotplug_device_destroy()
191 i2c_put_adapter(data->hpdev.adapter); in mlxreg_hotplug_device_destroy()
192 data->hpdev.adapter = NULL; in mlxreg_hotplug_device_destroy()
196 if (data->hpdev.pdev) in mlxreg_hotplug_device_destroy()
197 platform_device_unregister(data->hpdev.pdev); in mlxreg_hotplug_device_destroy()
210 int index = to_sensor_dev_attr_2(attr)->index; in mlxreg_hotplug_attr_show()
211 int nr = to_sensor_dev_attr_2(attr)->nr; in mlxreg_hotplug_attr_show()
217 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_attr_show()
218 item = pdata->items + nr; in mlxreg_hotplug_attr_show()
219 data = item->data + index; in mlxreg_hotplug_attr_show()
221 ret = regmap_read(priv->regmap, data->reg, &regval); in mlxreg_hotplug_attr_show()
225 if (item->health) { in mlxreg_hotplug_attr_show()
226 regval &= data->mask; in mlxreg_hotplug_attr_show()
228 /* Bit = 0 : functional if item->inversed is true. */ in mlxreg_hotplug_attr_show()
229 if (item->inversed) in mlxreg_hotplug_attr_show()
230 regval = !(regval & data->mask); in mlxreg_hotplug_attr_show()
232 regval = !!(regval & data->mask); in mlxreg_hotplug_attr_show()
238 #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
239 #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
245 for (i = 0, j = -1; i <= bit; i++) { in mlxreg_hotplug_item_label_index_get()
261 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_attr_init()
262 item = pdata->items; in mlxreg_hotplug_attr_init()
264 /* Go over all kinds of items - psu, pwr, fan. */ in mlxreg_hotplug_attr_init()
265 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_attr_init()
266 if (item->capability) { in mlxreg_hotplug_attr_init()
272 ret = regmap_read(priv->regmap, item->capability, in mlxreg_hotplug_attr_init()
277 item->mask = GENMASK((regval & item->mask) - 1, 0); in mlxreg_hotplug_attr_init()
280 data = item->data; in mlxreg_hotplug_attr_init()
283 mask = item->mask; in mlxreg_hotplug_attr_init()
285 count = item->ind ? item->ind : item->count; in mlxreg_hotplug_attr_init()
287 if (data->capability) { in mlxreg_hotplug_attr_init()
292 ret = regmap_read(priv->regmap, in mlxreg_hotplug_attr_init()
293 data->capability, &regval); in mlxreg_hotplug_attr_init()
297 if (!(regval & data->bit)) { in mlxreg_hotplug_attr_init()
304 PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, in mlxreg_hotplug_attr_init()
306 data->label); in mlxreg_hotplug_attr_init()
307 if (!PRIV_ATTR(id)->name) { in mlxreg_hotplug_attr_init()
308 dev_err(priv->dev, "Memory allocation failed for attr %d.\n", in mlxreg_hotplug_attr_init()
310 return -ENOMEM; in mlxreg_hotplug_attr_init()
314 PRIV_ATTR(id)->name; in mlxreg_hotplug_attr_init()
328 priv->group.attrs = devm_kcalloc(&priv->pdev->dev, in mlxreg_hotplug_attr_init()
332 if (!priv->group.attrs) in mlxreg_hotplug_attr_init()
333 return -ENOMEM; in mlxreg_hotplug_attr_init()
335 priv->group.attrs = priv->mlxreg_hotplug_attr; in mlxreg_hotplug_attr_init()
336 priv->groups[0] = &priv->group; in mlxreg_hotplug_attr_init()
337 priv->groups[1] = NULL; in mlxreg_hotplug_attr_init()
352 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
358 ret = regmap_read(priv->regmap, item->reg, &regval); in mlxreg_hotplug_work_helper()
363 regval &= item->mask; in mlxreg_hotplug_work_helper()
364 asserted = item->cache ^ regval; in mlxreg_hotplug_work_helper()
365 item->cache = regval; in mlxreg_hotplug_work_helper()
369 pos = mlxreg_hotplug_item_label_index_get(item->mask, bit); in mlxreg_hotplug_work_helper()
373 data = item->data + pos; in mlxreg_hotplug_work_helper()
375 if (item->inversed) in mlxreg_hotplug_work_helper()
376 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_work_helper()
378 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_work_helper()
380 if (item->inversed) in mlxreg_hotplug_work_helper()
381 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_work_helper()
383 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_work_helper()
388 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, in mlxreg_hotplug_work_helper()
394 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
395 item->mask); in mlxreg_hotplug_work_helper()
399 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_helper()
406 struct mlxreg_core_data *data = item->data; in mlxreg_hotplug_health_work_helper()
410 for (i = 0; i < item->count; i++, data++) { in mlxreg_hotplug_health_work_helper()
412 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
418 ret = regmap_read(priv->regmap, data->reg, &regval); in mlxreg_hotplug_health_work_helper()
422 regval &= data->mask; in mlxreg_hotplug_health_work_helper()
424 if (item->cache == regval) in mlxreg_hotplug_health_work_helper()
432 * pass the following states: dormant -> booting -> good. in mlxreg_hotplug_health_work_helper()
435 if (!data->attached) { in mlxreg_hotplug_health_work_helper()
440 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_health_work_helper()
441 data->attached = true; in mlxreg_hotplug_health_work_helper()
444 if (data->attached) { in mlxreg_hotplug_health_work_helper()
450 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_health_work_helper()
451 data->attached = false; in mlxreg_hotplug_health_work_helper()
452 data->health_cntr = 0; in mlxreg_hotplug_health_work_helper()
455 item->cache = regval; in mlxreg_hotplug_health_work_helper()
458 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
464 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
465 MLXREG_HOTPLUG_MASK_OFF, data->mask); in mlxreg_hotplug_health_work_helper()
472 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_health_work_helper()
476 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
480 * PSU registers: *---*
481 * *-----------------* | |
482 * |status/event/mask|-----> | * |
483 * *-----------------* | |
485 * *-----------------* | |
486 * |status/event/mask|-----> | * |
487 * *-----------------* | |
488 * FAN registers: | |--> CPU
489 * *-----------------* | |
490 * |status/event/mask|-----> | * |
491 * *-----------------* | |
493 * *-----------------* | |
494 * |status/event/mask|-----> | * |
495 * *-----------------* | |
496 * *---*
513 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_work_handler()
514 item = pdata->items; in mlxreg_hotplug_work_handler()
517 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
523 ret = regmap_read(priv->regmap, pdata->cell, &regval); in mlxreg_hotplug_work_handler()
527 regval &= pdata->mask; in mlxreg_hotplug_work_handler()
528 aggr_asserted = priv->aggr_cache ^ regval; in mlxreg_hotplug_work_handler()
529 priv->aggr_cache = regval; in mlxreg_hotplug_work_handler()
534 * run over all relevant signals to recover any missed signal. in mlxreg_hotplug_work_handler()
536 if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { in mlxreg_hotplug_work_handler()
537 priv->not_asserted = 0; in mlxreg_hotplug_work_handler()
538 aggr_asserted = pdata->mask; in mlxreg_hotplug_work_handler()
544 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_work_handler()
545 if (aggr_asserted & item->aggr_mask) { in mlxreg_hotplug_work_handler()
546 if (item->health) in mlxreg_hotplug_work_handler()
553 spin_lock_irqsave(&priv->lock, flags); in mlxreg_hotplug_work_handler()
556 * It is possible, that some signals have been inserted, while in mlxreg_hotplug_work_handler()
558 * case such signals will be missed. In order to handle these signals in mlxreg_hotplug_work_handler()
559 * delayed work is canceled and work task re-scheduled for immediate in mlxreg_hotplug_work_handler()
560 * execution. It allows to handle missed signals, if any. In other case in mlxreg_hotplug_work_handler()
561 * work handler just validates that no new signals have been received in mlxreg_hotplug_work_handler()
564 cancel_delayed_work(&priv->dwork_irq); in mlxreg_hotplug_work_handler()
565 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_work_handler()
567 spin_unlock_irqrestore(&priv->lock, flags); in mlxreg_hotplug_work_handler()
572 priv->not_asserted++; in mlxreg_hotplug_work_handler()
574 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
575 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_work_handler()
579 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_handler()
590 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_set_irq()
591 item = pdata->items; in mlxreg_hotplug_set_irq()
593 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_set_irq()
595 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
604 data = item->data; in mlxreg_hotplug_set_irq()
605 for (j = 0; j < item->count; j++, data++) { in mlxreg_hotplug_set_irq()
607 if (data->capability) { in mlxreg_hotplug_set_irq()
609 ret = regmap_read(priv->regmap, in mlxreg_hotplug_set_irq()
610 data->capability, &regval); in mlxreg_hotplug_set_irq()
614 if (!(regval & data->bit)) in mlxreg_hotplug_set_irq()
615 item->mask &= ~BIT(j); in mlxreg_hotplug_set_irq()
620 if (item->inversed) { in mlxreg_hotplug_set_irq()
621 item->cache = item->mask; in mlxreg_hotplug_set_irq()
622 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
624 item->mask); in mlxreg_hotplug_set_irq()
631 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_set_irq()
632 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_set_irq()
637 if (pdata->cell_low) { in mlxreg_hotplug_set_irq()
638 ret = regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_set_irq()
640 pdata->mask_low); in mlxreg_hotplug_set_irq()
646 mlxreg_hotplug_work_handler(&priv->dwork_irq.work); in mlxreg_hotplug_set_irq()
650 dev_err(priv->dev, "Failed to set interrupts.\n"); in mlxreg_hotplug_set_irq()
651 enable_irq(priv->irq); in mlxreg_hotplug_set_irq()
662 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_unset_irq()
663 item = pdata->items; in mlxreg_hotplug_unset_irq()
664 disable_irq(priv->irq); in mlxreg_hotplug_unset_irq()
665 cancel_delayed_work_sync(&priv->dwork_irq); in mlxreg_hotplug_unset_irq()
668 if (pdata->cell_low) in mlxreg_hotplug_unset_irq()
669 regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_unset_irq()
673 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, in mlxreg_hotplug_unset_irq()
677 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_unset_irq()
678 data = item->data; in mlxreg_hotplug_unset_irq()
680 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_unset_irq()
683 regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_unset_irq()
687 count = item->count; in mlxreg_hotplug_unset_irq()
689 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_unset_irq()
693 static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) in mlxreg_hotplug_irq_handler() argument
700 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_irq_handler()
712 pdata = dev_get_platdata(&pdev->dev); in mlxreg_hotplug_probe()
714 dev_err(&pdev->dev, "Failed to get platform data.\n"); in mlxreg_hotplug_probe()
715 return -EINVAL; in mlxreg_hotplug_probe()
719 deferred_adap = i2c_get_adapter(pdata->deferred_nr); in mlxreg_hotplug_probe()
721 return -EPROBE_DEFER; in mlxreg_hotplug_probe()
724 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in mlxreg_hotplug_probe()
726 return -ENOMEM; in mlxreg_hotplug_probe()
728 if (pdata->irq) { in mlxreg_hotplug_probe()
729 priv->irq = pdata->irq; in mlxreg_hotplug_probe()
731 priv->irq = platform_get_irq(pdev, 0); in mlxreg_hotplug_probe()
732 if (priv->irq < 0) in mlxreg_hotplug_probe()
733 return priv->irq; in mlxreg_hotplug_probe()
736 priv->regmap = pdata->regmap; in mlxreg_hotplug_probe()
737 priv->dev = pdev->dev.parent; in mlxreg_hotplug_probe()
738 priv->pdev = pdev; in mlxreg_hotplug_probe()
740 err = devm_request_irq(&pdev->dev, priv->irq, in mlxreg_hotplug_probe()
742 | IRQF_SHARED, "mlxreg-hotplug", priv); in mlxreg_hotplug_probe()
744 dev_err(&pdev->dev, "Failed to request irq: %d\n", err); in mlxreg_hotplug_probe()
748 disable_irq(priv->irq); in mlxreg_hotplug_probe()
749 spin_lock_init(&priv->lock); in mlxreg_hotplug_probe()
750 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); in mlxreg_hotplug_probe()
751 dev_set_drvdata(&pdev->dev, priv); in mlxreg_hotplug_probe()
755 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", in mlxreg_hotplug_probe()
760 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, in mlxreg_hotplug_probe()
761 "mlxreg_hotplug", priv, priv->groups); in mlxreg_hotplug_probe()
762 if (IS_ERR(priv->hwmon)) { in mlxreg_hotplug_probe()
763 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", in mlxreg_hotplug_probe()
764 PTR_ERR(priv->hwmon)); in mlxreg_hotplug_probe()
765 return PTR_ERR(priv->hwmon); in mlxreg_hotplug_probe()
770 priv->after_probe = true; in mlxreg_hotplug_probe()
777 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); in mlxreg_hotplug_remove()
781 devm_free_irq(&pdev->dev, priv->irq, priv); in mlxreg_hotplug_remove()
786 .name = "mlxreg-hotplug",
797 MODULE_ALIAS("platform:mlxreg-hotplug");