• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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