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
508 ret = regmap_write(priv->regmap, item->reg +
509 MLXREG_HOTPLUG_EVENT_OFF, 0);
510 if (ret)
511 goto out;
512
513
514
515
516
517 data = item->data;
518 for (j = 0; j < item->count; j++, data++) {
519
520 if (data->capability) {
521
522 ret = regmap_read(priv->regmap,
523 data->capability, ®val);
524 if (ret)
525 goto out;
526
527 if (!(regval & data->bit))
528 item->mask &= ~BIT(j);
529 }
530 }
531
532
533 if (item->inversed) {
534 item->cache = item->mask;
535 ret = regmap_write(priv->regmap, item->reg +
536 MLXREG_HOTPLUG_MASK_OFF,
537 item->mask);
538 if (ret)
539 goto out;
540 }
541 }
542
543
544 ret = regmap_write(priv->regmap, pdata->cell +
545 MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
546 if (ret)
547 goto out;
548
549
550 if (pdata->cell_low) {
551 ret = regmap_write(priv->regmap, pdata->cell_low +
552 MLXREG_HOTPLUG_AGGR_MASK_OFF,
553 pdata->mask_low);
554 if (ret)
555 goto out;
556 }
557
558
559 mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
560
561 out:
562 if (ret)
563 dev_err(priv->dev, "Failed to set interrupts.\n");
564 enable_irq(priv->irq);
565 return ret;
566}
567
568static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
569{
570 struct mlxreg_core_hotplug_platform_data *pdata;
571 struct mlxreg_core_item *item;
572 struct mlxreg_core_data *data;
573 int count, i, j;
574
575 pdata = dev_get_platdata(&priv->pdev->dev);
576 item = pdata->items;
577 disable_irq(priv->irq);
578 cancel_delayed_work_sync(&priv->dwork_irq);
579
580
581 if (pdata->cell_low)
582 regmap_write(priv->regmap, pdata->cell_low +
583 MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
584
585
586 regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
587 0);
588
589
590 for (i = 0; i < pdata->counter; i++, item++) {
591 data = item->data;
592
593 regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
594 0);
595
596 regmap_write(priv->regmap, data->reg +
597 MLXREG_HOTPLUG_EVENT_OFF, 0);
598
599
600 count = item->count;
601 for (j = 0; j < count; j++, data++)
602 mlxreg_hotplug_device_destroy(priv, data);
603 }
604}
605
606static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
607{
608 struct mlxreg_hotplug_priv_data *priv;
609
610 priv = (struct mlxreg_hotplug_priv_data *)dev;
611
612
613 schedule_delayed_work(&priv->dwork_irq, 0);
614
615 return IRQ_HANDLED;
616}
617
618static int mlxreg_hotplug_probe(struct platform_device *pdev)
619{
620 struct mlxreg_core_hotplug_platform_data *pdata;
621 struct mlxreg_hotplug_priv_data *priv;
622 struct i2c_adapter *deferred_adap;
623 int err;
624
625 pdata = dev_get_platdata(&pdev->dev);
626 if (!pdata) {
627 dev_err(&pdev->dev, "Failed to get platform data.\n");
628 return -EINVAL;
629 }
630
631
632 deferred_adap = i2c_get_adapter(pdata->deferred_nr);
633 if (!deferred_adap)
634 return -EPROBE_DEFER;
635 i2c_put_adapter(deferred_adap);
636
637 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
638 if (!priv)
639 return -ENOMEM;
640
641 if (pdata->irq) {
642 priv->irq = pdata->irq;
643 } else {
644 priv->irq = platform_get_irq(pdev, 0);
645 if (priv->irq < 0) {
646 dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
647 priv->irq);
648 return priv->irq;
649 }
650 }
651
652 priv->regmap = pdata->regmap;
653 priv->dev = pdev->dev.parent;
654 priv->pdev = pdev;
655
656 err = devm_request_irq(&pdev->dev, priv->irq,
657 mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
658 | IRQF_SHARED, "mlxreg-hotplug", priv);
659 if (err) {
660 dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
661 return err;
662 }
663
664 disable_irq(priv->irq);
665 spin_lock_init(&priv->lock);
666 INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
667 dev_set_drvdata(&pdev->dev, priv);
668
669 err = mlxreg_hotplug_attr_init(priv);
670 if (err) {
671 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
672 err);
673 return err;
674 }
675
676 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
677 "mlxreg_hotplug", priv, priv->groups);
678 if (IS_ERR(priv->hwmon)) {
679 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
680 PTR_ERR(priv->hwmon));
681 return PTR_ERR(priv->hwmon);
682 }
683
684
685 mlxreg_hotplug_set_irq(priv);
686 priv->after_probe = true;
687
688 return 0;
689}
690
691static int mlxreg_hotplug_remove(struct platform_device *pdev)
692{
693 struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
694
695
696 mlxreg_hotplug_unset_irq(priv);
697
698 return 0;
699}
700
701static struct platform_driver mlxreg_hotplug_driver = {
702 .driver = {
703 .name = "mlxreg-hotplug",
704 },
705 .probe = mlxreg_hotplug_probe,
706 .remove = mlxreg_hotplug_remove,
707};
708
709module_platform_driver(mlxreg_hotplug_driver);
710
711MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
712MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
713MODULE_LICENSE("Dual BSD/GPL");
714MODULE_ALIAS("platform:mlxreg-hotplug");
715