Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Mellanox hotplug driver
  4 *
  5 * Copyright (C) 2016-2020 Mellanox Technologies
  6 */
  7
  8#include <linux/bitops.h>
  9#include <linux/device.h>
 10#include <linux/hwmon.h>
 11#include <linux/hwmon-sysfs.h>
 12#include <linux/i2c.h>
 13#include <linux/interrupt.h>
 14#include <linux/module.h>
 15#include <linux/platform_data/mlxreg.h>
 16#include <linux/platform_device.h>
 17#include <linux/spinlock.h>
 18#include <linux/string_helpers.h>
 19#include <linux/regmap.h>
 20#include <linux/workqueue.h>
 21
 22/* Offset of event and mask registers from status register. */
 23#define MLXREG_HOTPLUG_EVENT_OFF	1
 24#define MLXREG_HOTPLUG_MASK_OFF		2
 25#define MLXREG_HOTPLUG_AGGR_MASK_OFF	1
 26
 27/* ASIC good health mask. */
 28#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK	0x02
 29
 30#define MLXREG_HOTPLUG_ATTRS_MAX	128
 31#define MLXREG_HOTPLUG_NOT_ASSERT	3
 32
 33/**
 34 * struct mlxreg_hotplug_priv_data - platform private data:
 35 * @irq: platform device interrupt number;
 36 * @dev: basic device;
 37 * @pdev: platform device;
 38 * @plat: platform data;
 39 * @regmap: register map handle;
 40 * @dwork_irq: delayed work template;
 41 * @lock: spin lock;
 42 * @hwmon: hwmon device;
 43 * @mlxreg_hotplug_attr: sysfs attributes array;
 44 * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
 45 * @group: sysfs attribute group;
 46 * @groups: list of sysfs attribute group for hwmon registration;
 47 * @cell: location of top aggregation interrupt register;
 48 * @mask: top aggregation interrupt common mask;
 49 * @aggr_cache: last value of aggregation register status;
 50 * @after_probe: flag indication probing completion;
 51 * @not_asserted: number of entries in workqueue with no signal assertion;
 52 */
 53struct mlxreg_hotplug_priv_data {
 54	int irq;
 55	struct device *dev;
 56	struct platform_device *pdev;
 57	struct mlxreg_hotplug_platform_data *plat;
 58	struct regmap *regmap;
 59	struct delayed_work dwork_irq;
 60	spinlock_t lock; /* sync with interrupt */
 61	struct device *hwmon;
 62	struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
 63	struct sensor_device_attribute_2
 64			mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
 65	struct attribute_group group;
 66	const struct attribute_group *groups[2];
 67	u32 cell;
 68	u32 mask;
 69	u32 aggr_cache;
 70	bool after_probe;
 71	u8 not_asserted;
 72};
 73
 74/* Environment variables array for udev. */
 75static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
 76
 77static int
 78mlxreg_hotplug_udev_event_send(struct kobject *kobj,
 79			       struct mlxreg_core_data *data, bool action)
 80{
 81	char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
 82	char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
 83
 84	mlxreg_hotplug_udev_envp[0] = event_str;
 85	string_upper(label, data->label);
 86	snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
 87
 88	return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
 89}
 90
 91static void
 92mlxreg_hotplug_pdata_export(void *pdata, void *regmap)
 93{
 94	struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata;
 95
 96	/* Export regmap to underlying device. */
 97	dev_pdata->regmap = regmap;
 98}
 99
100static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
101					struct mlxreg_core_data *data,
102					enum mlxreg_hotplug_kind kind)
103{
104	struct i2c_board_info *brdinfo = data->hpdev.brdinfo;
105	struct mlxreg_core_hotplug_platform_data *pdata;
106	struct i2c_client *client;
107
108	/* Notify user by sending hwmon uevent. */
109	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
110
111	/*
112	 * Return if adapter number is negative. It could be in case hotplug
113	 * event is not associated with hotplug device.
114	 */
115	if (data->hpdev.nr < 0 && data->hpdev.action != MLXREG_HOTPLUG_DEVICE_NO_ACTION)
116		return 0;
117
118	pdata = dev_get_platdata(&priv->pdev->dev);
119	switch (data->hpdev.action) {
120	case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
121		data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
122						      pdata->shift_nr);
123		if (!data->hpdev.adapter) {
124			dev_err(priv->dev, "Failed to get adapter for bus %d\n",
125				data->hpdev.nr + pdata->shift_nr);
126			return -EFAULT;
127		}
128
129		/* Export platform data to underlying device. */
130		if (brdinfo->platform_data)
131			mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap);
132
133		client = i2c_new_client_device(data->hpdev.adapter,
134					       brdinfo);
135		if (IS_ERR(client)) {
136			dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
137				brdinfo->type, data->hpdev.nr +
138				pdata->shift_nr, brdinfo->addr);
139
140			i2c_put_adapter(data->hpdev.adapter);
141			data->hpdev.adapter = NULL;
142			return PTR_ERR(client);
143		}
144
145		data->hpdev.client = client;
146		break;
147	case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
148		/* Export platform data to underlying device. */
149		if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data)
150			mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data,
151						    pdata->regmap);
152		/* Pass parent hotplug device handle to underlying device. */
153		data->notifier = data->hpdev.notifier;
154		data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev,
155								     brdinfo->type,
156								     data->hpdev.nr,
157								     NULL, 0, data,
158								     sizeof(*data));
159		if (IS_ERR(data->hpdev.pdev))
160			return PTR_ERR(data->hpdev.pdev);
161
162		break;
163	default:
164		break;
165	}
166
167	if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
168		return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1);
169
170	return 0;
171}
172
173static void
174mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
175			      struct mlxreg_core_data *data,
176			      enum mlxreg_hotplug_kind kind)
177{
178	/* Notify user by sending hwmon uevent. */
179	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
180	if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
181		data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0);
182
183	switch (data->hpdev.action) {
184	case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
185		if (data->hpdev.client) {
186			i2c_unregister_device(data->hpdev.client);
187			data->hpdev.client = NULL;
188		}
189
190		if (data->hpdev.adapter) {
191			i2c_put_adapter(data->hpdev.adapter);
192			data->hpdev.adapter = NULL;
193		}
194		break;
195	case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
196		if (data->hpdev.pdev)
197			platform_device_unregister(data->hpdev.pdev);
198		break;
199	default:
200		break;
201	}
202}
203
204static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
205					struct device_attribute *attr,
206					char *buf)
207{
208	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
209	struct mlxreg_core_hotplug_platform_data *pdata;
210	int index = to_sensor_dev_attr_2(attr)->index;
211	int nr = to_sensor_dev_attr_2(attr)->nr;
212	struct mlxreg_core_item *item;
213	struct mlxreg_core_data *data;
214	u32 regval;
215	int ret;
216
217	pdata = dev_get_platdata(&priv->pdev->dev);
218	item = pdata->items + nr;
219	data = item->data + index;
220
221	ret = regmap_read(priv->regmap, data->reg, &regval);
222	if (ret)
223		return ret;
224
225	if (item->health) {
226		regval &= data->mask;
227	} else {
228		/* Bit = 0 : functional if item->inversed is true. */
229		if (item->inversed)
230			regval = !(regval & data->mask);
231		else
232			regval = !!(regval & data->mask);
233	}
234
235	return sprintf(buf, "%u\n", regval);
236}
237
238#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
239#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
240
241static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit)
242{
243	int i, j;
244
245	for (i = 0, j = -1; i <= bit; i++) {
246		if (mask & BIT(i))
247			j++;
248	}
249	return j;
250}
251
252static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
253{
254	struct mlxreg_core_hotplug_platform_data *pdata;
255	struct mlxreg_core_item *item;
256	struct mlxreg_core_data *data;
257	unsigned long mask;
258	u32 regval;
259	int num_attrs = 0, id = 0, i, j, k, count, ret;
260
261	pdata = dev_get_platdata(&priv->pdev->dev);
262	item = pdata->items;
263
264	/* Go over all kinds of items - psu, pwr, fan. */
265	for (i = 0; i < pdata->counter; i++, item++) {
266		if (item->capability) {
267			/*
268			 * Read group capability register to get actual number
269			 * of interrupt capable components and set group mask
270			 * accordingly.
271			 */
272			ret = regmap_read(priv->regmap, item->capability,
273					  &regval);
274			if (ret)
275				return ret;
276
277			item->mask = GENMASK((regval & item->mask) - 1, 0);
278		}
279
280		data = item->data;
281
282		/* Go over all unmasked units within item. */
283		mask = item->mask;
284		k = 0;
285		count = item->ind ? item->ind : item->count;
286		for_each_set_bit(j, &mask, count) {
287			if (data->capability) {
288				/*
289				 * Read capability register and skip non
290				 * relevant attributes.
291				 */
292				ret = regmap_read(priv->regmap,
293						  data->capability, &regval);
294				if (ret)
295					return ret;
296
297				if (!(regval & data->bit)) {
298					data++;
299					continue;
300				}
301			}
302
303			PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
304			PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
305							     GFP_KERNEL,
306							     data->label);
307			if (!PRIV_ATTR(id)->name) {
308				dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
309					id);
310				return -ENOMEM;
311			}
312
313			PRIV_DEV_ATTR(id).dev_attr.attr.name =
314							PRIV_ATTR(id)->name;
315			PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
316			PRIV_DEV_ATTR(id).dev_attr.show =
317						mlxreg_hotplug_attr_show;
318			PRIV_DEV_ATTR(id).nr = i;
319			PRIV_DEV_ATTR(id).index = k;
320			sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
321			data++;
322			id++;
323			k++;
324		}
325		num_attrs += k;
326	}
327
328	priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
329					 num_attrs,
330					 sizeof(struct attribute *),
331					 GFP_KERNEL);
332	if (!priv->group.attrs)
333		return -ENOMEM;
334
335	priv->group.attrs = priv->mlxreg_hotplug_attr;
336	priv->groups[0] = &priv->group;
337	priv->groups[1] = NULL;
338
339	return 0;
340}
341
342static void
343mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
344			   struct mlxreg_core_item *item)
345{
346	struct mlxreg_core_data *data;
347	unsigned long asserted;
348	u32 regval, bit;
349	int ret;
350
351	/*
352	 * Validate if item related to received signal type is valid.
353	 * It should never happen, excepted the situation when some
354	 * piece of hardware is broken. In such situation just produce
355	 * error message and return. Caller must continue to handle the
356	 * signals from other devices if any.
357	 */
358	if (unlikely(!item)) {
359		dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
360			item->reg, item->mask);
361
362		return;
363	}
364
365	/* Mask event. */
366	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
367			   0);
368	if (ret)
369		goto out;
370
371	/* Read status. */
372	ret = regmap_read(priv->regmap, item->reg, &regval);
373	if (ret)
374		goto out;
375
376	/* Set asserted bits and save last status. */
377	regval &= item->mask;
378	asserted = item->cache ^ regval;
379	item->cache = regval;
380	for_each_set_bit(bit, &asserted, 8) {
381		int pos;
382
383		pos = mlxreg_hotplug_item_label_index_get(item->mask, bit);
384		if (pos < 0)
385			goto out;
386
387		data = item->data + pos;
388		if (regval & BIT(bit)) {
389			if (item->inversed)
390				mlxreg_hotplug_device_destroy(priv, data, item->kind);
391			else
392				mlxreg_hotplug_device_create(priv, data, item->kind);
393		} else {
394			if (item->inversed)
395				mlxreg_hotplug_device_create(priv, data, item->kind);
396			else
397				mlxreg_hotplug_device_destroy(priv, data, item->kind);
398		}
399	}
400
401	/* Acknowledge event. */
402	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
403			   0);
404	if (ret)
405		goto out;
406
407	/* Unmask event. */
408	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
409			   item->mask);
410
411 out:
412	if (ret)
413		dev_err(priv->dev, "Failed to complete workqueue.\n");
414}
415
416static void
417mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
418				  struct mlxreg_core_item *item)
419{
420	struct mlxreg_core_data *data = item->data;
421	u32 regval;
422	int i, ret = 0;
423
424	for (i = 0; i < item->count; i++, data++) {
425		/* Mask event. */
426		ret = regmap_write(priv->regmap, data->reg +
427				   MLXREG_HOTPLUG_MASK_OFF, 0);
428		if (ret)
429			goto out;
430
431		/* Read status. */
432		ret = regmap_read(priv->regmap, data->reg, &regval);
433		if (ret)
434			goto out;
435
436		regval &= data->mask;
437
438		if (item->cache == regval)
439			goto ack_event;
440
441		/*
442		 * ASIC health indication is provided through two bits. Bits
443		 * value 0x2 indicates that ASIC reached the good health, value
444		 * 0x0 indicates ASIC the bad health or dormant state and value
445		 * 0x3 indicates the booting state. During ASIC reset it should
446		 * pass the following states: dormant -> booting -> good.
447		 */
448		if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
449			if (!data->attached) {
450				/*
451				 * ASIC is in steady state. Connect associated
452				 * device, if configured.
453				 */
454				mlxreg_hotplug_device_create(priv, data, item->kind);
455				data->attached = true;
456			}
457		} else {
458			if (data->attached) {
459				/*
460				 * ASIC health is failed after ASIC has been
461				 * in steady state. Disconnect associated
462				 * device, if it has been connected.
463				 */
464				mlxreg_hotplug_device_destroy(priv, data, item->kind);
465				data->attached = false;
466				data->health_cntr = 0;
467			}
468		}
469		item->cache = regval;
470ack_event:
471		/* Acknowledge event. */
472		ret = regmap_write(priv->regmap, data->reg +
473				   MLXREG_HOTPLUG_EVENT_OFF, 0);
474		if (ret)
475			goto out;
476
477		/* Unmask event. */
478		ret = regmap_write(priv->regmap, data->reg +
479				   MLXREG_HOTPLUG_MASK_OFF, data->mask);
480		if (ret)
481			goto out;
482	}
483
484 out:
485	if (ret)
486		dev_err(priv->dev, "Failed to complete workqueue.\n");
487}
488
489/*
490 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
491 * registers according to the below hierarchy schema:
492 *
493 *				Aggregation registers (status/mask)
494 * PSU registers:		*---*
495 * *-----------------*		|   |
496 * |status/event/mask|----->    | * |
497 * *-----------------*		|   |
498 * Power registers:		|   |
499 * *-----------------*		|   |
500 * |status/event/mask|----->    | * |
501 * *-----------------*		|   |
502 * FAN registers:		|   |--> CPU
503 * *-----------------*		|   |
504 * |status/event/mask|----->    | * |
505 * *-----------------*		|   |
506 * ASIC registers:		|   |
507 * *-----------------*		|   |
508 * |status/event/mask|----->    | * |
509 * *-----------------*		|   |
510 *				*---*
511 *
512 * In case some system changed are detected: FAN in/out, PSU in/out, power
513 * cable attached/detached, ASIC health good/bad, relevant device is created
514 * or destroyed.
515 */
516static void mlxreg_hotplug_work_handler(struct work_struct *work)
517{
518	struct mlxreg_core_hotplug_platform_data *pdata;
519	struct mlxreg_hotplug_priv_data *priv;
520	struct mlxreg_core_item *item;
521	u32 regval, aggr_asserted;
522	unsigned long flags;
523	int i, ret;
524
525	priv = container_of(work, struct mlxreg_hotplug_priv_data,
526			    dwork_irq.work);
527	pdata = dev_get_platdata(&priv->pdev->dev);
528	item = pdata->items;
529
530	/* Mask aggregation event. */
531	ret = regmap_write(priv->regmap, pdata->cell +
532			   MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
533	if (ret < 0)
534		goto out;
535
536	/* Read aggregation status. */
537	ret = regmap_read(priv->regmap, pdata->cell, &regval);
538	if (ret)
539		goto out;
540
541	regval &= pdata->mask;
542	aggr_asserted = priv->aggr_cache ^ regval;
543	priv->aggr_cache = regval;
544
545	/*
546	 * Handler is invoked, but no assertion is detected at top aggregation
547	 * status level. Set aggr_asserted to mask value to allow handler extra
548	 * run over all relevant signals to recover any missed signal.
549	 */
550	if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
551		priv->not_asserted = 0;
552		aggr_asserted = pdata->mask;
553	}
554	if (!aggr_asserted)
555		goto unmask_event;
556
557	/* Handle topology and health configuration changes. */
558	for (i = 0; i < pdata->counter; i++, item++) {
559		if (aggr_asserted & item->aggr_mask) {
560			if (item->health)
561				mlxreg_hotplug_health_work_helper(priv, item);
562			else
563				mlxreg_hotplug_work_helper(priv, item);
564		}
565	}
566
567	spin_lock_irqsave(&priv->lock, flags);
568
569	/*
570	 * It is possible, that some signals have been inserted, while
571	 * interrupt has been masked by mlxreg_hotplug_work_handler. In this
572	 * case such signals will be missed. In order to handle these signals
573	 * delayed work is canceled and work task re-scheduled for immediate
574	 * execution. It allows to handle missed signals, if any. In other case
575	 * work handler just validates that no new signals have been received
576	 * during masking.
577	 */
578	cancel_delayed_work(&priv->dwork_irq);
579	schedule_delayed_work(&priv->dwork_irq, 0);
580
581	spin_unlock_irqrestore(&priv->lock, flags);
582
583	return;
584
585unmask_event:
586	priv->not_asserted++;
587	/* Unmask aggregation event (no need acknowledge). */
588	ret = regmap_write(priv->regmap, pdata->cell +
589			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
590
591 out:
592	if (ret)
593		dev_err(priv->dev, "Failed to complete workqueue.\n");
594}
595
596static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
597{
598	struct mlxreg_core_hotplug_platform_data *pdata;
599	struct mlxreg_core_item *item;
600	struct mlxreg_core_data *data;
601	u32 regval;
602	int i, j, ret;
603
604	pdata = dev_get_platdata(&priv->pdev->dev);
605	item = pdata->items;
606
607	for (i = 0; i < pdata->counter; i++, item++) {
608		/* Clear group presense event. */
609		ret = regmap_write(priv->regmap, item->reg +
610				   MLXREG_HOTPLUG_EVENT_OFF, 0);
611		if (ret)
612			goto out;
613
614		/*
615		 * Verify if hardware configuration requires to disable
616		 * interrupt capability for some of components.
617		 */
618		data = item->data;
619		for (j = 0; j < item->count; j++, data++) {
620			/* Verify if the attribute has capability register. */
621			if (data->capability) {
622				/* Read capability register. */
623				ret = regmap_read(priv->regmap,
624						  data->capability, &regval);
625				if (ret)
626					goto out;
627
628				if (!(regval & data->bit))
629					item->mask &= ~BIT(j);
630			}
631		}
632
633		/* Set group initial status as mask and unmask group event. */
634		if (item->inversed) {
635			item->cache = item->mask;
636			ret = regmap_write(priv->regmap, item->reg +
637					   MLXREG_HOTPLUG_MASK_OFF,
638					   item->mask);
639			if (ret)
640				goto out;
641		}
642	}
643
644	/* Keep aggregation initial status as zero and unmask events. */
645	ret = regmap_write(priv->regmap, pdata->cell +
646			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
647	if (ret)
648		goto out;
649
650	/* Keep low aggregation initial status as zero and unmask events. */
651	if (pdata->cell_low) {
652		ret = regmap_write(priv->regmap, pdata->cell_low +
653				   MLXREG_HOTPLUG_AGGR_MASK_OFF,
654				   pdata->mask_low);
655		if (ret)
656			goto out;
657	}
658
659	/* Invoke work handler for initializing hot plug devices setting. */
660	mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
661
662 out:
663	if (ret)
664		dev_err(priv->dev, "Failed to set interrupts.\n");
665	enable_irq(priv->irq);
666	return ret;
667}
668
669static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
670{
671	struct mlxreg_core_hotplug_platform_data *pdata;
672	struct mlxreg_core_item *item;
673	struct mlxreg_core_data *data;
674	int count, i, j;
675
676	pdata = dev_get_platdata(&priv->pdev->dev);
677	item = pdata->items;
678	disable_irq(priv->irq);
679	cancel_delayed_work_sync(&priv->dwork_irq);
680
681	/* Mask low aggregation event, if defined. */
682	if (pdata->cell_low)
683		regmap_write(priv->regmap, pdata->cell_low +
684			     MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
685
686	/* Mask aggregation event. */
687	regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
688		     0);
689
690	/* Clear topology configurations. */
691	for (i = 0; i < pdata->counter; i++, item++) {
692		data = item->data;
693		/* Mask group presense event. */
694		regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
695			     0);
696		/* Clear group presense event. */
697		regmap_write(priv->regmap, data->reg +
698			     MLXREG_HOTPLUG_EVENT_OFF, 0);
699
700		/* Remove all the attached devices in group. */
701		count = item->count;
702		for (j = 0; j < count; j++, data++)
703			mlxreg_hotplug_device_destroy(priv, data, item->kind);
704	}
705}
706
707static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
708{
709	struct mlxreg_hotplug_priv_data *priv;
710
711	priv = (struct mlxreg_hotplug_priv_data *)dev;
712
713	/* Schedule work task for immediate execution.*/
714	schedule_delayed_work(&priv->dwork_irq, 0);
715
716	return IRQ_HANDLED;
717}
718
719static int mlxreg_hotplug_probe(struct platform_device *pdev)
720{
721	struct mlxreg_core_hotplug_platform_data *pdata;
722	struct mlxreg_hotplug_priv_data *priv;
723	struct i2c_adapter *deferred_adap;
724	int err;
725
726	pdata = dev_get_platdata(&pdev->dev);
727	if (!pdata) {
728		dev_err(&pdev->dev, "Failed to get platform data.\n");
729		return -EINVAL;
730	}
731
732	/* Defer probing if the necessary adapter is not configured yet. */
733	deferred_adap = i2c_get_adapter(pdata->deferred_nr);
734	if (!deferred_adap)
735		return -EPROBE_DEFER;
736	i2c_put_adapter(deferred_adap);
737
738	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
739	if (!priv)
740		return -ENOMEM;
741
742	if (pdata->irq) {
743		priv->irq = pdata->irq;
744	} else {
745		priv->irq = platform_get_irq(pdev, 0);
746		if (priv->irq < 0)
747			return priv->irq;
748	}
749
750	priv->regmap = pdata->regmap;
751	priv->dev = pdev->dev.parent;
752	priv->pdev = pdev;
753
754	err = devm_request_irq(&pdev->dev, priv->irq,
755			       mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
756			       | IRQF_SHARED, "mlxreg-hotplug", priv);
757	if (err) {
758		dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
759		return err;
760	}
761
762	disable_irq(priv->irq);
763	spin_lock_init(&priv->lock);
764	INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
765	dev_set_drvdata(&pdev->dev, priv);
766
767	err = mlxreg_hotplug_attr_init(priv);
768	if (err) {
769		dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
770			err);
771		return err;
772	}
773
774	priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
775					"mlxreg_hotplug", priv, priv->groups);
776	if (IS_ERR(priv->hwmon)) {
777		dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
778			PTR_ERR(priv->hwmon));
779		return PTR_ERR(priv->hwmon);
780	}
781
782	/* Perform initial interrupts setup. */
783	mlxreg_hotplug_set_irq(priv);
784	priv->after_probe = true;
785
786	return 0;
787}
788
789static void mlxreg_hotplug_remove(struct platform_device *pdev)
790{
791	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
792
793	/* Clean interrupts setup. */
794	mlxreg_hotplug_unset_irq(priv);
795	devm_free_irq(&pdev->dev, priv->irq, priv);
796}
797
798static struct platform_driver mlxreg_hotplug_driver = {
799	.driver = {
800		.name = "mlxreg-hotplug",
801	},
802	.probe = mlxreg_hotplug_probe,
803	.remove_new = mlxreg_hotplug_remove,
804};
805
806module_platform_driver(mlxreg_hotplug_driver);
807
808MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
809MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
810MODULE_LICENSE("Dual BSD/GPL");
811MODULE_ALIAS("platform:mlxreg-hotplug");
v6.9.4
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Mellanox hotplug driver
  4 *
  5 * Copyright (C) 2016-2020 Mellanox Technologies
  6 */
  7
  8#include <linux/bitops.h>
  9#include <linux/device.h>
 10#include <linux/hwmon.h>
 11#include <linux/hwmon-sysfs.h>
 12#include <linux/i2c.h>
 13#include <linux/interrupt.h>
 14#include <linux/module.h>
 15#include <linux/platform_data/mlxreg.h>
 16#include <linux/platform_device.h>
 17#include <linux/spinlock.h>
 18#include <linux/string_helpers.h>
 19#include <linux/regmap.h>
 20#include <linux/workqueue.h>
 21
 22/* Offset of event and mask registers from status register. */
 23#define MLXREG_HOTPLUG_EVENT_OFF	1
 24#define MLXREG_HOTPLUG_MASK_OFF		2
 25#define MLXREG_HOTPLUG_AGGR_MASK_OFF	1
 26
 27/* ASIC good health mask. */
 28#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK	0x02
 29
 30#define MLXREG_HOTPLUG_ATTRS_MAX	128
 31#define MLXREG_HOTPLUG_NOT_ASSERT	3
 32
 33/**
 34 * struct mlxreg_hotplug_priv_data - platform private data:
 35 * @irq: platform device interrupt number;
 36 * @dev: basic device;
 37 * @pdev: platform device;
 38 * @plat: platform data;
 39 * @regmap: register map handle;
 40 * @dwork_irq: delayed work template;
 41 * @lock: spin lock;
 42 * @hwmon: hwmon device;
 43 * @mlxreg_hotplug_attr: sysfs attributes array;
 44 * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
 45 * @group: sysfs attribute group;
 46 * @groups: list of sysfs attribute group for hwmon registration;
 47 * @cell: location of top aggregation interrupt register;
 48 * @mask: top aggregation interrupt common mask;
 49 * @aggr_cache: last value of aggregation register status;
 50 * @after_probe: flag indication probing completion;
 51 * @not_asserted: number of entries in workqueue with no signal assertion;
 52 */
 53struct mlxreg_hotplug_priv_data {
 54	int irq;
 55	struct device *dev;
 56	struct platform_device *pdev;
 57	struct mlxreg_hotplug_platform_data *plat;
 58	struct regmap *regmap;
 59	struct delayed_work dwork_irq;
 60	spinlock_t lock; /* sync with interrupt */
 61	struct device *hwmon;
 62	struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
 63	struct sensor_device_attribute_2
 64			mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
 65	struct attribute_group group;
 66	const struct attribute_group *groups[2];
 67	u32 cell;
 68	u32 mask;
 69	u32 aggr_cache;
 70	bool after_probe;
 71	u8 not_asserted;
 72};
 73
 74/* Environment variables array for udev. */
 75static char *mlxreg_hotplug_udev_envp[] = { NULL, NULL };
 76
 77static int
 78mlxreg_hotplug_udev_event_send(struct kobject *kobj,
 79			       struct mlxreg_core_data *data, bool action)
 80{
 81	char event_str[MLXREG_CORE_LABEL_MAX_SIZE + 2];
 82	char label[MLXREG_CORE_LABEL_MAX_SIZE] = { 0 };
 83
 84	mlxreg_hotplug_udev_envp[0] = event_str;
 85	string_upper(label, data->label);
 86	snprintf(event_str, MLXREG_CORE_LABEL_MAX_SIZE, "%s=%d", label, !!action);
 87
 88	return kobject_uevent_env(kobj, KOBJ_CHANGE, mlxreg_hotplug_udev_envp);
 89}
 90
 91static void
 92mlxreg_hotplug_pdata_export(void *pdata, void *regmap)
 93{
 94	struct mlxreg_core_hotplug_platform_data *dev_pdata = pdata;
 95
 96	/* Export regmap to underlying device. */
 97	dev_pdata->regmap = regmap;
 98}
 99
100static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
101					struct mlxreg_core_data *data,
102					enum mlxreg_hotplug_kind kind)
103{
104	struct i2c_board_info *brdinfo = data->hpdev.brdinfo;
105	struct mlxreg_core_hotplug_platform_data *pdata;
106	struct i2c_client *client;
107
108	/* Notify user by sending hwmon uevent. */
109	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, true);
110
111	/*
112	 * Return if adapter number is negative. It could be in case hotplug
113	 * event is not associated with hotplug device.
114	 */
115	if (data->hpdev.nr < 0 && data->hpdev.action != MLXREG_HOTPLUG_DEVICE_NO_ACTION)
116		return 0;
117
118	pdata = dev_get_platdata(&priv->pdev->dev);
119	switch (data->hpdev.action) {
120	case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
121		data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
122						      pdata->shift_nr);
123		if (!data->hpdev.adapter) {
124			dev_err(priv->dev, "Failed to get adapter for bus %d\n",
125				data->hpdev.nr + pdata->shift_nr);
126			return -EFAULT;
127		}
128
129		/* Export platform data to underlying device. */
130		if (brdinfo->platform_data)
131			mlxreg_hotplug_pdata_export(brdinfo->platform_data, pdata->regmap);
132
133		client = i2c_new_client_device(data->hpdev.adapter,
134					       brdinfo);
135		if (IS_ERR(client)) {
136			dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
137				brdinfo->type, data->hpdev.nr +
138				pdata->shift_nr, brdinfo->addr);
139
140			i2c_put_adapter(data->hpdev.adapter);
141			data->hpdev.adapter = NULL;
142			return PTR_ERR(client);
143		}
144
145		data->hpdev.client = client;
146		break;
147	case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
148		/* Export platform data to underlying device. */
149		if (data->hpdev.brdinfo && data->hpdev.brdinfo->platform_data)
150			mlxreg_hotplug_pdata_export(data->hpdev.brdinfo->platform_data,
151						    pdata->regmap);
152		/* Pass parent hotplug device handle to underlying device. */
153		data->notifier = data->hpdev.notifier;
154		data->hpdev.pdev = platform_device_register_resndata(&priv->pdev->dev,
155								     brdinfo->type,
156								     data->hpdev.nr,
157								     NULL, 0, data,
158								     sizeof(*data));
159		if (IS_ERR(data->hpdev.pdev))
160			return PTR_ERR(data->hpdev.pdev);
161
162		break;
163	default:
164		break;
165	}
166
167	if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
168		return data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 1);
169
170	return 0;
171}
172
173static void
174mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
175			      struct mlxreg_core_data *data,
176			      enum mlxreg_hotplug_kind kind)
177{
178	/* Notify user by sending hwmon uevent. */
179	mlxreg_hotplug_udev_event_send(&priv->hwmon->kobj, data, false);
180	if (data->hpdev.notifier && data->hpdev.notifier->user_handler)
181		data->hpdev.notifier->user_handler(data->hpdev.notifier->handle, kind, 0);
182
183	switch (data->hpdev.action) {
184	case MLXREG_HOTPLUG_DEVICE_DEFAULT_ACTION:
185		if (data->hpdev.client) {
186			i2c_unregister_device(data->hpdev.client);
187			data->hpdev.client = NULL;
188		}
189
190		if (data->hpdev.adapter) {
191			i2c_put_adapter(data->hpdev.adapter);
192			data->hpdev.adapter = NULL;
193		}
194		break;
195	case MLXREG_HOTPLUG_DEVICE_PLATFORM_ACTION:
196		if (data->hpdev.pdev)
197			platform_device_unregister(data->hpdev.pdev);
198		break;
199	default:
200		break;
201	}
202}
203
204static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
205					struct device_attribute *attr,
206					char *buf)
207{
208	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
209	struct mlxreg_core_hotplug_platform_data *pdata;
210	int index = to_sensor_dev_attr_2(attr)->index;
211	int nr = to_sensor_dev_attr_2(attr)->nr;
212	struct mlxreg_core_item *item;
213	struct mlxreg_core_data *data;
214	u32 regval;
215	int ret;
216
217	pdata = dev_get_platdata(&priv->pdev->dev);
218	item = pdata->items + nr;
219	data = item->data + index;
220
221	ret = regmap_read(priv->regmap, data->reg, &regval);
222	if (ret)
223		return ret;
224
225	if (item->health) {
226		regval &= data->mask;
227	} else {
228		/* Bit = 0 : functional if item->inversed is true. */
229		if (item->inversed)
230			regval = !(regval & data->mask);
231		else
232			regval = !!(regval & data->mask);
233	}
234
235	return sprintf(buf, "%u\n", regval);
236}
237
238#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
239#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
240
241static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit)
242{
243	int i, j;
244
245	for (i = 0, j = -1; i <= bit; i++) {
246		if (mask & BIT(i))
247			j++;
248	}
249	return j;
250}
251
252static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
253{
254	struct mlxreg_core_hotplug_platform_data *pdata;
255	struct mlxreg_core_item *item;
256	struct mlxreg_core_data *data;
257	unsigned long mask;
258	u32 regval;
259	int num_attrs = 0, id = 0, i, j, k, count, ret;
260
261	pdata = dev_get_platdata(&priv->pdev->dev);
262	item = pdata->items;
263
264	/* Go over all kinds of items - psu, pwr, fan. */
265	for (i = 0; i < pdata->counter; i++, item++) {
266		if (item->capability) {
267			/*
268			 * Read group capability register to get actual number
269			 * of interrupt capable components and set group mask
270			 * accordingly.
271			 */
272			ret = regmap_read(priv->regmap, item->capability,
273					  &regval);
274			if (ret)
275				return ret;
276
277			item->mask = GENMASK((regval & item->mask) - 1, 0);
278		}
279
280		data = item->data;
281
282		/* Go over all unmasked units within item. */
283		mask = item->mask;
284		k = 0;
285		count = item->ind ? item->ind : item->count;
286		for_each_set_bit(j, &mask, count) {
287			if (data->capability) {
288				/*
289				 * Read capability register and skip non
290				 * relevant attributes.
291				 */
292				ret = regmap_read(priv->regmap,
293						  data->capability, &regval);
294				if (ret)
295					return ret;
296
297				if (!(regval & data->bit)) {
298					data++;
299					continue;
300				}
301			}
302
303			PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
304			PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
305							     GFP_KERNEL,
306							     data->label);
307			if (!PRIV_ATTR(id)->name) {
308				dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
309					id);
310				return -ENOMEM;
311			}
312
313			PRIV_DEV_ATTR(id).dev_attr.attr.name =
314							PRIV_ATTR(id)->name;
315			PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
316			PRIV_DEV_ATTR(id).dev_attr.show =
317						mlxreg_hotplug_attr_show;
318			PRIV_DEV_ATTR(id).nr = i;
319			PRIV_DEV_ATTR(id).index = k;
320			sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
321			data++;
322			id++;
323			k++;
324		}
325		num_attrs += k;
326	}
327
328	priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
329					 num_attrs,
330					 sizeof(struct attribute *),
331					 GFP_KERNEL);
332	if (!priv->group.attrs)
333		return -ENOMEM;
334
335	priv->group.attrs = priv->mlxreg_hotplug_attr;
336	priv->groups[0] = &priv->group;
337	priv->groups[1] = NULL;
338
339	return 0;
340}
341
342static void
343mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
344			   struct mlxreg_core_item *item)
345{
346	struct mlxreg_core_data *data;
347	unsigned long asserted;
348	u32 regval, bit;
349	int ret;
350
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351	/* Mask event. */
352	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
353			   0);
354	if (ret)
355		goto out;
356
357	/* Read status. */
358	ret = regmap_read(priv->regmap, item->reg, &regval);
359	if (ret)
360		goto out;
361
362	/* Set asserted bits and save last status. */
363	regval &= item->mask;
364	asserted = item->cache ^ regval;
365	item->cache = regval;
366	for_each_set_bit(bit, &asserted, 8) {
367		int pos;
368
369		pos = mlxreg_hotplug_item_label_index_get(item->mask, bit);
370		if (pos < 0)
371			goto out;
372
373		data = item->data + pos;
374		if (regval & BIT(bit)) {
375			if (item->inversed)
376				mlxreg_hotplug_device_destroy(priv, data, item->kind);
377			else
378				mlxreg_hotplug_device_create(priv, data, item->kind);
379		} else {
380			if (item->inversed)
381				mlxreg_hotplug_device_create(priv, data, item->kind);
382			else
383				mlxreg_hotplug_device_destroy(priv, data, item->kind);
384		}
385	}
386
387	/* Acknowledge event. */
388	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
389			   0);
390	if (ret)
391		goto out;
392
393	/* Unmask event. */
394	ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
395			   item->mask);
396
397 out:
398	if (ret)
399		dev_err(priv->dev, "Failed to complete workqueue.\n");
400}
401
402static void
403mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
404				  struct mlxreg_core_item *item)
405{
406	struct mlxreg_core_data *data = item->data;
407	u32 regval;
408	int i, ret = 0;
409
410	for (i = 0; i < item->count; i++, data++) {
411		/* Mask event. */
412		ret = regmap_write(priv->regmap, data->reg +
413				   MLXREG_HOTPLUG_MASK_OFF, 0);
414		if (ret)
415			goto out;
416
417		/* Read status. */
418		ret = regmap_read(priv->regmap, data->reg, &regval);
419		if (ret)
420			goto out;
421
422		regval &= data->mask;
423
424		if (item->cache == regval)
425			goto ack_event;
426
427		/*
428		 * ASIC health indication is provided through two bits. Bits
429		 * value 0x2 indicates that ASIC reached the good health, value
430		 * 0x0 indicates ASIC the bad health or dormant state and value
431		 * 0x3 indicates the booting state. During ASIC reset it should
432		 * pass the following states: dormant -> booting -> good.
433		 */
434		if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
435			if (!data->attached) {
436				/*
437				 * ASIC is in steady state. Connect associated
438				 * device, if configured.
439				 */
440				mlxreg_hotplug_device_create(priv, data, item->kind);
441				data->attached = true;
442			}
443		} else {
444			if (data->attached) {
445				/*
446				 * ASIC health is failed after ASIC has been
447				 * in steady state. Disconnect associated
448				 * device, if it has been connected.
449				 */
450				mlxreg_hotplug_device_destroy(priv, data, item->kind);
451				data->attached = false;
452				data->health_cntr = 0;
453			}
454		}
455		item->cache = regval;
456ack_event:
457		/* Acknowledge event. */
458		ret = regmap_write(priv->regmap, data->reg +
459				   MLXREG_HOTPLUG_EVENT_OFF, 0);
460		if (ret)
461			goto out;
462
463		/* Unmask event. */
464		ret = regmap_write(priv->regmap, data->reg +
465				   MLXREG_HOTPLUG_MASK_OFF, data->mask);
466		if (ret)
467			goto out;
468	}
469
470 out:
471	if (ret)
472		dev_err(priv->dev, "Failed to complete workqueue.\n");
473}
474
475/*
476 * mlxreg_hotplug_work_handler - performs traversing of device interrupt
477 * registers according to the below hierarchy schema:
478 *
479 *				Aggregation registers (status/mask)
480 * PSU registers:		*---*
481 * *-----------------*		|   |
482 * |status/event/mask|----->    | * |
483 * *-----------------*		|   |
484 * Power registers:		|   |
485 * *-----------------*		|   |
486 * |status/event/mask|----->    | * |
487 * *-----------------*		|   |
488 * FAN registers:		|   |--> CPU
489 * *-----------------*		|   |
490 * |status/event/mask|----->    | * |
491 * *-----------------*		|   |
492 * ASIC registers:		|   |
493 * *-----------------*		|   |
494 * |status/event/mask|----->    | * |
495 * *-----------------*		|   |
496 *				*---*
497 *
498 * In case some system changed are detected: FAN in/out, PSU in/out, power
499 * cable attached/detached, ASIC health good/bad, relevant device is created
500 * or destroyed.
501 */
502static void mlxreg_hotplug_work_handler(struct work_struct *work)
503{
504	struct mlxreg_core_hotplug_platform_data *pdata;
505	struct mlxreg_hotplug_priv_data *priv;
506	struct mlxreg_core_item *item;
507	u32 regval, aggr_asserted;
508	unsigned long flags;
509	int i, ret;
510
511	priv = container_of(work, struct mlxreg_hotplug_priv_data,
512			    dwork_irq.work);
513	pdata = dev_get_platdata(&priv->pdev->dev);
514	item = pdata->items;
515
516	/* Mask aggregation event. */
517	ret = regmap_write(priv->regmap, pdata->cell +
518			   MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
519	if (ret < 0)
520		goto out;
521
522	/* Read aggregation status. */
523	ret = regmap_read(priv->regmap, pdata->cell, &regval);
524	if (ret)
525		goto out;
526
527	regval &= pdata->mask;
528	aggr_asserted = priv->aggr_cache ^ regval;
529	priv->aggr_cache = regval;
530
531	/*
532	 * Handler is invoked, but no assertion is detected at top aggregation
533	 * status level. Set aggr_asserted to mask value to allow handler extra
534	 * run over all relevant signals to recover any missed signal.
535	 */
536	if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
537		priv->not_asserted = 0;
538		aggr_asserted = pdata->mask;
539	}
540	if (!aggr_asserted)
541		goto unmask_event;
542
543	/* Handle topology and health configuration changes. */
544	for (i = 0; i < pdata->counter; i++, item++) {
545		if (aggr_asserted & item->aggr_mask) {
546			if (item->health)
547				mlxreg_hotplug_health_work_helper(priv, item);
548			else
549				mlxreg_hotplug_work_helper(priv, item);
550		}
551	}
552
553	spin_lock_irqsave(&priv->lock, flags);
554
555	/*
556	 * It is possible, that some signals have been inserted, while
557	 * interrupt has been masked by mlxreg_hotplug_work_handler. In this
558	 * case such signals will be missed. In order to handle these signals
559	 * delayed work is canceled and work task re-scheduled for immediate
560	 * execution. It allows to handle missed signals, if any. In other case
561	 * work handler just validates that no new signals have been received
562	 * during masking.
563	 */
564	cancel_delayed_work(&priv->dwork_irq);
565	schedule_delayed_work(&priv->dwork_irq, 0);
566
567	spin_unlock_irqrestore(&priv->lock, flags);
568
569	return;
570
571unmask_event:
572	priv->not_asserted++;
573	/* Unmask aggregation event (no need acknowledge). */
574	ret = regmap_write(priv->regmap, pdata->cell +
575			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
576
577 out:
578	if (ret)
579		dev_err(priv->dev, "Failed to complete workqueue.\n");
580}
581
582static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
583{
584	struct mlxreg_core_hotplug_platform_data *pdata;
585	struct mlxreg_core_item *item;
586	struct mlxreg_core_data *data;
587	u32 regval;
588	int i, j, ret;
589
590	pdata = dev_get_platdata(&priv->pdev->dev);
591	item = pdata->items;
592
593	for (i = 0; i < pdata->counter; i++, item++) {
594		/* Clear group presense event. */
595		ret = regmap_write(priv->regmap, item->reg +
596				   MLXREG_HOTPLUG_EVENT_OFF, 0);
597		if (ret)
598			goto out;
599
600		/*
601		 * Verify if hardware configuration requires to disable
602		 * interrupt capability for some of components.
603		 */
604		data = item->data;
605		for (j = 0; j < item->count; j++, data++) {
606			/* Verify if the attribute has capability register. */
607			if (data->capability) {
608				/* Read capability register. */
609				ret = regmap_read(priv->regmap,
610						  data->capability, &regval);
611				if (ret)
612					goto out;
613
614				if (!(regval & data->bit))
615					item->mask &= ~BIT(j);
616			}
617		}
618
619		/* Set group initial status as mask and unmask group event. */
620		if (item->inversed) {
621			item->cache = item->mask;
622			ret = regmap_write(priv->regmap, item->reg +
623					   MLXREG_HOTPLUG_MASK_OFF,
624					   item->mask);
625			if (ret)
626				goto out;
627		}
628	}
629
630	/* Keep aggregation initial status as zero and unmask events. */
631	ret = regmap_write(priv->regmap, pdata->cell +
632			   MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
633	if (ret)
634		goto out;
635
636	/* Keep low aggregation initial status as zero and unmask events. */
637	if (pdata->cell_low) {
638		ret = regmap_write(priv->regmap, pdata->cell_low +
639				   MLXREG_HOTPLUG_AGGR_MASK_OFF,
640				   pdata->mask_low);
641		if (ret)
642			goto out;
643	}
644
645	/* Invoke work handler for initializing hot plug devices setting. */
646	mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
647
648 out:
649	if (ret)
650		dev_err(priv->dev, "Failed to set interrupts.\n");
651	enable_irq(priv->irq);
652	return ret;
653}
654
655static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
656{
657	struct mlxreg_core_hotplug_platform_data *pdata;
658	struct mlxreg_core_item *item;
659	struct mlxreg_core_data *data;
660	int count, i, j;
661
662	pdata = dev_get_platdata(&priv->pdev->dev);
663	item = pdata->items;
664	disable_irq(priv->irq);
665	cancel_delayed_work_sync(&priv->dwork_irq);
666
667	/* Mask low aggregation event, if defined. */
668	if (pdata->cell_low)
669		regmap_write(priv->regmap, pdata->cell_low +
670			     MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
671
672	/* Mask aggregation event. */
673	regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
674		     0);
675
676	/* Clear topology configurations. */
677	for (i = 0; i < pdata->counter; i++, item++) {
678		data = item->data;
679		/* Mask group presense event. */
680		regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
681			     0);
682		/* Clear group presense event. */
683		regmap_write(priv->regmap, data->reg +
684			     MLXREG_HOTPLUG_EVENT_OFF, 0);
685
686		/* Remove all the attached devices in group. */
687		count = item->count;
688		for (j = 0; j < count; j++, data++)
689			mlxreg_hotplug_device_destroy(priv, data, item->kind);
690	}
691}
692
693static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
694{
695	struct mlxreg_hotplug_priv_data *priv;
696
697	priv = (struct mlxreg_hotplug_priv_data *)dev;
698
699	/* Schedule work task for immediate execution.*/
700	schedule_delayed_work(&priv->dwork_irq, 0);
701
702	return IRQ_HANDLED;
703}
704
705static int mlxreg_hotplug_probe(struct platform_device *pdev)
706{
707	struct mlxreg_core_hotplug_platform_data *pdata;
708	struct mlxreg_hotplug_priv_data *priv;
709	struct i2c_adapter *deferred_adap;
710	int err;
711
712	pdata = dev_get_platdata(&pdev->dev);
713	if (!pdata) {
714		dev_err(&pdev->dev, "Failed to get platform data.\n");
715		return -EINVAL;
716	}
717
718	/* Defer probing if the necessary adapter is not configured yet. */
719	deferred_adap = i2c_get_adapter(pdata->deferred_nr);
720	if (!deferred_adap)
721		return -EPROBE_DEFER;
722	i2c_put_adapter(deferred_adap);
723
724	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
725	if (!priv)
726		return -ENOMEM;
727
728	if (pdata->irq) {
729		priv->irq = pdata->irq;
730	} else {
731		priv->irq = platform_get_irq(pdev, 0);
732		if (priv->irq < 0)
733			return priv->irq;
734	}
735
736	priv->regmap = pdata->regmap;
737	priv->dev = pdev->dev.parent;
738	priv->pdev = pdev;
739
740	err = devm_request_irq(&pdev->dev, priv->irq,
741			       mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
742			       | IRQF_SHARED, "mlxreg-hotplug", priv);
743	if (err) {
744		dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
745		return err;
746	}
747
748	disable_irq(priv->irq);
749	spin_lock_init(&priv->lock);
750	INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
751	dev_set_drvdata(&pdev->dev, priv);
752
753	err = mlxreg_hotplug_attr_init(priv);
754	if (err) {
755		dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
756			err);
757		return err;
758	}
759
760	priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
761					"mlxreg_hotplug", priv, priv->groups);
762	if (IS_ERR(priv->hwmon)) {
763		dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
764			PTR_ERR(priv->hwmon));
765		return PTR_ERR(priv->hwmon);
766	}
767
768	/* Perform initial interrupts setup. */
769	mlxreg_hotplug_set_irq(priv);
770	priv->after_probe = true;
771
772	return 0;
773}
774
775static void mlxreg_hotplug_remove(struct platform_device *pdev)
776{
777	struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
778
779	/* Clean interrupts setup. */
780	mlxreg_hotplug_unset_irq(priv);
781	devm_free_irq(&pdev->dev, priv->irq, priv);
782}
783
784static struct platform_driver mlxreg_hotplug_driver = {
785	.driver = {
786		.name = "mlxreg-hotplug",
787	},
788	.probe = mlxreg_hotplug_probe,
789	.remove_new = mlxreg_hotplug_remove,
790};
791
792module_platform_driver(mlxreg_hotplug_driver);
793
794MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
795MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
796MODULE_LICENSE("Dual BSD/GPL");
797MODULE_ALIAS("platform:mlxreg-hotplug");