1 /*
2 * Copyright (C) 2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18 #include <linux/module.h>
19 #include <linux/init.h>
20 #include <linux/dma-mapping.h>
21 #include <linux/err.h>
22 #include <linux/slab.h>
23 #include <linux/string.h>
24 #include <linux/version.h>
25 #include "securec.h"
26 #include "himedia_base.h"
27
28
29 /* himedia bus */
himedia_bus_release(struct device * dev)30 static void himedia_bus_release(struct device *dev)
31 {
32 return;
33 }
34
35 struct device g_himedia_bus = {
36 .init_name = "himedia_bus_dev",
37 .release = himedia_bus_release
38 };
39
40 /* top level bus, parent and bus member are both NULL */ /* CNcomment:这是顶层总线,parent 和 bus 成员为NULL */
41
modalias_show(struct device * dev,struct device_attribute * a,char * buf)42 static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
43 char *buf)
44 {
45 pm_basedev *pdev = TO_PM_BASEDEV(dev);
46 int len = snprintf_s(buf, PAGE_SIZE, (PAGE_SIZE - 1), "himedia:%s\n", (char *)pdev->name);
47 if (len < 0) {
48 printk("modalias_show call snprintf_s failed!\n");
49 }
50
51 return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
52 }
53
54
55 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
56 static DEVICE_ATTR_RO(modalias);
57
58 static struct attribute *g_himedia_dev_attrs[] = {
59 &dev_attr_modalias.attr,
60 NULL,
61 };
62
63 ATTRIBUTE_GROUPS(g_himedia_dev);
64 #else
65 static struct device_attribute g_himedia_dev_attrs[] = {
66 __ATTR_RO(modalias),
67 __ATTR_NULL,
68 };
69 #endif
70
himedia_match(struct device * dev,struct device_driver * drv)71 static int himedia_match(struct device *dev, struct device_driver *drv)
72 {
73 pm_basedev *pdev = TO_PM_BASEDEV(dev);
74 return (strncmp(pdev->name, drv->name, HIMEDIA_DEVICE_NAME_MAX_LEN + 8) == 0); /* 8 用于计算drv->name的长度 */
75 }
76
himedia_uevent(struct device * dev,struct kobj_uevent_env * env)77 static int himedia_uevent(struct device *dev, struct kobj_uevent_env *env)
78 {
79 int ret;
80 pm_basedev *pdev = TO_PM_BASEDEV(dev);
81 ret = add_uevent_var(env, "MODALIAS=himedia:%s", pdev->name);
82 if (ret) {
83 return ret;
84 }
85 return 0;
86 }
87
88 #if 1
himedia_legacy_suspend(struct device * dev,pm_message_t mesg)89 static int himedia_legacy_suspend(struct device *dev, pm_message_t mesg)
90 {
91 int ret = 0;
92
93 if (dev->driver && dev->driver->suspend) {
94 ret = dev->driver->suspend(dev, mesg);
95 }
96
97 return ret;
98 }
99
himedia_legacy_suspend_late(struct device * dev,pm_message_t mesg)100 static int himedia_legacy_suspend_late(struct device *dev, pm_message_t mesg)
101 {
102 int ret = 0;
103 pm_basedev *pdev = TO_PM_BASEDEV(dev);
104 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
105
106 if (dev->driver && pdrv->suspend_late) {
107 ret = pdrv->suspend_late(pdev, mesg);
108 }
109
110 return ret;
111 }
112
himedia_legacy_resume_early(struct device * dev)113 static int himedia_legacy_resume_early(struct device *dev)
114 {
115 int ret = 0;
116 pm_basedev *pdev = TO_PM_BASEDEV(dev);
117 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
118
119 if (dev->driver && pdrv->resume_early) {
120 ret = pdrv->resume_early(pdev);
121 }
122
123 return ret;
124 }
125
himedia_legacy_resume(struct device * dev)126 static int himedia_legacy_resume(struct device *dev)
127 {
128 int ret = 0;
129
130 if (dev->driver && dev->driver->resume) {
131 ret = dev->driver->resume(dev);
132 }
133
134 return ret;
135 }
136
himedia_pm_prepare(struct device * dev)137 static int himedia_pm_prepare(struct device *dev)
138 {
139 struct device_driver *drv = dev->driver;
140 int ret = 0;
141
142 if (drv != NULL && drv->pm && drv->pm->prepare) {
143 ret = drv->pm->prepare(dev);
144 }
145
146 return ret;
147 }
148
himedia_pm_complete(struct device * dev)149 static void himedia_pm_complete(struct device *dev)
150 {
151 struct device_driver *drv = dev->driver;
152
153 if (drv != NULL && drv->pm && drv->pm->complete) {
154 drv->pm->complete(dev);
155 }
156 }
157
158 #if 1
159
himedia_pm_suspend(struct device * dev)160 static int himedia_pm_suspend(struct device *dev)
161 {
162 int ret = 0;
163 struct device_driver *drv = dev->driver;
164
165 if (drv == HI_NULL) {
166 return 0;
167 }
168
169 if (drv->pm) {
170 if (drv->pm->suspend) {
171 ret = drv->pm->suspend(dev);
172 }
173 } else {
174 ret = himedia_legacy_suspend(dev, PMSG_SUSPEND);
175 }
176
177 return ret;
178 }
179
himedia_pm_suspend_noirq(struct device * dev)180 static int himedia_pm_suspend_noirq(struct device *dev)
181 {
182 int ret = 0;
183 struct device_driver *drv = dev->driver;
184
185 if (drv == HI_NULL) {
186 return 0;
187 }
188
189 if (drv->pm) {
190 if (drv->pm->suspend_noirq) {
191 ret = drv->pm->suspend_noirq(dev);
192 }
193 } else {
194 ret = himedia_legacy_suspend_late(dev, PMSG_SUSPEND);
195 }
196
197 return ret;
198 }
199
himedia_pm_resume(struct device * dev)200 static int himedia_pm_resume(struct device *dev)
201 {
202 int ret = 0;
203 struct device_driver *drv = dev->driver;
204
205 if (drv == NULL) {
206 return 0;
207 }
208
209 if (drv->pm) {
210 if (drv->pm->resume) {
211 ret = drv->pm->resume(dev);
212 }
213 } else {
214 ret = himedia_legacy_resume(dev);
215 }
216
217 return ret;
218 }
219
himedia_pm_resume_noirq(struct device * dev)220 static int himedia_pm_resume_noirq(struct device *dev)
221 {
222 int ret = 0;
223 struct device_driver *drv = dev->driver;
224
225 if (drv == NULL) {
226 return 0;
227 }
228
229 if (drv->pm) {
230 if (drv->pm->resume_noirq) {
231 ret = drv->pm->resume_noirq(dev);
232 }
233 } else {
234 ret = himedia_legacy_resume_early(dev);
235 }
236
237 return ret;
238 }
239
240 #else /* !CONFIG_SUSPEND */
241
242 #define himedia_pm_suspend NULL
243 #define himedia_pm_resume NULL
244 #define himedia_pm_suspend_noirq NULL
245 #define himedia_pm_resume_noirq NULL
246
247 #endif /* !CONFIG_SUSPEND */
248
249 #ifdef CONFIG_HISI_SNAPSHOT_BOOT
himedia_pm_freeze(struct device * dev)250 static int himedia_pm_freeze(struct device *dev)
251 {
252 int ret = 0;
253 struct device_driver *drv = dev->driver;
254
255 if (drv == NULL) {
256 return 0;
257 }
258
259 if (drv->pm) {
260 if (drv->pm->freeze) {
261 ret = drv->pm->freeze(dev);
262 }
263 } else {
264 ret = himedia_legacy_suspend(dev, PMSG_FREEZE);
265 }
266
267 return ret;
268 }
269
himedia_pm_freeze_noirq(struct device * dev)270 static int himedia_pm_freeze_noirq(struct device *dev)
271 {
272 int ret = 0;
273 struct device_driver *drv = dev->driver;
274
275 if (drv == NULL) {
276 return 0;
277 }
278
279 if (drv->pm) {
280 if (drv->pm->freeze_noirq) {
281 ret = drv->pm->freeze_noirq(dev);
282 }
283 } else {
284 ret = himedia_legacy_suspend_late(dev, PMSG_FREEZE);
285 }
286
287 return ret;
288 }
289
himedia_pm_thaw(struct device * dev)290 static int himedia_pm_thaw(struct device *dev)
291 {
292 int ret = 0;
293 struct device_driver *drv = dev->driver;
294
295 if (drv == NULL) {
296 return 0;
297 }
298
299 if (drv->pm) {
300 if (drv->pm->thaw) {
301 ret = drv->pm->thaw(dev);
302 }
303 } else {
304 ret = himedia_legacy_resume(dev);
305 }
306
307 return ret;
308 }
309
himedia_pm_thaw_noirq(struct device * dev)310 static int himedia_pm_thaw_noirq(struct device *dev)
311 {
312 int ret = 0;
313 struct device_driver *drv = dev->driver;
314
315 if (drv == NULL) {
316 return 0;
317 }
318
319 if (drv->pm) {
320 if (drv->pm->thaw_noirq) {
321 ret = drv->pm->thaw_noirq(dev);
322 }
323 } else {
324 ret = himedia_legacy_resume_early(dev);
325 }
326
327 return ret;
328 }
329
himedia_pm_poweroff(struct device * dev)330 static int himedia_pm_poweroff(struct device *dev)
331 {
332 int ret = 0;
333 struct device_driver *drv = dev->driver;
334
335 if (drv == NULL) {
336 return 0;
337 }
338
339 if (drv->pm) {
340 if (drv->pm->poweroff) {
341 ret = drv->pm->poweroff(dev);
342 }
343 } else {
344 ret = himedia_legacy_suspend(dev, PMSG_HIBERNATE);
345 }
346
347 return ret;
348 }
349
himedia_pm_poweroff_noirq(struct device * dev)350 static int himedia_pm_poweroff_noirq(struct device *dev)
351 {
352 int ret = 0;
353 struct device_driver *drv = dev->driver;
354
355 if (drv == HI_NULL) {
356 return 0;
357 }
358
359 if (drv->pm) {
360 if (drv->pm->poweroff_noirq) {
361 ret = drv->pm->poweroff_noirq(dev);
362 }
363 } else {
364 ret = himedia_legacy_suspend_late(dev, PMSG_HIBERNATE);
365 }
366
367 return ret;
368 }
369
himedia_pm_restore(struct device * dev)370 static int himedia_pm_restore(struct device *dev)
371 {
372 int ret = 0;
373 struct device_driver *drv = dev->driver;
374
375 if (drv == NULL) {
376 return 0;
377 }
378
379 if (drv->pm) {
380 if (drv->pm->restore) {
381 ret = drv->pm->restore(dev);
382 }
383 } else {
384 ret = himedia_legacy_resume(dev);
385 }
386
387 return ret;
388 }
389
himedia_pm_restore_noirq(struct device * dev)390 static int himedia_pm_restore_noirq(struct device *dev)
391 {
392 int ret = 0;
393 struct device_driver *drv = dev->driver;
394
395 if (drv == HI_NULL) {
396 return 0;
397 }
398
399 if (drv->pm) {
400 if (drv->pm->restore_noirq) {
401 ret = drv->pm->restore_noirq(dev);
402 }
403 } else {
404 ret = himedia_legacy_resume_early(dev);
405 }
406
407 return ret;
408 }
409
410 #else /* !CONFIG_HIBERNATION */
411
412 #define himedia_pm_freeze NULL
413 #define himedia_pm_thaw NULL
414 #define himedia_pm_poweroff NULL
415 #define himedia_pm_restore NULL
416 #define himedia_pm_freeze_noirq NULL
417 #define himedia_pm_thaw_noirq NULL
418 #define himedia_pm_poweroff_noirq NULL
419 #define himedia_pm_restore_noirq NULL
420
421 #endif /* !CONFIG_HIBERNATION */
422
423 static struct dev_pm_ops g_himedia_dev_pm_ops = {
424 .prepare = himedia_pm_prepare,
425 .complete = himedia_pm_complete,
426 .suspend = himedia_pm_suspend,
427 .resume = himedia_pm_resume,
428 .freeze = himedia_pm_freeze,
429 .thaw = himedia_pm_thaw,
430 .poweroff = himedia_pm_poweroff,
431 .restore = himedia_pm_restore,
432 .suspend_noirq = himedia_pm_suspend_noirq,
433 .resume_noirq = himedia_pm_resume_noirq,
434 .freeze_noirq = himedia_pm_freeze_noirq,
435 .thaw_noirq = himedia_pm_thaw_noirq,
436 .poweroff_noirq = himedia_pm_poweroff_noirq,
437 .restore_noirq = himedia_pm_restore_noirq,
438 };
439
440 #define HIMEDIA_PM_OPS_PTR (&g_himedia_dev_pm_ops)
441
442 #else /* !CONFIG_PM_SLEEP */
443
444 #define HIMEDIA_PM_OPS_PTR NULL
445
446 #endif /* !CONFIG_PM_SLEEP */
447
448 struct bus_type g_himedia_bus_type = {
449 .name = "himedia_bus",
450 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0))
451 .dev_groups = g_himedia_dev_groups,
452 #else
453 .dev_attrs = g_himedia_dev_attrs,
454 #endif
455 .match = himedia_match,
456 .uevent = himedia_uevent,
457 .pm = HIMEDIA_PM_OPS_PTR,
458 };
459
himedia_bus_init(void)460 int himedia_bus_init(void)
461 {
462 int ret;
463 ret = device_register(&g_himedia_bus);
464 if (ret) {
465 return ret;
466 }
467 ret = bus_register(&g_himedia_bus_type);
468 if (ret) {
469 device_unregister(&g_himedia_bus);
470 }
471 return ret;
472 }
473
himedia_bus_exit(void)474 void himedia_bus_exit(void)
475 {
476 bus_unregister(&g_himedia_bus_type);
477 device_unregister(&g_himedia_bus);
478 return;
479 }
480
481 /* himedia base device */
himedia_device_add(pm_basedev * pdev)482 int himedia_device_add(pm_basedev *pdev)
483 {
484 // 0
485 if (pdev == NULL) {
486 return -EINVAL;
487 }
488 // 1
489 if (!pdev->dev.parent) {
490 pdev->dev.parent = &g_himedia_bus;
491 }
492 pdev->dev.bus = &g_himedia_bus_type;
493
494 if (pdev->id != -1) {
495 dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
496 } else {
497 dev_set_name(&pdev->dev, pdev->name);
498 }
499
500 return device_add(&pdev->dev);
501 }
502
himedia_device_del(pm_basedev * pdev)503 void himedia_device_del(pm_basedev *pdev)
504 {
505 if (pdev != NULL) {
506 device_del(&pdev->dev);
507 }
508 return;
509 }
510
himedia_device_put(pm_basedev * pdev)511 void himedia_device_put(pm_basedev *pdev)
512 {
513 if (pdev != NULL) {
514 put_device(&pdev->dev);
515 }
516 }
517
518 struct himedia_devobj {
519 pm_basedev pdev;
520 char name[1];
521 };
522
himedia_device_release(struct device * dev)523 static void himedia_device_release(struct device *dev)
524 {
525 struct himedia_devobj *pa = container_of(dev, struct himedia_devobj,
526 pdev.dev);
527 kfree(pa);
528 return;
529 }
530
himedia_device_alloc(const char * name,int id)531 pm_basedev *himedia_device_alloc(const char *name, int id)
532 {
533 int size, ret;
534 struct himedia_devobj *pa;
535 size = strlen(name) + 5; /* 5 表示保存name后面的字符串的长度 */
536 pa = kmalloc(sizeof(struct himedia_devobj) + size, GFP_KERNEL | __GFP_ZERO);
537 if (pa != NULL) {
538 ret = snprintf_s(pa->name, sizeof(struct himedia_devobj) + size - sizeof(pa->pdev),
539 size, "%s-base", name);
540 if (ret != size) {
541 printk("call snprintf_s func error.\n");
542 }
543 pa->pdev.name = pa->name;
544 pa->pdev.id = id;
545 device_initialize(&pa->pdev.dev);
546 pa->pdev.dev.release = himedia_device_release;
547 }
548 return pa ? &pa->pdev : NULL;
549 }
550
himedia_device_register(pm_basedev * pdev)551 int himedia_device_register(pm_basedev *pdev)
552 {
553 device_initialize(&pdev->dev);
554 return himedia_device_add(pdev);
555 }
556
himedia_device_unregister(pm_basedev * pdev)557 void himedia_device_unregister(pm_basedev *pdev)
558 {
559 himedia_device_del(pdev);
560 himedia_device_put(pdev);
561 return;
562 }
563
564 /* himedia base driver */
himedia_drv_probe(struct device * dev)565 static int himedia_drv_probe(struct device *dev)
566 {
567 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
568 pm_basedev *pdev = TO_PM_BASEDEV(dev);
569
570 return pdrv->probe(pdev);
571 }
572
himedia_drv_remove(struct device * dev)573 static int himedia_drv_remove(struct device *dev)
574 {
575 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
576 pm_basedev *pdev = TO_PM_BASEDEV(dev);
577
578 return pdrv->remove(pdev);
579 }
580
himedia_drv_shutdown(struct device * dev)581 static void himedia_drv_shutdown(struct device *dev)
582 {
583 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
584 pm_basedev *pdev = TO_PM_BASEDEV(dev);
585
586 pdrv->shutdown(pdev);
587 return;
588 }
589
himedia_drv_suspend(struct device * dev,pm_message_t state)590 static int himedia_drv_suspend(struct device *dev, pm_message_t state)
591 {
592 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
593 pm_basedev *pdev = TO_PM_BASEDEV(dev);
594
595 return pdrv->suspend(pdev, state);
596 }
597
himedia_drv_resume(struct device * dev)598 static int himedia_drv_resume(struct device *dev)
599 {
600 pm_basedrv *pdrv = to_himedia_basedrv(dev->driver);
601 pm_basedev *pdev = TO_PM_BASEDEV(dev);
602
603 return pdrv->resume(pdev);
604 }
605
himedia_driver_register(pm_basedrv * drv)606 int himedia_driver_register(pm_basedrv *drv)
607 {
608 drv->driver.bus = &g_himedia_bus_type;
609 if (drv->probe) {
610 drv->driver.probe = himedia_drv_probe;
611 }
612 if (drv->remove) {
613 drv->driver.remove = himedia_drv_remove;
614 }
615 if (drv->shutdown) {
616 drv->driver.shutdown = himedia_drv_shutdown;
617 }
618 if (drv->suspend) {
619 drv->driver.suspend = himedia_drv_suspend;
620 }
621 if (drv->resume) {
622 drv->driver.resume = himedia_drv_resume;
623 }
624 return driver_register(&drv->driver);
625 }
626
himedia_driver_unregister(pm_basedrv * drv)627 void himedia_driver_unregister(pm_basedrv *drv)
628 {
629 driver_unregister(&drv->driver);
630 }
631
632 struct himedia_drvobj {
633 pm_basedrv pdrv;
634 char name[1];
635 };
636
himedia_driver_alloc(const char * name,struct module * owner,pm_baseops * ops)637 pm_basedrv *himedia_driver_alloc(const char *name, struct module *owner,
638 pm_baseops *ops)
639 {
640 int size, ret;
641 struct himedia_drvobj *pa;
642 size = strlen(name) + 5; /* 5 表示保存name后面的字符串的长度 */
643 pa = kmalloc(sizeof(struct himedia_drvobj) + size, GFP_KERNEL | __GFP_ZERO);
644 if (pa != NULL) {
645 // 0
646 ret = snprintf_s(pa->name, sizeof(struct himedia_devobj) + size - sizeof(pa->pdrv),
647 size, "%s-base", name);
648 if (ret != size) {
649 printk("call snprintf_s func error.\n");
650 }
651
652 pa->pdrv.driver.name = pa->name;
653 pa->pdrv.driver.owner = owner;
654 // 1
655 if (ops != NULL && ops->probe != NULL) {
656 pa->pdrv.probe = ops->probe;
657 } else {
658 pa->pdrv.probe = NULL;
659 }
660
661 if (ops != NULL && ops->remove != NULL) {
662 pa->pdrv.remove = ops->remove;
663 } else {
664 pa->pdrv.remove = NULL;
665 }
666
667 if (ops != NULL && ops->shutdown != NULL) {
668 pa->pdrv.shutdown = ops->shutdown;
669 } else {
670 pa->pdrv.shutdown = NULL;
671 }
672
673 if (ops != NULL && ops->suspend != NULL) {
674 pa->pdrv.suspend = ops->suspend;
675 } else {
676 pa->pdrv.suspend = NULL;
677 }
678
679 if (ops != NULL && ops->resume != NULL) {
680 pa->pdrv.resume = ops->resume;
681 } else {
682 pa->pdrv.resume = NULL;
683 }
684
685 if (ops != NULL && ops->suspend_late != NULL) {
686 pa->pdrv.suspend_late = ops->suspend_late;
687 } else {
688 pa->pdrv.suspend_late = NULL;
689 }
690
691 if (ops != NULL && ops->resume_early != NULL) {
692 pa->pdrv.resume_early = ops->resume_early;
693 } else {
694 pa->pdrv.resume_early = NULL;
695 }
696 }
697 return pa ? &pa->pdrv : NULL;
698 }
699
himedia_driver_release(pm_basedrv * drv)700 void himedia_driver_release(pm_basedrv *drv)
701 {
702 struct himedia_drvobj *pa = container_of(drv, struct himedia_drvobj, pdrv);
703 kfree(pa);
704 return;
705 }
706