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