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, ®val); 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, ®val); 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()
356 * signals from other devices if any. in mlxreg_hotplug_work_helper()
359 dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n", in mlxreg_hotplug_work_helper()
360 item->reg, item->mask); in mlxreg_hotplug_work_helper()
366 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
372 ret = regmap_read(priv->regmap, item->reg, ®val); in mlxreg_hotplug_work_helper()
377 regval &= item->mask; in mlxreg_hotplug_work_helper()
378 asserted = item->cache ^ regval; in mlxreg_hotplug_work_helper()
379 item->cache = regval; in mlxreg_hotplug_work_helper()
383 pos = mlxreg_hotplug_item_label_index_get(item->mask, bit); in mlxreg_hotplug_work_helper()
387 data = item->data + pos; in mlxreg_hotplug_work_helper()
389 if (item->inversed) in mlxreg_hotplug_work_helper()
390 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_work_helper()
392 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_work_helper()
394 if (item->inversed) in mlxreg_hotplug_work_helper()
395 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_work_helper()
397 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_work_helper()
402 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, in mlxreg_hotplug_work_helper()
408 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
409 item->mask); in mlxreg_hotplug_work_helper()
413 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_helper()
420 struct mlxreg_core_data *data = item->data; in mlxreg_hotplug_health_work_helper()
424 for (i = 0; i < item->count; i++, data++) { in mlxreg_hotplug_health_work_helper()
426 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
432 ret = regmap_read(priv->regmap, data->reg, ®val); in mlxreg_hotplug_health_work_helper()
436 regval &= data->mask; in mlxreg_hotplug_health_work_helper()
438 if (item->cache == regval) in mlxreg_hotplug_health_work_helper()
446 * pass the following states: dormant -> booting -> good. in mlxreg_hotplug_health_work_helper()
449 if (!data->attached) { in mlxreg_hotplug_health_work_helper()
454 mlxreg_hotplug_device_create(priv, data, item->kind); in mlxreg_hotplug_health_work_helper()
455 data->attached = true; in mlxreg_hotplug_health_work_helper()
458 if (data->attached) { in mlxreg_hotplug_health_work_helper()
464 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_health_work_helper()
465 data->attached = false; in mlxreg_hotplug_health_work_helper()
466 data->health_cntr = 0; in mlxreg_hotplug_health_work_helper()
469 item->cache = regval; in mlxreg_hotplug_health_work_helper()
472 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
478 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
479 MLXREG_HOTPLUG_MASK_OFF, data->mask); in mlxreg_hotplug_health_work_helper()
486 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_health_work_helper()
490 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
494 * PSU registers: *---*
495 * *-----------------* | |
496 * |status/event/mask|-----> | * |
497 * *-----------------* | |
499 * *-----------------* | |
500 * |status/event/mask|-----> | * |
501 * *-----------------* | |
502 * FAN registers: | |--> CPU
503 * *-----------------* | |
504 * |status/event/mask|-----> | * |
505 * *-----------------* | |
507 * *-----------------* | |
508 * |status/event/mask|-----> | * |
509 * *-----------------* | |
510 * *---*
527 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_work_handler()
528 item = pdata->items; in mlxreg_hotplug_work_handler()
531 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
537 ret = regmap_read(priv->regmap, pdata->cell, ®val); in mlxreg_hotplug_work_handler()
541 regval &= pdata->mask; in mlxreg_hotplug_work_handler()
542 aggr_asserted = priv->aggr_cache ^ regval; in mlxreg_hotplug_work_handler()
543 priv->aggr_cache = regval; in mlxreg_hotplug_work_handler()
548 * run over all relevant signals to recover any missed signal. in mlxreg_hotplug_work_handler()
550 if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { in mlxreg_hotplug_work_handler()
551 priv->not_asserted = 0; in mlxreg_hotplug_work_handler()
552 aggr_asserted = pdata->mask; in mlxreg_hotplug_work_handler()
558 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_work_handler()
559 if (aggr_asserted & item->aggr_mask) { in mlxreg_hotplug_work_handler()
560 if (item->health) in mlxreg_hotplug_work_handler()
567 spin_lock_irqsave(&priv->lock, flags); in mlxreg_hotplug_work_handler()
570 * It is possible, that some signals have been inserted, while in mlxreg_hotplug_work_handler()
572 * case such signals will be missed. In order to handle these signals in mlxreg_hotplug_work_handler()
573 * delayed work is canceled and work task re-scheduled for immediate in mlxreg_hotplug_work_handler()
574 * execution. It allows to handle missed signals, if any. In other case in mlxreg_hotplug_work_handler()
575 * work handler just validates that no new signals have been received in mlxreg_hotplug_work_handler()
578 cancel_delayed_work(&priv->dwork_irq); in mlxreg_hotplug_work_handler()
579 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_work_handler()
581 spin_unlock_irqrestore(&priv->lock, flags); in mlxreg_hotplug_work_handler()
586 priv->not_asserted++; in mlxreg_hotplug_work_handler()
588 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
589 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_work_handler()
593 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_handler()
604 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_set_irq()
605 item = pdata->items; in mlxreg_hotplug_set_irq()
607 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_set_irq()
609 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
618 data = item->data; in mlxreg_hotplug_set_irq()
619 for (j = 0; j < item->count; j++, data++) { in mlxreg_hotplug_set_irq()
621 if (data->capability) { in mlxreg_hotplug_set_irq()
623 ret = regmap_read(priv->regmap, in mlxreg_hotplug_set_irq()
624 data->capability, ®val); in mlxreg_hotplug_set_irq()
628 if (!(regval & data->bit)) in mlxreg_hotplug_set_irq()
629 item->mask &= ~BIT(j); in mlxreg_hotplug_set_irq()
634 if (item->inversed) { in mlxreg_hotplug_set_irq()
635 item->cache = item->mask; in mlxreg_hotplug_set_irq()
636 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
638 item->mask); in mlxreg_hotplug_set_irq()
645 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_set_irq()
646 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_set_irq()
651 if (pdata->cell_low) { in mlxreg_hotplug_set_irq()
652 ret = regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_set_irq()
654 pdata->mask_low); in mlxreg_hotplug_set_irq()
660 mlxreg_hotplug_work_handler(&priv->dwork_irq.work); in mlxreg_hotplug_set_irq()
664 dev_err(priv->dev, "Failed to set interrupts.\n"); in mlxreg_hotplug_set_irq()
665 enable_irq(priv->irq); in mlxreg_hotplug_set_irq()
676 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_unset_irq()
677 item = pdata->items; in mlxreg_hotplug_unset_irq()
678 disable_irq(priv->irq); in mlxreg_hotplug_unset_irq()
679 cancel_delayed_work_sync(&priv->dwork_irq); in mlxreg_hotplug_unset_irq()
682 if (pdata->cell_low) in mlxreg_hotplug_unset_irq()
683 regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_unset_irq()
687 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, in mlxreg_hotplug_unset_irq()
691 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_unset_irq()
692 data = item->data; in mlxreg_hotplug_unset_irq()
694 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_unset_irq()
697 regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_unset_irq()
701 count = item->count; in mlxreg_hotplug_unset_irq()
703 mlxreg_hotplug_device_destroy(priv, data, item->kind); in mlxreg_hotplug_unset_irq()
707 static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) in mlxreg_hotplug_irq_handler() argument
714 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_irq_handler()
726 pdata = dev_get_platdata(&pdev->dev); in mlxreg_hotplug_probe()
728 dev_err(&pdev->dev, "Failed to get platform data.\n"); in mlxreg_hotplug_probe()
729 return -EINVAL; in mlxreg_hotplug_probe()
733 deferred_adap = i2c_get_adapter(pdata->deferred_nr); in mlxreg_hotplug_probe()
735 return -EPROBE_DEFER; in mlxreg_hotplug_probe()
738 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in mlxreg_hotplug_probe()
740 return -ENOMEM; in mlxreg_hotplug_probe()
742 if (pdata->irq) { in mlxreg_hotplug_probe()
743 priv->irq = pdata->irq; in mlxreg_hotplug_probe()
745 priv->irq = platform_get_irq(pdev, 0); in mlxreg_hotplug_probe()
746 if (priv->irq < 0) in mlxreg_hotplug_probe()
747 return priv->irq; in mlxreg_hotplug_probe()
750 priv->regmap = pdata->regmap; in mlxreg_hotplug_probe()
751 priv->dev = pdev->dev.parent; in mlxreg_hotplug_probe()
752 priv->pdev = pdev; in mlxreg_hotplug_probe()
754 err = devm_request_irq(&pdev->dev, priv->irq, in mlxreg_hotplug_probe()
756 | IRQF_SHARED, "mlxreg-hotplug", priv); in mlxreg_hotplug_probe()
758 dev_err(&pdev->dev, "Failed to request irq: %d\n", err); in mlxreg_hotplug_probe()
762 disable_irq(priv->irq); in mlxreg_hotplug_probe()
763 spin_lock_init(&priv->lock); in mlxreg_hotplug_probe()
764 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); in mlxreg_hotplug_probe()
765 dev_set_drvdata(&pdev->dev, priv); in mlxreg_hotplug_probe()
769 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", in mlxreg_hotplug_probe()
774 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, in mlxreg_hotplug_probe()
775 "mlxreg_hotplug", priv, priv->groups); in mlxreg_hotplug_probe()
776 if (IS_ERR(priv->hwmon)) { in mlxreg_hotplug_probe()
777 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", in mlxreg_hotplug_probe()
778 PTR_ERR(priv->hwmon)); in mlxreg_hotplug_probe()
779 return PTR_ERR(priv->hwmon); in mlxreg_hotplug_probe()
784 priv->after_probe = true; in mlxreg_hotplug_probe()
791 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); in mlxreg_hotplug_remove()
795 devm_free_irq(&pdev->dev, priv->irq, priv); in mlxreg_hotplug_remove()
802 .name = "mlxreg-hotplug",
813 MODULE_ALIAS("platform:mlxreg-hotplug");