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>
35 * struct mlxreg_hotplug_priv_data - platform private data:
36 * @irq: platform device interrupt number;
55 int irq; member
86 string_upper(label, data->label); in mlxreg_hotplug_udev_event_send()
99 mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true); in mlxreg_hotplug_device_create()
105 if (data->hpdev.nr < 0) in mlxreg_hotplug_device_create()
108 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_device_create()
109 data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr + in mlxreg_hotplug_device_create()
110 pdata->shift_nr); in mlxreg_hotplug_device_create()
111 if (!data->hpdev.adapter) { in mlxreg_hotplug_device_create()
112 dev_err(priv->dev, "Failed to get adapter for bus %d\n", in mlxreg_hotplug_device_create()
113 data->hpdev.nr + pdata->shift_nr); in mlxreg_hotplug_device_create()
114 return -EFAULT; in mlxreg_hotplug_device_create()
117 client = i2c_new_client_device(data->hpdev.adapter, in mlxreg_hotplug_device_create()
118 data->hpdev.brdinfo); in mlxreg_hotplug_device_create()
120 dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", in mlxreg_hotplug_device_create()
121 data->hpdev.brdinfo->type, data->hpdev.nr + in mlxreg_hotplug_device_create()
122 pdata->shift_nr, data->hpdev.brdinfo->addr); in mlxreg_hotplug_device_create()
124 i2c_put_adapter(data->hpdev.adapter); in mlxreg_hotplug_device_create()
125 data->hpdev.adapter = NULL; in mlxreg_hotplug_device_create()
129 data->hpdev.client = client; in mlxreg_hotplug_device_create()
139 mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false); in mlxreg_hotplug_device_destroy()
141 if (data->hpdev.client) { in mlxreg_hotplug_device_destroy()
142 i2c_unregister_device(data->hpdev.client); in mlxreg_hotplug_device_destroy()
143 data->hpdev.client = NULL; in mlxreg_hotplug_device_destroy()
146 if (data->hpdev.adapter) { in mlxreg_hotplug_device_destroy()
147 i2c_put_adapter(data->hpdev.adapter); in mlxreg_hotplug_device_destroy()
148 data->hpdev.adapter = NULL; in mlxreg_hotplug_device_destroy()
158 int index = to_sensor_dev_attr_2(attr)->index; in mlxreg_hotplug_attr_show()
159 int nr = to_sensor_dev_attr_2(attr)->nr; in mlxreg_hotplug_attr_show()
165 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_attr_show()
166 item = pdata->items + nr; in mlxreg_hotplug_attr_show()
167 data = item->data + index; in mlxreg_hotplug_attr_show()
169 ret = regmap_read(priv->regmap, data->reg, ®val); in mlxreg_hotplug_attr_show()
173 if (item->health) { in mlxreg_hotplug_attr_show()
174 regval &= data->mask; in mlxreg_hotplug_attr_show()
176 /* Bit = 0 : functional if item->inversed is true. */ in mlxreg_hotplug_attr_show()
177 if (item->inversed) in mlxreg_hotplug_attr_show()
178 regval = !(regval & data->mask); in mlxreg_hotplug_attr_show()
180 regval = !!(regval & data->mask); in mlxreg_hotplug_attr_show()
186 #define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
187 #define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
198 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_attr_init()
199 item = pdata->items; in mlxreg_hotplug_attr_init()
201 /* Go over all kinds of items - psu, pwr, fan. */ in mlxreg_hotplug_attr_init()
202 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_attr_init()
203 if (item->capability) { in mlxreg_hotplug_attr_init()
209 ret = regmap_read(priv->regmap, item->capability, in mlxreg_hotplug_attr_init()
214 item->mask = GENMASK((regval & item->mask) - 1, 0); in mlxreg_hotplug_attr_init()
217 data = item->data; in mlxreg_hotplug_attr_init()
220 mask = item->mask; in mlxreg_hotplug_attr_init()
222 for_each_set_bit(j, &mask, item->count) { in mlxreg_hotplug_attr_init()
223 if (data->capability) { in mlxreg_hotplug_attr_init()
228 ret = regmap_read(priv->regmap, in mlxreg_hotplug_attr_init()
229 data->capability, ®val); in mlxreg_hotplug_attr_init()
232 if (!(regval & data->bit)) { in mlxreg_hotplug_attr_init()
238 PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev, in mlxreg_hotplug_attr_init()
240 data->label); in mlxreg_hotplug_attr_init()
242 if (!PRIV_ATTR(id)->name) { in mlxreg_hotplug_attr_init()
243 dev_err(priv->dev, "Memory allocation failed for attr %d.\n", in mlxreg_hotplug_attr_init()
245 return -ENOMEM; in mlxreg_hotplug_attr_init()
249 PRIV_ATTR(id)->name; in mlxreg_hotplug_attr_init()
263 priv->group.attrs = devm_kcalloc(&priv->pdev->dev, in mlxreg_hotplug_attr_init()
267 if (!priv->group.attrs) in mlxreg_hotplug_attr_init()
268 return -ENOMEM; in mlxreg_hotplug_attr_init()
270 priv->group.attrs = priv->mlxreg_hotplug_attr; in mlxreg_hotplug_attr_init()
271 priv->groups[0] = &priv->group; in mlxreg_hotplug_attr_init()
272 priv->groups[1] = NULL; in mlxreg_hotplug_attr_init()
291 * signals from other devices if any. in mlxreg_hotplug_work_helper()
294 dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n", in mlxreg_hotplug_work_helper()
295 item->reg, item->mask); in mlxreg_hotplug_work_helper()
301 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
307 ret = regmap_read(priv->regmap, item->reg, ®val); in mlxreg_hotplug_work_helper()
312 regval &= item->mask; in mlxreg_hotplug_work_helper()
313 asserted = item->cache ^ regval; in mlxreg_hotplug_work_helper()
314 item->cache = regval; in mlxreg_hotplug_work_helper()
317 data = item->data + bit; in mlxreg_hotplug_work_helper()
319 if (item->inversed) in mlxreg_hotplug_work_helper()
324 if (item->inversed) in mlxreg_hotplug_work_helper()
332 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF, in mlxreg_hotplug_work_helper()
338 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_work_helper()
339 item->mask); in mlxreg_hotplug_work_helper()
343 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_helper()
350 struct mlxreg_core_data *data = item->data; in mlxreg_hotplug_health_work_helper()
354 for (i = 0; i < item->count; i++, data++) { in mlxreg_hotplug_health_work_helper()
356 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
362 ret = regmap_read(priv->regmap, data->reg, ®val); in mlxreg_hotplug_health_work_helper()
366 regval &= data->mask; in mlxreg_hotplug_health_work_helper()
368 if (item->cache == regval) in mlxreg_hotplug_health_work_helper()
376 * pass the following states: dormant -> booting -> good. in mlxreg_hotplug_health_work_helper()
379 if (!data->attached) { in mlxreg_hotplug_health_work_helper()
385 data->attached = true; in mlxreg_hotplug_health_work_helper()
388 if (data->attached) { in mlxreg_hotplug_health_work_helper()
395 data->attached = false; in mlxreg_hotplug_health_work_helper()
396 data->health_cntr = 0; in mlxreg_hotplug_health_work_helper()
399 item->cache = regval; in mlxreg_hotplug_health_work_helper()
402 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
408 ret = regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_health_work_helper()
409 MLXREG_HOTPLUG_MASK_OFF, data->mask); in mlxreg_hotplug_health_work_helper()
416 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_health_work_helper()
420 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
424 * PSU registers: *---*
425 * *-----------------* | |
426 * |status/event/mask|-----> | * |
427 * *-----------------* | |
429 * *-----------------* | |
430 * |status/event/mask|-----> | * |
431 * *-----------------* | |
432 * FAN registers: | |--> CPU
433 * *-----------------* | |
434 * |status/event/mask|-----> | * |
435 * *-----------------* | |
437 * *-----------------* | |
438 * |status/event/mask|-----> | * |
439 * *-----------------* | |
440 * *---*
457 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_work_handler()
458 item = pdata->items; in mlxreg_hotplug_work_handler()
461 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
467 ret = regmap_read(priv->regmap, pdata->cell, ®val); in mlxreg_hotplug_work_handler()
471 regval &= pdata->mask; in mlxreg_hotplug_work_handler()
472 aggr_asserted = priv->aggr_cache ^ regval; in mlxreg_hotplug_work_handler()
473 priv->aggr_cache = regval; in mlxreg_hotplug_work_handler()
478 * run over all relevant signals to recover any missed signal. in mlxreg_hotplug_work_handler()
480 if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) { in mlxreg_hotplug_work_handler()
481 priv->not_asserted = 0; in mlxreg_hotplug_work_handler()
482 aggr_asserted = pdata->mask; in mlxreg_hotplug_work_handler()
488 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_work_handler()
489 if (aggr_asserted & item->aggr_mask) { in mlxreg_hotplug_work_handler()
490 if (item->health) in mlxreg_hotplug_work_handler()
497 spin_lock_irqsave(&priv->lock, flags); in mlxreg_hotplug_work_handler()
500 * It is possible, that some signals have been inserted, while in mlxreg_hotplug_work_handler()
502 * case such signals will be missed. In order to handle these signals in mlxreg_hotplug_work_handler()
503 * delayed work is canceled and work task re-scheduled for immediate in mlxreg_hotplug_work_handler()
504 * execution. It allows to handle missed signals, if any. In other case in mlxreg_hotplug_work_handler()
505 * work handler just validates that no new signals have been received in mlxreg_hotplug_work_handler()
508 cancel_delayed_work(&priv->dwork_irq); in mlxreg_hotplug_work_handler()
509 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_work_handler()
511 spin_unlock_irqrestore(&priv->lock, flags); in mlxreg_hotplug_work_handler()
516 priv->not_asserted++; in mlxreg_hotplug_work_handler()
518 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_work_handler()
519 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_work_handler()
523 dev_err(priv->dev, "Failed to complete workqueue.\n"); in mlxreg_hotplug_work_handler()
534 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_set_irq()
535 item = pdata->items; in mlxreg_hotplug_set_irq()
537 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_set_irq()
539 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
548 data = item->data; in mlxreg_hotplug_set_irq()
549 for (j = 0; j < item->count; j++, data++) { in mlxreg_hotplug_set_irq()
551 if (data->capability) { in mlxreg_hotplug_set_irq()
553 ret = regmap_read(priv->regmap, in mlxreg_hotplug_set_irq()
554 data->capability, ®val); in mlxreg_hotplug_set_irq()
558 if (!(regval & data->bit)) in mlxreg_hotplug_set_irq()
559 item->mask &= ~BIT(j); in mlxreg_hotplug_set_irq()
564 if (item->inversed) { in mlxreg_hotplug_set_irq()
565 item->cache = item->mask; in mlxreg_hotplug_set_irq()
566 ret = regmap_write(priv->regmap, item->reg + in mlxreg_hotplug_set_irq()
568 item->mask); in mlxreg_hotplug_set_irq()
575 ret = regmap_write(priv->regmap, pdata->cell + in mlxreg_hotplug_set_irq()
576 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask); in mlxreg_hotplug_set_irq()
581 if (pdata->cell_low) { in mlxreg_hotplug_set_irq()
582 ret = regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_set_irq()
584 pdata->mask_low); in mlxreg_hotplug_set_irq()
590 mlxreg_hotplug_work_handler(&priv->dwork_irq.work); in mlxreg_hotplug_set_irq()
594 dev_err(priv->dev, "Failed to set interrupts.\n"); in mlxreg_hotplug_set_irq()
595 enable_irq(priv->irq); in mlxreg_hotplug_set_irq()
606 pdata = dev_get_platdata(&priv->pdev->dev); in mlxreg_hotplug_unset_irq()
607 item = pdata->items; in mlxreg_hotplug_unset_irq()
608 disable_irq(priv->irq); in mlxreg_hotplug_unset_irq()
609 cancel_delayed_work_sync(&priv->dwork_irq); in mlxreg_hotplug_unset_irq()
612 if (pdata->cell_low) in mlxreg_hotplug_unset_irq()
613 regmap_write(priv->regmap, pdata->cell_low + in mlxreg_hotplug_unset_irq()
617 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF, in mlxreg_hotplug_unset_irq()
621 for (i = 0; i < pdata->counter; i++, item++) { in mlxreg_hotplug_unset_irq()
622 data = item->data; in mlxreg_hotplug_unset_irq()
624 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF, in mlxreg_hotplug_unset_irq()
627 regmap_write(priv->regmap, data->reg + in mlxreg_hotplug_unset_irq()
631 count = item->count; in mlxreg_hotplug_unset_irq()
637 static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev) in mlxreg_hotplug_irq_handler() argument
644 schedule_delayed_work(&priv->dwork_irq, 0); in mlxreg_hotplug_irq_handler()
656 pdata = dev_get_platdata(&pdev->dev); in mlxreg_hotplug_probe()
658 dev_err(&pdev->dev, "Failed to get platform data.\n"); in mlxreg_hotplug_probe()
659 return -EINVAL; in mlxreg_hotplug_probe()
663 deferred_adap = i2c_get_adapter(pdata->deferred_nr); in mlxreg_hotplug_probe()
665 return -EPROBE_DEFER; in mlxreg_hotplug_probe()
668 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); in mlxreg_hotplug_probe()
670 return -ENOMEM; in mlxreg_hotplug_probe()
672 if (pdata->irq) { in mlxreg_hotplug_probe()
673 priv->irq = pdata->irq; in mlxreg_hotplug_probe()
675 priv->irq = platform_get_irq(pdev, 0); in mlxreg_hotplug_probe()
676 if (priv->irq < 0) in mlxreg_hotplug_probe()
677 return priv->irq; in mlxreg_hotplug_probe()
680 priv->regmap = pdata->regmap; in mlxreg_hotplug_probe()
681 priv->dev = pdev->dev.parent; in mlxreg_hotplug_probe()
682 priv->pdev = pdev; in mlxreg_hotplug_probe()
684 err = devm_request_irq(&pdev->dev, priv->irq, in mlxreg_hotplug_probe()
686 | IRQF_SHARED, "mlxreg-hotplug", priv); in mlxreg_hotplug_probe()
688 dev_err(&pdev->dev, "Failed to request irq: %d\n", err); in mlxreg_hotplug_probe()
692 disable_irq(priv->irq); in mlxreg_hotplug_probe()
693 spin_lock_init(&priv->lock); in mlxreg_hotplug_probe()
694 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); in mlxreg_hotplug_probe()
695 dev_set_drvdata(&pdev->dev, priv); in mlxreg_hotplug_probe()
699 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", in mlxreg_hotplug_probe()
704 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, in mlxreg_hotplug_probe()
705 "mlxreg_hotplug", priv, priv->groups); in mlxreg_hotplug_probe()
706 if (IS_ERR(priv->hwmon)) { in mlxreg_hotplug_probe()
707 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", in mlxreg_hotplug_probe()
708 PTR_ERR(priv->hwmon)); in mlxreg_hotplug_probe()
709 return PTR_ERR(priv->hwmon); in mlxreg_hotplug_probe()
714 priv->after_probe = true; in mlxreg_hotplug_probe()
721 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev); in mlxreg_hotplug_remove()
725 devm_free_irq(&pdev->dev, priv->irq, priv); in mlxreg_hotplug_remove()
732 .name = "mlxreg-hotplug",
743 MODULE_ALIAS("platform:mlxreg-hotplug");