• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/err.h>
23 #include <linux/slab.h>
24 #include <linux/device.h>
25 #include <linux/fs.h>
26 #include <linux/errno.h>
27 #include <linux/kernel.h>
28 #include <linux/major.h>
29 #include <linux/stat.h>
30 #include <linux/init.h>
31 #include <linux/kmod.h>
32 #include "securec.h"
33 #include "base.h"
34 
himedia_bus_release(struct device * dev)35 static void himedia_bus_release(struct device *dev)
36 {
37     osal_unused(dev);
38     return;
39 }
40 
41 struct device g_himedia_bus = {
42     .init_name = "himedia",
43     .release = himedia_bus_release
44 };
45 
46 
47 /* bus match & uevent */
himedia_match(struct device * dev,struct device_driver * drv)48 static int himedia_match(struct device *dev, struct device_driver *drv)
49 {
50     struct himedia_device *pdev = to_himedia_device(dev);
51     return (strncmp(pdev->devfs_name, drv->name, sizeof(pdev->devfs_name)) == 0);
52 }
53 
himedia_uevent(struct device * dev,struct kobj_uevent_env * env)54 static int himedia_uevent(struct device *dev, struct kobj_uevent_env *env)
55 {
56     struct himedia_device *pdev = to_himedia_device(dev);
57     add_uevent_var(env, "MODALIAS=himedia:%s", pdev->devfs_name);
58     return 0;
59 }
60 
61 /* pm methods */
himedia_pm_prepare(struct device * dev)62 static int himedia_pm_prepare(struct device *dev)
63 {
64     struct himedia_device *pdev = to_himedia_device(dev);
65     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
66 
67     if ((pdrv->ops == NULL) || (pdrv->ops->pm_prepare == NULL)) {
68         return 0;
69     }
70 
71     return pdrv->ops->pm_prepare(pdev);
72 }
73 
himedia_pm_complete(struct device * dev)74 static void himedia_pm_complete(struct device *dev)
75 {
76     struct himedia_device *pdev = to_himedia_device(dev);
77     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
78 
79     if ((pdrv->ops == NULL) || (pdrv->ops->pm_complete == NULL)) {
80         return;
81     }
82 
83     pdrv->ops->pm_complete(pdev);
84 }
85 
himedia_pm_suspend(struct device * dev)86 static int himedia_pm_suspend(struct device *dev)
87 {
88     struct himedia_device *pdev = to_himedia_device(dev);
89     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
90 
91     if ((pdrv->ops == NULL) || (pdrv->ops->pm_suspend == NULL)) {
92         return 0;
93     }
94 
95     return pdrv->ops->pm_suspend(pdev);
96 }
97 
himedia_pm_resume(struct device * dev)98 static int himedia_pm_resume(struct device *dev)
99 {
100     struct himedia_device *pdev = to_himedia_device(dev);
101     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
102 
103     if ((pdrv->ops == NULL) || (pdrv->ops->pm_resume == NULL)) {
104         return 0;
105     }
106 
107     return pdrv->ops->pm_resume(pdev);
108 }
109 
himedia_pm_freeze(struct device * dev)110 static int himedia_pm_freeze(struct device *dev)
111 {
112     struct himedia_device *pdev = to_himedia_device(dev);
113     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
114 
115     if ((pdrv->ops == NULL) || (pdrv->ops->pm_freeze == NULL)) {
116         return 0;
117     }
118 
119     return pdrv->ops->pm_freeze(pdev);
120 }
121 
himedia_pm_thaw(struct device * dev)122 static int himedia_pm_thaw(struct device *dev)
123 {
124     struct himedia_device *pdev = to_himedia_device(dev);
125     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
126 
127     if ((pdrv->ops == NULL) || (pdrv->ops->pm_thaw == NULL)) {
128         return 0;
129     }
130 
131     return pdrv->ops->pm_thaw(pdev);
132 }
133 
himedia_pm_poweroff(struct device * dev)134 static int himedia_pm_poweroff(struct device *dev)
135 {
136     struct himedia_device *pdev = to_himedia_device(dev);
137     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
138 
139     if ((pdrv->ops == NULL) || (pdrv->ops->pm_poweroff == NULL)) {
140         return 0;
141     }
142 
143     return pdrv->ops->pm_poweroff(pdev);
144 }
145 
himedia_pm_restore(struct device * dev)146 static int himedia_pm_restore(struct device *dev)
147 {
148     struct himedia_device *pdev = to_himedia_device(dev);
149     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
150 
151     if ((pdrv->ops == NULL) || (pdrv->ops->pm_restore == NULL)) {
152         return 0;
153     }
154 
155     return pdrv->ops->pm_restore(pdev);
156 }
himedia_pm_suspend_noirq(struct device * dev)157 static int himedia_pm_suspend_noirq(struct device *dev)
158 {
159     struct himedia_device *pdev = to_himedia_device(dev);
160     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
161 
162     if ((pdrv->ops == NULL) || (pdrv->ops->pm_suspend_noirq == NULL)) {
163         return 0;
164     }
165 
166     return pdrv->ops->pm_suspend_noirq(pdev);
167 }
168 
himedia_pm_resume_noirq(struct device * dev)169 static int himedia_pm_resume_noirq(struct device *dev)
170 {
171     struct himedia_device *pdev = to_himedia_device(dev);
172     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
173 
174     if ((pdrv->ops == NULL) || (pdrv->ops->pm_resume_noirq == NULL)) {
175         return 0;
176     }
177 
178     return pdrv->ops->pm_resume_noirq(pdev);
179 }
180 
himedia_pm_freeze_noirq(struct device * dev)181 static int himedia_pm_freeze_noirq(struct device *dev)
182 {
183     struct himedia_device *pdev = to_himedia_device(dev);
184     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
185 
186     if ((pdrv->ops == NULL) || (pdrv->ops->pm_freeze_noirq == NULL)) {
187         return 0;
188     }
189 
190     return pdrv->ops->pm_freeze_noirq(pdev);
191 }
192 
himedia_pm_thaw_noirq(struct device * dev)193 static int himedia_pm_thaw_noirq(struct device *dev)
194 {
195     struct himedia_device *pdev = to_himedia_device(dev);
196     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
197 
198     if ((pdrv->ops == NULL) || (pdrv->ops->pm_thaw_noirq == NULL)) {
199         return 0;
200     }
201 
202     return pdrv->ops->pm_thaw_noirq(pdev);
203 }
204 
himedia_pm_poweroff_noirq(struct device * dev)205 static int himedia_pm_poweroff_noirq(struct device *dev)
206 {
207     struct himedia_device *pdev = to_himedia_device(dev);
208     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
209 
210     if ((pdrv->ops == NULL) || (pdrv->ops->pm_poweroff_noirq == NULL)) {
211         return 0;
212     }
213 
214     return pdrv->ops->pm_poweroff_noirq(pdev);
215 }
216 
himedia_pm_restore_noirq(struct device * dev)217 static int himedia_pm_restore_noirq(struct device *dev)
218 {
219     struct himedia_device *pdev = to_himedia_device(dev);
220     struct himedia_driver *pdrv = to_himedia_driver(dev->driver);
221 
222     if ((pdrv->ops == NULL) || (pdrv->ops->pm_restore_noirq == NULL)) {
223         return 0;
224     }
225 
226     return pdrv->ops->pm_restore_noirq(pdev);
227 }
228 
229 static struct dev_pm_ops g_himedia_bus_pm_ops = {
230     .prepare = himedia_pm_prepare,
231     .complete = himedia_pm_complete,
232 
233     /* with irq */
234     .suspend = himedia_pm_suspend,
235     .resume = himedia_pm_resume,
236 
237     .freeze = himedia_pm_freeze,
238     .thaw = himedia_pm_thaw,
239     .poweroff = himedia_pm_poweroff,
240     .restore = himedia_pm_restore,
241 
242     /* with noirq */
243     .suspend_noirq = himedia_pm_suspend_noirq,
244     .resume_noirq = himedia_pm_resume_noirq,
245     .freeze_noirq = himedia_pm_freeze_noirq,
246     .thaw_noirq = himedia_pm_thaw_noirq,
247     .poweroff_noirq = himedia_pm_poweroff_noirq,
248     .restore_noirq = himedia_pm_restore_noirq,
249 };
250 
251 struct bus_type g_himedia_bus_type = {
252     .name = "himedia",
253     .match = himedia_match,
254     .uevent = himedia_uevent,
255     .pm = &g_himedia_bus_pm_ops,
256 };
257 
himedia_bus_init(void)258 int himedia_bus_init(void)
259 {
260     int ret;
261     ret = device_register(&g_himedia_bus);
262     if (ret) {
263         return ret;
264     }
265 
266     ret = bus_register(&g_himedia_bus_type);
267     if (ret) {
268         goto error;
269     }
270 
271     return 0;
272 error:
273     device_unregister(&g_himedia_bus);
274     return ret;
275 }
276 
himedia_bus_exit(void)277 void himedia_bus_exit(void)
278 {
279     bus_unregister(&g_himedia_bus_type);
280     device_unregister(&g_himedia_bus);
281 }
282 
himedia_device_release(struct device * dev)283 static void himedia_device_release(struct device *dev)
284 {
285     osal_unused(dev);
286     return;
287 }
288 
himedia_device_register(struct himedia_device * pdev)289 int himedia_device_register(struct himedia_device *pdev)
290 {
291     dev_set_name(&pdev->device, "%s", pdev->devfs_name);
292 
293     pdev->device.devt = MKDEV(HIMEDIA_DEVICE_MAJOR, pdev->minor);
294     pdev->device.release = himedia_device_release;
295     pdev->device.bus = &g_himedia_bus_type;
296 
297     return device_register(&pdev->device);
298 }
299 
himedia_device_unregister(struct himedia_device * pdev)300 void himedia_device_unregister(struct himedia_device *pdev)
301 {
302     device_unregister(&pdev->device);
303 }
304 
himedia_driver_register(const char * name,struct module * owner,struct himedia_ops * ops)305 struct himedia_driver *himedia_driver_register(const char *name,
306                                                struct module *owner, struct himedia_ops *ops)
307 {
308     int ret;
309     struct himedia_driver *pdrv = NULL;
310 
311     if ((name == NULL) || (owner == NULL)) {
312         return ERR_PTR(-EINVAL);
313     }
314 
315     pdrv = kzalloc(sizeof(struct himedia_driver) + strnlen(name, HIMIDIA_MAX_DEV_NAME_LEN), GFP_KERNEL);
316     if (pdrv == NULL) {
317         return ERR_PTR(-ENOMEM);
318     }
319 
320     /* init driver object */
321     if (strncpy_s(pdrv->name, HIMIDIA_MAX_DEV_NAME_LEN, name, strnlen(name, HIMIDIA_MAX_DEV_NAME_LEN - 1)) != EOK) {
322         kfree(pdrv);
323         pdrv = NULL;
324         return ERR_PTR(-EINVAL);
325     }
326     pdrv->name[HIMIDIA_MAX_DEV_NAME_LEN - 1] = '\0';
327 
328     pdrv->ops = ops;
329 
330     pdrv->driver.name = pdrv->name;
331     pdrv->driver.owner = owner;
332     pdrv->driver.bus = &g_himedia_bus_type;
333 
334     ret = driver_register(&pdrv->driver);
335     if (ret) {
336         kfree(pdrv);
337         pdrv = NULL;
338         return ERR_PTR(ret);
339     }
340 
341     return pdrv;
342 }
343 
himedia_driver_unregister(struct himedia_driver * pdrv)344 void himedia_driver_unregister(struct himedia_driver *pdrv)
345 {
346     if (pdrv != NULL) {
347         driver_unregister(&pdrv->driver);
348         kfree(pdrv);
349         pdrv = NULL;
350     }
351 }
352