Commit | Line | Data |
---|---|---|
7d55524d ORL |
1 | /* |
2 | * drv_interface.c | |
3 | * | |
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | |
5 | * | |
6 | * DSP/BIOS Bridge driver interface. | |
7 | * | |
8 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | |
9 | * | |
10 | * This package is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License version 2 as | |
12 | * published by the Free Software Foundation. | |
13 | * | |
14 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
15 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
16 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
17 | */ | |
18 | ||
2203747c | 19 | #include <linux/platform_data/dsp-omap.h> |
82d4b477 | 20 | |
2094f12d | 21 | #include <linux/types.h> |
7d55524d ORL |
22 | #include <linux/platform_device.h> |
23 | #include <linux/pm.h> | |
7d55524d | 24 | #include <linux/module.h> |
7d55524d ORL |
25 | #include <linux/device.h> |
26 | #include <linux/init.h> | |
27 | #include <linux/moduleparam.h> | |
28 | #include <linux/cdev.h> | |
29 | ||
30 | /* ----------------------------------- DSP/BIOS Bridge */ | |
7d55524d ORL |
31 | #include <dspbridge/dbdefs.h> |
32 | ||
7d55524d | 33 | /* ----------------------------------- OS Adaptation Layer */ |
7d55524d | 34 | #include <dspbridge/clk.h> |
7d55524d ORL |
35 | |
36 | /* ----------------------------------- Platform Manager */ | |
7d55524d ORL |
37 | #include <dspbridge/dspapi.h> |
38 | #include <dspbridge/dspdrv.h> | |
39 | ||
40 | /* ----------------------------------- Resource Manager */ | |
41 | #include <dspbridge/pwr.h> | |
42 | ||
7d55524d | 43 | #include <dspbridge/resourcecleanup.h> |
7d55524d ORL |
44 | #include <dspbridge/proc.h> |
45 | #include <dspbridge/dev.h> | |
7d55524d | 46 | |
b3d23688 | 47 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
48 | #include <mach-omap2/omap3-opp.h> |
49 | #endif | |
50 | ||
7d55524d | 51 | /* ----------------------------------- Globals */ |
7d55524d ORL |
52 | #define DSPBRIDGE_VERSION "0.3" |
53 | s32 dsp_debug; | |
54 | ||
55 | struct platform_device *omap_dspbridge_dev; | |
56 | struct device *bridge; | |
57 | ||
58 | /* This is a test variable used by Bridge to test different sleep states */ | |
59 | s32 dsp_test_sleepstate; | |
60 | ||
61 | static struct cdev bridge_cdev; | |
62 | ||
63 | static struct class *bridge_class; | |
64 | ||
65 | static u32 driver_context; | |
66 | static s32 driver_major; | |
67 | static char *base_img; | |
68 | char *iva_img; | |
69 | static s32 shm_size = 0x500000; /* 5 MB */ | |
70 | static int tc_wordswapon; /* Default value is always false */ | |
b3d23688 | 71 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
72 | #define REC_TIMEOUT 5000 /*recovery timeout in msecs */ |
73 | static atomic_t bridge_cref; /* number of bridge open handles */ | |
74 | static struct workqueue_struct *bridge_rec_queue; | |
75 | static struct work_struct bridge_recovery_work; | |
76 | static DECLARE_COMPLETION(bridge_comp); | |
77 | static DECLARE_COMPLETION(bridge_open_comp); | |
78 | static bool recover; | |
79 | #endif | |
80 | ||
81 | #ifdef CONFIG_PM | |
82 | struct omap34_xx_bridge_suspend_data { | |
83 | int suspended; | |
84 | wait_queue_head_t suspend_wq; | |
85 | }; | |
86 | ||
87 | static struct omap34_xx_bridge_suspend_data bridge_suspend_data; | |
88 | ||
89 | static int omap34_xxbridge_suspend_lockout(struct omap34_xx_bridge_suspend_data | |
90 | *s, struct file *f) | |
91 | { | |
92 | if ((s)->suspended) { | |
93 | if ((f)->f_flags & O_NONBLOCK) | |
94 | return -EPERM; | |
95 | wait_event_interruptible((s)->suspend_wq, (s)->suspended == 0); | |
96 | } | |
97 | return 0; | |
98 | } | |
99 | #endif | |
100 | ||
101 | module_param(dsp_debug, int, 0); | |
102 | MODULE_PARM_DESC(dsp_debug, "Wait after loading DSP image. default = false"); | |
103 | ||
104 | module_param(dsp_test_sleepstate, int, 0); | |
105 | MODULE_PARM_DESC(dsp_test_sleepstate, "DSP Sleep state = 0"); | |
106 | ||
107 | module_param(base_img, charp, 0); | |
108 | MODULE_PARM_DESC(base_img, "DSP base image, default = NULL"); | |
109 | ||
110 | module_param(shm_size, int, 0); | |
111 | MODULE_PARM_DESC(shm_size, "shm size, default = 4 MB, minimum = 64 KB"); | |
112 | ||
113 | module_param(tc_wordswapon, int, 0); | |
114 | MODULE_PARM_DESC(tc_wordswapon, "TC Word Swap Option. default = 0"); | |
115 | ||
116 | MODULE_AUTHOR("Texas Instruments"); | |
117 | MODULE_LICENSE("GPL"); | |
118 | MODULE_VERSION(DSPBRIDGE_VERSION); | |
119 | ||
518761db VMJL |
120 | /* |
121 | * This function is called when an application opens handle to the | |
122 | * bridge driver. | |
123 | */ | |
124 | static int bridge_open(struct inode *ip, struct file *filp) | |
125 | { | |
126 | int status = 0; | |
127 | struct process_context *pr_ctxt = NULL; | |
128 | ||
129 | /* | |
130 | * Allocate a new process context and insert it into global | |
131 | * process context list. | |
132 | */ | |
133 | ||
134 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY | |
135 | if (recover) { | |
136 | if (filp->f_flags & O_NONBLOCK || | |
7724e8bf | 137 | wait_for_completion_interruptible(&bridge_open_comp)) |
518761db VMJL |
138 | return -EBUSY; |
139 | } | |
140 | #endif | |
141 | pr_ctxt = kzalloc(sizeof(struct process_context), GFP_KERNEL); | |
25738978 ORL |
142 | if (!pr_ctxt) |
143 | return -ENOMEM; | |
144 | ||
145 | pr_ctxt->res_state = PROC_RES_ALLOCATED; | |
146 | spin_lock_init(&pr_ctxt->dmm_map_lock); | |
147 | INIT_LIST_HEAD(&pr_ctxt->dmm_map_list); | |
148 | spin_lock_init(&pr_ctxt->dmm_rsv_lock); | |
149 | INIT_LIST_HEAD(&pr_ctxt->dmm_rsv_list); | |
150 | ||
151 | pr_ctxt->node_id = kzalloc(sizeof(struct idr), GFP_KERNEL); | |
152 | if (!pr_ctxt->node_id) { | |
518761db | 153 | status = -ENOMEM; |
25738978 | 154 | goto err1; |
518761db | 155 | } |
25738978 ORL |
156 | |
157 | idr_init(pr_ctxt->node_id); | |
158 | ||
159 | pr_ctxt->stream_id = kzalloc(sizeof(struct idr), GFP_KERNEL); | |
160 | if (!pr_ctxt->stream_id) { | |
161 | status = -ENOMEM; | |
162 | goto err2; | |
163 | } | |
164 | ||
165 | idr_init(pr_ctxt->stream_id); | |
166 | ||
518761db | 167 | filp->private_data = pr_ctxt; |
25738978 | 168 | |
518761db | 169 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
25738978 | 170 | atomic_inc(&bridge_cref); |
518761db | 171 | #endif |
25738978 ORL |
172 | return 0; |
173 | ||
174 | err2: | |
175 | kfree(pr_ctxt->node_id); | |
176 | err1: | |
177 | kfree(pr_ctxt); | |
518761db VMJL |
178 | return status; |
179 | } | |
180 | ||
181 | /* | |
182 | * This function is called when an application closes handle to the bridge | |
183 | * driver. | |
184 | */ | |
185 | static int bridge_release(struct inode *ip, struct file *filp) | |
186 | { | |
187 | int status = 0; | |
188 | struct process_context *pr_ctxt; | |
189 | ||
190 | if (!filp->private_data) { | |
191 | status = -EIO; | |
192 | goto err; | |
193 | } | |
194 | ||
195 | pr_ctxt = filp->private_data; | |
196 | flush_signals(current); | |
197 | drv_remove_all_resources(pr_ctxt); | |
198 | proc_detach(pr_ctxt); | |
25738978 ORL |
199 | kfree(pr_ctxt->node_id); |
200 | kfree(pr_ctxt->stream_id); | |
518761db VMJL |
201 | kfree(pr_ctxt); |
202 | ||
203 | filp->private_data = NULL; | |
204 | ||
205 | err: | |
206 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY | |
207 | if (!atomic_dec_return(&bridge_cref)) | |
208 | complete(&bridge_comp); | |
209 | #endif | |
210 | return status; | |
211 | } | |
212 | ||
213 | /* This function provides IO interface to the bridge driver. */ | |
214 | static long bridge_ioctl(struct file *filp, unsigned int code, | |
215 | unsigned long args) | |
216 | { | |
217 | int status; | |
218 | u32 retval = 0; | |
219 | union trapped_args buf_in; | |
220 | ||
518761db VMJL |
221 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
222 | if (recover) { | |
223 | status = -EIO; | |
224 | goto err; | |
225 | } | |
226 | #endif | |
227 | #ifdef CONFIG_PM | |
228 | status = omap34_xxbridge_suspend_lockout(&bridge_suspend_data, filp); | |
229 | if (status != 0) | |
230 | return status; | |
231 | #endif | |
232 | ||
233 | if (!filp->private_data) { | |
234 | status = -EIO; | |
235 | goto err; | |
236 | } | |
237 | ||
238 | status = copy_from_user(&buf_in, (union trapped_args *)args, | |
239 | sizeof(union trapped_args)); | |
240 | ||
241 | if (!status) { | |
242 | status = api_call_dev_ioctl(code, &buf_in, &retval, | |
7724e8bf | 243 | filp->private_data); |
518761db VMJL |
244 | |
245 | if (!status) { | |
246 | status = retval; | |
247 | } else { | |
248 | dev_dbg(bridge, "%s: IOCTL Failed, code: 0x%x " | |
249 | "status 0x%x\n", __func__, code, status); | |
250 | status = -1; | |
251 | } | |
252 | ||
253 | } | |
254 | ||
255 | err: | |
256 | return status; | |
257 | } | |
258 | ||
259 | /* This function maps kernel space memory to user space memory. */ | |
260 | static int bridge_mmap(struct file *filp, struct vm_area_struct *vma) | |
261 | { | |
518761db VMJL |
262 | u32 status; |
263 | ||
314e51b9 | 264 | /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ |
518761db VMJL |
265 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
266 | ||
4f8aae53 VMJL |
267 | dev_dbg(bridge, "%s: vm filp %p start %lx end %lx page_prot %ulx " |
268 | "flags %lx\n", __func__, filp, | |
9fdf6550 VMJL |
269 | vma->vm_start, vma->vm_end, vma->vm_page_prot, |
270 | vma->vm_flags); | |
518761db VMJL |
271 | |
272 | status = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, | |
273 | vma->vm_end - vma->vm_start, | |
274 | vma->vm_page_prot); | |
275 | if (status != 0) | |
276 | status = -EAGAIN; | |
277 | ||
278 | return status; | |
279 | } | |
7d55524d ORL |
280 | |
281 | static const struct file_operations bridge_fops = { | |
282 | .open = bridge_open, | |
283 | .release = bridge_release, | |
284 | .unlocked_ioctl = bridge_ioctl, | |
285 | .mmap = bridge_mmap, | |
6038f373 | 286 | .llseek = noop_llseek, |
7d55524d ORL |
287 | }; |
288 | ||
289 | #ifdef CONFIG_PM | |
290 | static u32 time_out = 1000; | |
b3d23688 | 291 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
292 | s32 dsp_max_opps = VDD1_OPP5; |
293 | #endif | |
294 | ||
295 | /* Maximum Opps that can be requested by IVA */ | |
296 | /*vdd1 rate table */ | |
b3d23688 | 297 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
298 | const struct omap_opp vdd1_rate_table_bridge[] = { |
299 | {0, 0, 0}, | |
300 | /*OPP1 */ | |
301 | {S125M, VDD1_OPP1, 0}, | |
302 | /*OPP2 */ | |
303 | {S250M, VDD1_OPP2, 0}, | |
304 | /*OPP3 */ | |
305 | {S500M, VDD1_OPP3, 0}, | |
306 | /*OPP4 */ | |
307 | {S550M, VDD1_OPP4, 0}, | |
308 | /*OPP5 */ | |
309 | {S600M, VDD1_OPP5, 0}, | |
310 | }; | |
311 | #endif | |
312 | #endif | |
313 | ||
82d4b477 | 314 | struct omap_dsp_platform_data *omap_dspbridge_pdata; |
7d55524d ORL |
315 | |
316 | u32 vdd1_dsp_freq[6][4] = { | |
317 | {0, 0, 0, 0}, | |
318 | /*OPP1 */ | |
319 | {0, 90000, 0, 86000}, | |
320 | /*OPP2 */ | |
321 | {0, 180000, 80000, 170000}, | |
322 | /*OPP3 */ | |
323 | {0, 360000, 160000, 340000}, | |
324 | /*OPP4 */ | |
325 | {0, 396000, 325000, 376000}, | |
326 | /*OPP5 */ | |
327 | {0, 430000, 355000, 430000}, | |
328 | }; | |
329 | ||
b3d23688 | 330 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
331 | static void bridge_recover(struct work_struct *work) |
332 | { | |
333 | struct dev_object *dev; | |
334 | struct cfg_devnode *dev_node; | |
335 | if (atomic_read(&bridge_cref)) { | |
336 | INIT_COMPLETION(bridge_comp); | |
337 | while (!wait_for_completion_timeout(&bridge_comp, | |
338 | msecs_to_jiffies(REC_TIMEOUT))) | |
339 | pr_info("%s:%d handle(s) still opened\n", | |
340 | __func__, atomic_read(&bridge_cref)); | |
341 | } | |
342 | dev = dev_get_first(); | |
343 | dev_get_dev_node(dev, &dev_node); | |
b66e0986 | 344 | if (!dev_node || proc_auto_start(dev_node, dev)) |
7d55524d ORL |
345 | pr_err("DSP could not be restarted\n"); |
346 | recover = false; | |
347 | complete_all(&bridge_open_comp); | |
348 | } | |
349 | ||
350 | void bridge_recover_schedule(void) | |
351 | { | |
352 | INIT_COMPLETION(bridge_open_comp); | |
353 | recover = true; | |
354 | queue_work(bridge_rec_queue, &bridge_recovery_work); | |
355 | } | |
356 | #endif | |
b3d23688 | 357 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d | 358 | static int dspbridge_scale_notification(struct notifier_block *op, |
7724e8bf | 359 | unsigned long val, void *ptr) |
7d55524d | 360 | { |
82d4b477 | 361 | struct omap_dsp_platform_data *pdata = |
7724e8bf | 362 | omap_dspbridge_dev->dev.platform_data; |
7d55524d ORL |
363 | |
364 | if (CPUFREQ_POSTCHANGE == val && pdata->dsp_get_opp) | |
365 | pwr_pm_post_scale(PRCM_VDD1, pdata->dsp_get_opp()); | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | static struct notifier_block iva_clk_notifier = { | |
371 | .notifier_call = dspbridge_scale_notification, | |
372 | NULL, | |
373 | }; | |
374 | #endif | |
375 | ||
376 | /** | |
377 | * omap3_bridge_startup() - perform low lever initializations | |
378 | * @pdev: pointer to platform device | |
379 | * | |
380 | * Initializes recovery, PM and DVFS required data, before calling | |
381 | * clk and memory init routines. | |
382 | */ | |
383 | static int omap3_bridge_startup(struct platform_device *pdev) | |
384 | { | |
82d4b477 | 385 | struct omap_dsp_platform_data *pdata = pdev->dev.platform_data; |
7d55524d ORL |
386 | struct drv_data *drv_datap = NULL; |
387 | u32 phys_membase, phys_memsize; | |
388 | int err; | |
389 | ||
b3d23688 | 390 | #ifdef CONFIG_TIDSPBRIDGE_RECOVERY |
7d55524d ORL |
391 | bridge_rec_queue = create_workqueue("bridge_rec_queue"); |
392 | INIT_WORK(&bridge_recovery_work, bridge_recover); | |
393 | INIT_COMPLETION(bridge_comp); | |
394 | #endif | |
395 | ||
396 | #ifdef CONFIG_PM | |
397 | /* Initialize the wait queue */ | |
398 | bridge_suspend_data.suspended = 0; | |
399 | init_waitqueue_head(&bridge_suspend_data.suspend_wq); | |
400 | ||
b3d23688 | 401 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
402 | for (i = 0; i < 6; i++) |
403 | pdata->mpu_speed[i] = vdd1_rate_table_bridge[i].rate; | |
404 | ||
405 | err = cpufreq_register_notifier(&iva_clk_notifier, | |
406 | CPUFREQ_TRANSITION_NOTIFIER); | |
407 | if (err) | |
408 | pr_err("%s: clk_notifier_register failed for iva2_ck\n", | |
409 | __func__); | |
410 | #endif | |
411 | #endif | |
412 | ||
413 | dsp_clk_init(); | |
7d55524d ORL |
414 | |
415 | drv_datap = kzalloc(sizeof(struct drv_data), GFP_KERNEL); | |
416 | if (!drv_datap) { | |
417 | err = -ENOMEM; | |
418 | goto err1; | |
419 | } | |
420 | ||
421 | drv_datap->shm_size = shm_size; | |
422 | drv_datap->tc_wordswapon = tc_wordswapon; | |
423 | ||
424 | if (base_img) { | |
425 | drv_datap->base_img = kmalloc(strlen(base_img) + 1, GFP_KERNEL); | |
426 | if (!drv_datap->base_img) { | |
427 | err = -ENOMEM; | |
428 | goto err2; | |
429 | } | |
430 | strncpy(drv_datap->base_img, base_img, strlen(base_img) + 1); | |
431 | } | |
432 | ||
433 | dev_set_drvdata(bridge, drv_datap); | |
434 | ||
435 | if (shm_size < 0x10000) { /* 64 KB */ | |
436 | err = -EINVAL; | |
437 | pr_err("%s: shm size must be at least 64 KB\n", __func__); | |
438 | goto err3; | |
439 | } | |
440 | dev_dbg(bridge, "%s: requested shm_size = 0x%x\n", __func__, shm_size); | |
441 | ||
442 | phys_membase = pdata->phys_mempool_base; | |
443 | phys_memsize = pdata->phys_mempool_size; | |
444 | if (phys_membase > 0 && phys_memsize > 0) | |
445 | mem_ext_phys_pool_init(phys_membase, phys_memsize); | |
446 | ||
447 | if (tc_wordswapon) | |
448 | dev_dbg(bridge, "%s: TC Word Swap is enabled\n", __func__); | |
449 | ||
450 | driver_context = dsp_init(&err); | |
451 | if (err) { | |
452 | pr_err("DSP Bridge driver initialization failed\n"); | |
453 | goto err4; | |
454 | } | |
455 | ||
456 | return 0; | |
457 | ||
458 | err4: | |
459 | mem_ext_phys_pool_release(); | |
460 | err3: | |
461 | kfree(drv_datap->base_img); | |
462 | err2: | |
463 | kfree(drv_datap); | |
464 | err1: | |
b3d23688 | 465 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d | 466 | cpufreq_unregister_notifier(&iva_clk_notifier, |
7724e8bf | 467 | CPUFREQ_TRANSITION_NOTIFIER); |
7d55524d ORL |
468 | #endif |
469 | dsp_clk_exit(); | |
7d55524d ORL |
470 | |
471 | return err; | |
472 | } | |
473 | ||
474 | static int __devinit omap34_xx_bridge_probe(struct platform_device *pdev) | |
475 | { | |
476 | int err; | |
477 | dev_t dev = 0; | |
b3d23688 | 478 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d ORL |
479 | int i = 0; |
480 | #endif | |
481 | ||
482 | omap_dspbridge_dev = pdev; | |
483 | ||
484 | /* Global bridge device */ | |
485 | bridge = &omap_dspbridge_dev->dev; | |
486 | ||
487 | /* Bridge low level initializations */ | |
488 | err = omap3_bridge_startup(pdev); | |
489 | if (err) | |
490 | goto err1; | |
491 | ||
492 | /* use 2.6 device model */ | |
3bdb54fc | 493 | err = alloc_chrdev_region(&dev, 0, 1, "DspBridge"); |
7d55524d ORL |
494 | if (err) { |
495 | pr_err("%s: Can't get major %d\n", __func__, driver_major); | |
496 | goto err1; | |
497 | } | |
498 | ||
499 | cdev_init(&bridge_cdev, &bridge_fops); | |
500 | bridge_cdev.owner = THIS_MODULE; | |
501 | ||
502 | err = cdev_add(&bridge_cdev, dev, 1); | |
503 | if (err) { | |
504 | pr_err("%s: Failed to add bridge device\n", __func__); | |
505 | goto err2; | |
506 | } | |
507 | ||
508 | /* udev support */ | |
509 | bridge_class = class_create(THIS_MODULE, "ti_bridge"); | |
510 | if (IS_ERR(bridge_class)) { | |
511 | pr_err("%s: Error creating bridge class\n", __func__); | |
512 | goto err3; | |
513 | } | |
514 | ||
515 | driver_major = MAJOR(dev); | |
516 | device_create(bridge_class, NULL, MKDEV(driver_major, 0), | |
517 | NULL, "DspBridge"); | |
518 | pr_info("DSP Bridge driver loaded\n"); | |
519 | ||
520 | return 0; | |
521 | ||
522 | err3: | |
523 | cdev_del(&bridge_cdev); | |
524 | err2: | |
525 | unregister_chrdev_region(dev, 1); | |
526 | err1: | |
527 | return err; | |
528 | } | |
529 | ||
530 | static int __devexit omap34_xx_bridge_remove(struct platform_device *pdev) | |
531 | { | |
532 | dev_t devno; | |
7d55524d | 533 | int status = 0; |
73b87a91 | 534 | struct drv_data *drv_datap = dev_get_drvdata(bridge); |
7d55524d | 535 | |
73b87a91 IGC |
536 | /* Retrieve the Object handle from the driver data */ |
537 | if (!drv_datap || !drv_datap->drv_object) { | |
538 | status = -ENODATA; | |
539 | pr_err("%s: Failed to retrieve the object handle\n", __func__); | |
7d55524d | 540 | goto func_cont; |
73b87a91 | 541 | } |
7d55524d | 542 | |
b3d23688 | 543 | #ifdef CONFIG_TIDSPBRIDGE_DVFS |
7d55524d | 544 | if (cpufreq_unregister_notifier(&iva_clk_notifier, |
7724e8bf | 545 | CPUFREQ_TRANSITION_NOTIFIER)) |
7d55524d ORL |
546 | pr_err("%s: cpufreq_unregister_notifier failed for iva2_ck\n", |
547 | __func__); | |
b3d23688 | 548 | #endif /* #ifdef CONFIG_TIDSPBRIDGE_DVFS */ |
7d55524d ORL |
549 | |
550 | if (driver_context) { | |
551 | /* Put the DSP in reset state */ | |
b8bfa4c5 | 552 | dsp_deinit(driver_context); |
7d55524d | 553 | driver_context = 0; |
7d55524d ORL |
554 | } |
555 | ||
44c54350 ORL |
556 | kfree(drv_datap); |
557 | dev_set_drvdata(bridge, NULL); | |
558 | ||
7d55524d ORL |
559 | func_cont: |
560 | mem_ext_phys_pool_release(); | |
561 | ||
562 | dsp_clk_exit(); | |
7d55524d ORL |
563 | |
564 | devno = MKDEV(driver_major, 0); | |
565 | cdev_del(&bridge_cdev); | |
566 | unregister_chrdev_region(devno, 1); | |
567 | if (bridge_class) { | |
568 | /* remove the device from sysfs */ | |
569 | device_destroy(bridge_class, MKDEV(driver_major, 0)); | |
570 | class_destroy(bridge_class); | |
571 | ||
572 | } | |
573 | return 0; | |
574 | } | |
575 | ||
576 | #ifdef CONFIG_PM | |
4f1ef761 | 577 | static int bridge_suspend(struct platform_device *pdev, pm_message_t state) |
7d55524d ORL |
578 | { |
579 | u32 status; | |
580 | u32 command = PWR_EMERGENCYDEEPSLEEP; | |
581 | ||
582 | status = pwr_sleep_dsp(command, time_out); | |
b66e0986 | 583 | if (status) |
7d55524d ORL |
584 | return -1; |
585 | ||
586 | bridge_suspend_data.suspended = 1; | |
587 | return 0; | |
588 | } | |
589 | ||
4f1ef761 | 590 | static int bridge_resume(struct platform_device *pdev) |
7d55524d ORL |
591 | { |
592 | u32 status; | |
593 | ||
594 | status = pwr_wake_dsp(time_out); | |
b66e0986 | 595 | if (status) |
7d55524d ORL |
596 | return -1; |
597 | ||
598 | bridge_suspend_data.suspended = 0; | |
599 | wake_up(&bridge_suspend_data.suspend_wq); | |
600 | return 0; | |
601 | } | |
7d55524d ORL |
602 | #endif |
603 | ||
604 | static struct platform_driver bridge_driver = { | |
605 | .driver = { | |
95624b2d | 606 | .name = "omap-dsp", |
7d55524d ORL |
607 | }, |
608 | .probe = omap34_xx_bridge_probe, | |
609 | .remove = __devexit_p(omap34_xx_bridge_remove), | |
4f1ef761 VMJL |
610 | #ifdef CONFIG_PM |
611 | .suspend = bridge_suspend, | |
612 | .resume = bridge_resume, | |
613 | #endif | |
7d55524d ORL |
614 | }; |
615 | ||
7d55524d ORL |
616 | /* To remove all process resources before removing the process from the |
617 | * process context list */ | |
e6890692 | 618 | int drv_remove_all_resources(void *process_ctxt) |
7d55524d ORL |
619 | { |
620 | int status = 0; | |
e6890692 | 621 | struct process_context *ctxt = (struct process_context *)process_ctxt; |
7d55524d ORL |
622 | drv_remove_all_strm_res_elements(ctxt); |
623 | drv_remove_all_node_res_elements(ctxt); | |
624 | drv_remove_all_dmm_res_elements(ctxt); | |
625 | ctxt->res_state = PROC_RES_FREED; | |
626 | return status; | |
627 | } | |
628 | ||
b95dd03d | 629 | module_platform_driver(bridge_driver); |