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