1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/bitops.h>
35#include <linux/device.h>
36#include <linux/hwmon.h>
37#include <linux/hwmon-sysfs.h>
38#include <linux/i2c.h>
39#include <linux/interrupt.h>
40#include <linux/module.h>
41#include <linux/of_device.h>
42#include <linux/platform_data/mlxreg.h>
43#include <linux/platform_device.h>
44#include <linux/spinlock.h>
45#include <linux/regmap.h>
46#include <linux/workqueue.h>
47
48
49#define MLXREG_HOTPLUG_EVENT_OFF 1
50#define MLXREG_HOTPLUG_MASK_OFF 2
51#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
52
53
54#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02
55
56#define MLXREG_HOTPLUG_ATTRS_MAX 24
57#define MLXREG_HOTPLUG_NOT_ASSERT 3
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79struct mlxreg_hotplug_priv_data {
80 int irq;
81 struct device *dev;
82 struct platform_device *pdev;
83 struct mlxreg_hotplug_platform_data *plat;
84 struct regmap *regmap;
85 struct delayed_work dwork_irq;
86 spinlock_t lock;
87 struct device *hwmon;
88 struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
89 struct sensor_device_attribute_2
90 mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
91 struct attribute_group group;
92 const struct attribute_group *groups[2];
93 u32 cell;
94 u32 mask;
95 u32 aggr_cache;
96 bool after_probe;
97 u8 not_asserted;
98};
99
100static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv,
101 struct mlxreg_core_data *data)
102{
103 struct mlxreg_core_hotplug_platform_data *pdata;
104
105
106 kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
107
108
109
110
111
112 if (data->hpdev.nr < 0)
113 return 0;
114
115 pdata = dev_get_platdata(&priv->pdev->dev);
116 data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr +
117 pdata->shift_nr);
118 if (!data->hpdev.adapter) {
119 dev_err(priv->dev, "Failed to get adapter for bus %d\n",
120 data->hpdev.nr + pdata->shift_nr);
121 return -EFAULT;
122 }
123
124 data->hpdev.client = i2c_new_device(data->hpdev.adapter,
125 data->hpdev.brdinfo);
126 if (!data->hpdev.client) {
127 dev_err(priv->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
128 data->hpdev.brdinfo->type, data->hpdev.nr +
129 pdata->shift_nr, data->hpdev.brdinfo->addr);
130
131 i2c_put_adapter(data->hpdev.adapter);
132 data->hpdev.adapter = NULL;
133 return -EFAULT;
134 }
135
136 return 0;
137}
138
139static void
140mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv,
141 struct mlxreg_core_data *data)
142{
143
144 kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE);
145
146 if (data->hpdev.client) {
147 i2c_unregister_device(data->hpdev.client);
148 data->hpdev.client = NULL;
149 }
150
151 if (data->hpdev.adapter) {
152 i2c_put_adapter(data->hpdev.adapter);
153 data->hpdev.adapter = NULL;
154 }
155}
156
157static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
158 struct device_attribute *attr,
159 char *buf)
160{
161 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
162 struct mlxreg_core_hotplug_platform_data *pdata;
163 int index = to_sensor_dev_attr_2(attr)->index;
164 int nr = to_sensor_dev_attr_2(attr)->nr;
165 struct mlxreg_core_item *item;
166 struct mlxreg_core_data *data;
167 u32 regval;
168 int ret;
169
170 pdata = dev_get_platdata(&priv->pdev->dev);
171 item = pdata->items + nr;
172 data = item->data + index;
173
174 ret = regmap_read(priv->regmap, data->reg, ®val);
175 if (ret)
176 return ret;
177
178 if (item->health) {
179 regval &= data->mask;
180 } else {
181
182 if (item->inversed)
183 regval = !(regval & data->mask);
184 else
185 regval = !!(regval & data->mask);
186 }
187
188 return sprintf(buf, "%u\n", regval);
189}
190
191#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
192#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
193
194static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
195{
196 struct mlxreg_core_hotplug_platform_data *pdata;
197 struct mlxreg_core_item *item;
198 struct mlxreg_core_data *data;
199 int num_attrs = 0, id = 0, i, j;
200
201 pdata = dev_get_platdata(&priv->pdev->dev);
202 item = pdata->items;
203
204
205 for (i = 0; i < pdata->counter; i++, item++) {
206 num_attrs += item->count;
207 data = item->data;
208
209 for (j = 0; j < item->count; j++, data++, id++) {
210 PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
211 PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
212 GFP_KERNEL,
213 data->label);
214
215 if (!PRIV_ATTR(id)->name) {
216 dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
217 id);
218 return -ENOMEM;
219 }
220
221 PRIV_DEV_ATTR(id).dev_attr.attr.name =
222 PRIV_ATTR(id)->name;
223 PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
224 PRIV_DEV_ATTR(id).dev_attr.show =
225 mlxreg_hotplug_attr_show;
226 PRIV_DEV_ATTR(id).nr = i;
227 PRIV_DEV_ATTR(id).index = j;
228 sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
229 }
230 }
231
232 priv->group.attrs = devm_kcalloc(&priv->pdev->dev,
233 num_attrs,
234 sizeof(struct attribute *),
235 GFP_KERNEL);
236 if (!priv->group.attrs)
237 return -ENOMEM;
238
239 priv->group.attrs = priv->mlxreg_hotplug_attr;
240 priv->groups[0] = &priv->group;
241 priv->groups[1] = NULL;
242
243 return 0;
244}
245
246static void
247mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
248 struct mlxreg_core_item *item)
249{
250 struct mlxreg_core_data *data;
251 unsigned long asserted;
252 u32 regval, bit;
253 int ret;
254
255
256
257
258
259
260
261
262 if (unlikely(!item)) {
263 dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
264 item->reg, item->mask);
265
266 return;
267 }
268
269
270 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
271 0);
272 if (ret)
273 goto out;
274
275
276 ret = regmap_read(priv->regmap, item->reg, ®val);
277 if (ret)
278 goto out;
279
280
281 regval &= item->mask;
282 asserted = item->cache ^ regval;
283 item->cache = regval;
284
285 for_each_set_bit(bit, &asserted, 8) {
286 data = item->data + bit;
287 if (regval & BIT(bit)) {
288 if (item->inversed)
289 mlxreg_hotplug_device_destroy(priv, data);
290 else
291 mlxreg_hotplug_device_create(priv, data);
292 } else {
293 if (item->inversed)
294 mlxreg_hotplug_device_create(priv, data);
295 else
296 mlxreg_hotplug_device_destroy(priv, data);
297 }
298 }
299
300
301 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
302 0);
303 if (ret)
304 goto out;
305
306
307 ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
308 item->mask);
309
310 out:
311 if (ret)
312 dev_err(priv->dev, "Failed to complete workqueue.\n");
313}
314
315static void
316mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
317 struct mlxreg_core_item *item)
318{
319 struct mlxreg_core_data *data = item->data;
320 u32 regval;
321 int i, ret = 0;
322
323 for (i = 0; i < item->count; i++, data++) {
324
325 ret = regmap_write(priv->regmap, data->reg +
326 MLXREG_HOTPLUG_MASK_OFF, 0);
327 if (ret)
328 goto out;
329
330
331 ret = regmap_read(priv->regmap, data->reg, ®val);
332 if (ret)
333 goto out;
334
335 regval &= data->mask;
336
337 if (item->cache == regval)
338 goto ack_event;
339
340
341
342
343
344
345
346
347 if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) {
348 if (!data->attached) {
349
350
351
352
353 mlxreg_hotplug_device_create(priv, data);
354 data->attached = true;
355 }
356 } else {
357 if (data->attached) {
358
359
360
361
362
363 mlxreg_hotplug_device_destroy(priv, data);
364 data->attached = false;
365 data->health_cntr = 0;
366 }
367 }
368 item->cache = regval;
369ack_event:
370
371 ret = regmap_write(priv->regmap, data->reg +
372 MLXREG_HOTPLUG_EVENT_OFF, 0);
373 if (ret)
374 goto out;
375
376
377 ret = regmap_write(priv->regmap, data->reg +
378 MLXREG_HOTPLUG_MASK_OFF, data->mask);
379 if (ret)
380 goto out;
381 }
382
383 out:
384 if (ret)
385 dev_err(priv->dev, "Failed to complete workqueue.\n");
386}
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415static void mlxreg_hotplug_work_handler(struct work_struct *work)
416{
417 struct mlxreg_core_hotplug_platform_data *pdata;
418 struct mlxreg_hotplug_priv_data *priv;
419 struct mlxreg_core_item *item;
420 u32 regval, aggr_asserted;
421 unsigned long flags;
422 int i, ret;
423
424 priv = container_of(work, struct mlxreg_hotplug_priv_data,
425 dwork_irq.work);
426 pdata = dev_get_platdata(&priv->pdev->dev);
427 item = pdata->items;
428
429
430 ret = regmap_write(priv->regmap, pdata->cell +
431 MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
432 if (ret < 0)
433 goto out;
434
435
436 ret = regmap_read(priv->regmap, pdata->cell, ®val);
437 if (ret)
438 goto out;
439
440 regval &= pdata->mask;
441 aggr_asserted = priv->aggr_cache ^ regval;
442 priv->aggr_cache = regval;
443
444
445
446
447
448
449 if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
450 priv->not_asserted = 0;
451 aggr_asserted = pdata->mask;
452 }
453 if (!aggr_asserted)
454 goto unmask_event;
455
456
457 for (i = 0; i < pdata->counter; i++, item++) {
458 if (aggr_asserted & item->aggr_mask) {
459 if (item->health)
460 mlxreg_hotplug_health_work_helper(priv, item);
461 else
462 mlxreg_hotplug_work_helper(priv, item);
463 }
464 }
465
466 spin_lock_irqsave(&priv->lock, flags);
467
468
469
470
471
472
473
474
475
476
477 cancel_delayed_work(&priv->dwork_irq);
478 schedule_delayed_work(&priv->dwork_irq, 0);
479
480 spin_unlock_irqrestore(&priv->lock, flags);
481
482 return;
483
484unmask_event:
485 priv->not_asserted++;
486
487 ret = regmap_write(priv->regmap, pdata->cell +
488 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
489
490 out:
491 if (ret)
492 dev_err(priv->dev, "Failed to complete workqueue.\n");
493}
494
495static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
496{
497 struct mlxreg_core_hotplug_platform_data *pdata;
498 struct mlxreg_core_item *item;
499 struct mlxreg_core_data *data;
500 u32 regval;
501 int i, j, ret;
502
503 pdata = dev_get_platdata(&priv->pdev->dev);
504 item = pdata->items;
505
506 for (i = 0; i < pdata->counter; i++, item++) {
507 if (item->capability) {
508
509
510
511
512
513 ret = regmap_read(priv->regmap, item->capability,
514 ®val);
515 if (ret)
516 goto out;
517
518 item->mask = GENMASK((regval & item->mask) - 1, 0);
519 }
520
521
522 ret = regmap_write(priv->regmap, item->reg +
523 MLXREG_HOTPLUG_EVENT_OFF, 0);
524 if (ret)
525 goto out;
526
527
528
529
530
531 data = item->data;
532 for (j = 0; j < item->count; j++, data++) {
533
534 if (data->capability) {
535
536 ret = regmap_read(priv->regmap,
537 data->capability, ®val);
538 if (ret)
539 goto out;
540
541 if (!(regval & data->bit))
542 item->mask &= ~BIT(j);
543 }
544 }
545
546
547 if (item->inversed) {
548 item->cache = item->mask;
549 ret = regmap_write(priv->regmap, item->reg +
550 MLXREG_HOTPLUG_MASK_OFF,
551 item->mask);
552 if (ret)
553 goto out;
554 }
555 }
556
557
558 ret = regmap_write(priv->regmap, pdata->cell +
559 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
560 if (ret)
561 goto out;
562
563
564 if (pdata->cell_low) {
565 ret = regmap_write(priv->regmap, pdata->cell_low +
566 MLXREG_HOTPLUG_AGGR_MASK_OFF,
567 pdata->mask_low);
568 if (ret)
569 goto out;
570 }
571
572
573 mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
574
575 out:
576 if (ret)
577 dev_err(priv->dev, "Failed to set interrupts.\n");
578 enable_irq(priv->irq);
579 return ret;
580}
581
582static void mlxreg_hotplug_unset_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 int count, i, j;
588
589 pdata = dev_get_platdata(&priv->pdev->dev);
590 item = pdata->items;
591 disable_irq(priv->irq);
592 cancel_delayed_work_sync(&priv->dwork_irq);
593
594
595 if (pdata->cell_low)
596 regmap_write(priv->regmap, pdata->cell_low +
597 MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
598
599
600 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
601 0);
602
603
604 for (i = 0; i < pdata->counter; i++, item++) {
605 data = item->data;
606
607 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
608 0);
609
610 regmap_write(priv->regmap, data->reg +
611 MLXREG_HOTPLUG_EVENT_OFF, 0);
612
613
614 count = item->count;
615 for (j = 0; j < count; j++, data++)
616 mlxreg_hotplug_device_destroy(priv, data);
617 }
618}
619
620static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
621{
622 struct mlxreg_hotplug_priv_data *priv;
623
624 priv = (struct mlxreg_hotplug_priv_data *)dev;
625
626
627 schedule_delayed_work(&priv->dwork_irq, 0);
628
629 return IRQ_HANDLED;
630}
631
632static int mlxreg_hotplug_probe(struct platform_device *pdev)
633{
634 struct mlxreg_core_hotplug_platform_data *pdata;
635 struct mlxreg_hotplug_priv_data *priv;
636 struct i2c_adapter *deferred_adap;
637 int err;
638
639 pdata = dev_get_platdata(&pdev->dev);
640 if (!pdata) {
641 dev_err(&pdev->dev, "Failed to get platform data.\n");
642 return -EINVAL;
643 }
644
645
646 deferred_adap = i2c_get_adapter(pdata->deferred_nr);
647 if (!deferred_adap)
648 return -EPROBE_DEFER;
649 i2c_put_adapter(deferred_adap);
650
651 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
652 if (!priv)
653 return -ENOMEM;
654
655 if (pdata->irq) {
656 priv->irq = pdata->irq;
657 } else {
658 priv->irq = platform_get_irq(pdev, 0);
659 if (priv->irq < 0)
660 return priv->irq;
661 }
662
663 priv->regmap = pdata->regmap;
664 priv->dev = pdev->dev.parent;
665 priv->pdev = pdev;
666
667 err = devm_request_irq(&pdev->dev, priv->irq,
668 mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
669 | IRQF_SHARED, "mlxreg-hotplug", priv);
670 if (err) {
671 dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
672 return err;
673 }
674
675 disable_irq(priv->irq);
676 spin_lock_init(&priv->lock);
677 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
678 dev_set_drvdata(&pdev->dev, priv);
679
680 err = mlxreg_hotplug_attr_init(priv);
681 if (err) {
682 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
683 err);
684 return err;
685 }
686
687 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
688 "mlxreg_hotplug", priv, priv->groups);
689 if (IS_ERR(priv->hwmon)) {
690 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
691 PTR_ERR(priv->hwmon));
692 return PTR_ERR(priv->hwmon);
693 }
694
695
696 mlxreg_hotplug_set_irq(priv);
697 priv->after_probe = true;
698
699 return 0;
700}
701
702static int mlxreg_hotplug_remove(struct platform_device *pdev)
703{
704 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
705
706
707 mlxreg_hotplug_unset_irq(priv);
708 devm_free_irq(&pdev->dev, priv->irq, priv);
709
710 return 0;
711}
712
713static struct platform_driver mlxreg_hotplug_driver = {
714 .driver = {
715 .name = "mlxreg-hotplug",
716 },
717 .probe = mlxreg_hotplug_probe,
718 .remove = mlxreg_hotplug_remove,
719};
720
721module_platform_driver(mlxreg_hotplug_driver);
722
723MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
724MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
725MODULE_LICENSE("Dual BSD/GPL");
726MODULE_ALIAS("platform:mlxreg-hotplug");
727