Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[firefly-linux-kernel-4.4.55.git] / drivers / staging / crystalhd / crystalhd_lnx.c
1 /***************************************************************************
2   BCM70010 Linux driver
3   Copyright (c) 2005-2009, Broadcom Corporation.
4
5   This driver is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, version 2 of the License.
8
9   This driver 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 driver.  If not, see <http://www.gnu.org/licenses/>.
16 ***************************************************************************/
17
18 #include "crystalhd.h"
19
20 #include <linux/mutex.h>
21 #include <linux/slab.h>
22
23
24 static DEFINE_MUTEX(chd_dec_mutex);
25 static struct class *crystalhd_class;
26
27 static struct crystalhd_adp *g_adp_info;
28
29 static irqreturn_t chd_dec_isr(int irq, void *arg)
30 {
31         struct crystalhd_adp *adp = (struct crystalhd_adp *) arg;
32         int rc = 0;
33         if (adp)
34                 rc = crystalhd_cmd_interrupt(&adp->cmds);
35
36         return IRQ_RETVAL(rc);
37 }
38
39 static int chd_dec_enable_int(struct crystalhd_adp *adp)
40 {
41         int rc = 0;
42
43         if (!adp || !adp->pdev) {
44                 BCMLOG_ERR("Invalid arg!!\n");
45                 return -EINVAL;
46         }
47
48         if (adp->pdev->msi_enabled)
49                 adp->msi = 1;
50         else
51                 adp->msi = pci_enable_msi(adp->pdev);
52
53         rc = request_irq(adp->pdev->irq, chd_dec_isr, IRQF_SHARED,
54                          adp->name, (void *)adp);
55         if (rc) {
56                 BCMLOG_ERR("Interrupt request failed..\n");
57                 pci_disable_msi(adp->pdev);
58         }
59
60         return rc;
61 }
62
63 static int chd_dec_disable_int(struct crystalhd_adp *adp)
64 {
65         if (!adp || !adp->pdev) {
66                 BCMLOG_ERR("Invalid arg!!\n");
67                 return -EINVAL;
68         }
69
70         free_irq(adp->pdev->irq, adp);
71
72         if (adp->msi)
73                 pci_disable_msi(adp->pdev);
74
75         return 0;
76 }
77
78 static struct
79 crystalhd_ioctl_data *chd_dec_alloc_iodata(struct crystalhd_adp *adp,
80                                            bool isr)
81 {
82         unsigned long flags = 0;
83         struct crystalhd_ioctl_data *temp;
84
85         if (!adp)
86                 return NULL;
87
88         spin_lock_irqsave(&adp->lock, flags);
89
90         temp = adp->idata_free_head;
91         if (temp) {
92                 adp->idata_free_head = adp->idata_free_head->next;
93                 memset(temp, 0, sizeof(*temp));
94         }
95
96         spin_unlock_irqrestore(&adp->lock, flags);
97         return temp;
98 }
99
100 static void chd_dec_free_iodata(struct crystalhd_adp *adp,
101                                 struct crystalhd_ioctl_data *iodata, bool isr)
102 {
103         unsigned long flags = 0;
104
105         if (!adp || !iodata)
106                 return;
107
108         spin_lock_irqsave(&adp->lock, flags);
109         iodata->next = adp->idata_free_head;
110         adp->idata_free_head = iodata;
111         spin_unlock_irqrestore(&adp->lock, flags);
112 }
113
114 static inline int crystalhd_user_data(void __user *ud, void *dr,
115                          int size, int set)
116 {
117         int rc;
118
119         if (!ud || !dr) {
120                 BCMLOG_ERR("Invalid arg\n");
121                 return -EINVAL;
122         }
123
124         if (set)
125                 rc = copy_to_user(ud, dr, size);
126         else
127                 rc = copy_from_user(dr, ud, size);
128
129         if (rc) {
130                 BCMLOG_ERR("Invalid args for command\n");
131                 rc = -EFAULT;
132         }
133
134         return rc;
135 }
136
137 static int chd_dec_fetch_cdata(struct crystalhd_adp *adp,
138          struct crystalhd_ioctl_data *io, uint32_t m_sz, unsigned long ua)
139 {
140         unsigned long ua_off;
141         int rc = 0;
142
143         if (!adp || !io || !ua || !m_sz) {
144                 BCMLOG_ERR("Invalid Arg!!\n");
145                 return -EINVAL;
146         }
147
148         io->add_cdata = vmalloc(m_sz);
149         if (!io->add_cdata) {
150                 BCMLOG_ERR("kalloc fail for sz:%x\n", m_sz);
151                 return -ENOMEM;
152         }
153
154         io->add_cdata_sz = m_sz;
155         ua_off = ua + sizeof(io->udata);
156         rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata,
157                         io->add_cdata_sz, 0);
158         if (rc) {
159                 BCMLOG_ERR("failed to pull add_cdata sz:%x ua_off:%x\n",
160                            io->add_cdata_sz, (unsigned int)ua_off);
161                 vfree(io->add_cdata);
162                 io->add_cdata = NULL;
163                 return -ENODATA;
164         }
165
166         return rc;
167 }
168
169 static int chd_dec_release_cdata(struct crystalhd_adp *adp,
170                          struct crystalhd_ioctl_data *io, unsigned long ua)
171 {
172         unsigned long ua_off;
173         int rc;
174
175         if (!adp || !io || !ua) {
176                 BCMLOG_ERR("Invalid Arg!!\n");
177                 return -EINVAL;
178         }
179
180         if (io->cmd != BCM_IOC_FW_DOWNLOAD) {
181                 ua_off = ua + sizeof(io->udata);
182                 rc = crystalhd_user_data((void __user *)ua_off, io->add_cdata,
183                                         io->add_cdata_sz, 1);
184                 if (rc) {
185                         BCMLOG_ERR(
186                                 "failed to push add_cdata sz:%x ua_off:%x\n",
187                                  io->add_cdata_sz, (unsigned int)ua_off);
188                         return -ENODATA;
189                 }
190         }
191
192         if (io->add_cdata) {
193                 vfree(io->add_cdata);
194                 io->add_cdata = NULL;
195         }
196
197         return 0;
198 }
199
200 static int chd_dec_proc_user_data(struct crystalhd_adp *adp,
201                                   struct crystalhd_ioctl_data *io,
202                                   unsigned long ua, int set)
203 {
204         int rc;
205         uint32_t m_sz = 0;
206
207         if (!adp || !io || !ua) {
208                 BCMLOG_ERR("Invalid Arg!!\n");
209                 return -EINVAL;
210         }
211
212         rc = crystalhd_user_data((void __user *)ua, &io->udata,
213                         sizeof(io->udata), set);
214         if (rc) {
215                 BCMLOG_ERR("failed to %s iodata\n", (set ? "set" : "get"));
216                 return rc;
217         }
218
219         switch (io->cmd) {
220         case BCM_IOC_MEM_RD:
221         case BCM_IOC_MEM_WR:
222         case BCM_IOC_FW_DOWNLOAD:
223                 m_sz = io->udata.u.devMem.NumDwords * 4;
224                 if (set)
225                         rc = chd_dec_release_cdata(adp, io, ua);
226                 else
227                         rc = chd_dec_fetch_cdata(adp, io, m_sz, ua);
228                 break;
229         default:
230                 break;
231         }
232
233         return rc;
234 }
235
236 static int chd_dec_api_cmd(struct crystalhd_adp *adp, unsigned long ua,
237                            uint32_t uid, uint32_t cmd, crystalhd_cmd_proc func)
238 {
239         int rc;
240         struct crystalhd_ioctl_data *temp;
241         enum BC_STATUS sts = BC_STS_SUCCESS;
242
243         temp = chd_dec_alloc_iodata(adp, 0);
244         if (!temp) {
245                 BCMLOG_ERR("Failed to get iodata..\n");
246                 return -EINVAL;
247         }
248
249         temp->u_id = uid;
250         temp->cmd  = cmd;
251
252         rc = chd_dec_proc_user_data(adp, temp, ua, 0);
253         if (!rc) {
254                 sts = func(&adp->cmds, temp);
255                 if (sts == BC_STS_PENDING)
256                         sts = BC_STS_NOT_IMPL;
257                 temp->udata.RetSts = sts;
258                 rc = chd_dec_proc_user_data(adp, temp, ua, 1);
259         }
260
261         chd_dec_free_iodata(adp, temp, 0);
262
263         return rc;
264 }
265
266 /* API interfaces */
267 static long chd_dec_ioctl(struct file *fd, unsigned int cmd, unsigned long ua)
268 {
269         struct crystalhd_adp *adp = chd_get_adp();
270         crystalhd_cmd_proc cproc;
271         struct crystalhd_user *uc;
272         int ret;
273
274         if (!adp || !fd) {
275                 BCMLOG_ERR("Invalid adp\n");
276                 return -EINVAL;
277         }
278
279         uc = fd->private_data;
280         if (!uc) {
281                 BCMLOG_ERR("Failed to get uc\n");
282                 return -ENODATA;
283         }
284
285         mutex_lock(&chd_dec_mutex);
286         cproc = crystalhd_get_cmd_proc(&adp->cmds, cmd, uc);
287         if (!cproc) {
288                 BCMLOG_ERR("Unhandled command: %d\n", cmd);
289                 mutex_unlock(&chd_dec_mutex);
290                 return -EINVAL;
291         }
292
293         ret = chd_dec_api_cmd(adp, ua, uc->uid, cmd, cproc);
294         mutex_unlock(&chd_dec_mutex);
295         return ret;
296 }
297
298 static int chd_dec_open(struct inode *in, struct file *fd)
299 {
300         struct crystalhd_adp *adp = chd_get_adp();
301         int rc = 0;
302         enum BC_STATUS sts = BC_STS_SUCCESS;
303         struct crystalhd_user *uc = NULL;
304
305         if (!adp) {
306                 BCMLOG_ERR("Invalid adp\n");
307                 return -EINVAL;
308         }
309
310         if (adp->cfg_users >= BC_LINK_MAX_OPENS) {
311                 BCMLOG(BCMLOG_INFO, "Already in use.%d\n", adp->cfg_users);
312                 return -EBUSY;
313         }
314
315         sts = crystalhd_user_open(&adp->cmds, &uc);
316         if (sts != BC_STS_SUCCESS) {
317                 BCMLOG_ERR("cmd_user_open - %d\n", sts);
318                 rc = -EBUSY;
319         }
320
321         adp->cfg_users++;
322
323         fd->private_data = uc;
324
325         return rc;
326 }
327
328 static int chd_dec_close(struct inode *in, struct file *fd)
329 {
330         struct crystalhd_adp *adp = chd_get_adp();
331         struct crystalhd_user *uc;
332
333         if (!adp) {
334                 BCMLOG_ERR("Invalid adp\n");
335                 return -EINVAL;
336         }
337
338         uc = fd->private_data;
339         if (!uc) {
340                 BCMLOG_ERR("Failed to get uc\n");
341                 return -ENODATA;
342         }
343
344         crystalhd_user_close(&adp->cmds, uc);
345
346         adp->cfg_users--;
347
348         return 0;
349 }
350
351 static const struct file_operations chd_dec_fops = {
352         .owner   = THIS_MODULE,
353         .unlocked_ioctl = chd_dec_ioctl,
354         .open    = chd_dec_open,
355         .release = chd_dec_close,
356         .llseek = noop_llseek,
357 };
358
359 static int chd_dec_init_chdev(struct crystalhd_adp *adp)
360 {
361         struct crystalhd_ioctl_data *temp;
362         struct device *dev;
363         int rc = -ENODEV, i = 0;
364
365         if (!adp)
366                 goto fail;
367
368         adp->chd_dec_major = register_chrdev(0, CRYSTALHD_API_NAME,
369                                              &chd_dec_fops);
370         if (adp->chd_dec_major < 0) {
371                 BCMLOG_ERR("Failed to create config dev\n");
372                 rc = adp->chd_dec_major;
373                 goto fail;
374         }
375
376         /* register crystalhd class */
377         crystalhd_class = class_create(THIS_MODULE, "crystalhd");
378         if (IS_ERR(crystalhd_class)) {
379                 rc = PTR_ERR(crystalhd_class);
380                 BCMLOG_ERR("failed to create class\n");
381                 goto class_create_fail;
382         }
383
384         dev = device_create(crystalhd_class, NULL,
385                          MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd");
386         if (IS_ERR(dev)) {
387                 rc = PTR_ERR(dev);
388                 BCMLOG_ERR("failed to create device\n");
389                 goto device_create_fail;
390         }
391
392         rc = crystalhd_create_elem_pool(adp, BC_LINK_ELEM_POOL_SZ);
393         if (rc) {
394                 BCMLOG_ERR("failed to create device\n");
395                 goto elem_pool_fail;
396         }
397
398         /* Allocate general purpose ioctl pool. */
399         for (i = 0; i < CHD_IODATA_POOL_SZ; i++) {
400                 temp = kzalloc(sizeof(struct crystalhd_ioctl_data),
401                                          GFP_KERNEL);
402                 if (!temp) {
403                         BCMLOG_ERR("ioctl data pool kzalloc failed\n");
404                         rc = -ENOMEM;
405                         goto kzalloc_fail;
406                 }
407                 /* Add to global pool.. */
408                 chd_dec_free_iodata(adp, temp, 0);
409         }
410
411         return 0;
412
413 kzalloc_fail:
414         crystalhd_delete_elem_pool(adp);
415 elem_pool_fail:
416         device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
417 device_create_fail:
418         class_destroy(crystalhd_class);
419 class_create_fail:
420         unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
421 fail:
422         return rc;
423 }
424
425 static void chd_dec_release_chdev(struct crystalhd_adp *adp)
426 {
427         struct crystalhd_ioctl_data *temp = NULL;
428         if (!adp)
429                 return;
430
431         if (adp->chd_dec_major > 0) {
432                 /* unregister crystalhd class */
433                 device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
434                 unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
435                 BCMLOG(BCMLOG_INFO, "released api device - %d\n",
436                        adp->chd_dec_major);
437                 class_destroy(crystalhd_class);
438         }
439         adp->chd_dec_major = 0;
440
441         /* Clear iodata pool.. */
442         do {
443                 temp = chd_dec_alloc_iodata(adp, 0);
444                 kfree(temp);
445         } while (temp);
446
447         crystalhd_delete_elem_pool(adp);
448 }
449
450 static int chd_pci_reserve_mem(struct crystalhd_adp *pinfo)
451 {
452         int rc;
453         unsigned long bar2 = pci_resource_start(pinfo->pdev, 2);
454         uint32_t mem_len   = pci_resource_len(pinfo->pdev, 2);
455         unsigned long bar0 = pci_resource_start(pinfo->pdev, 0);
456         uint32_t i2o_len   = pci_resource_len(pinfo->pdev, 0);
457
458         BCMLOG(BCMLOG_SSTEP, "bar2:0x%lx-0x%08x  bar0:0x%lx-0x%08x\n",
459                bar2, mem_len, bar0, i2o_len);
460
461         rc = check_mem_region(bar2, mem_len);
462         if (rc) {
463                 BCMLOG_ERR("No valid mem region...\n");
464                 return -ENOMEM;
465         }
466
467         pinfo->addr = ioremap_nocache(bar2, mem_len);
468         if (!pinfo->addr) {
469                 BCMLOG_ERR("Failed to remap mem region...\n");
470                 return -ENOMEM;
471         }
472
473         pinfo->pci_mem_start = bar2;
474         pinfo->pci_mem_len   = mem_len;
475
476         rc = check_mem_region(bar0, i2o_len);
477         if (rc) {
478                 BCMLOG_ERR("No valid mem region...\n");
479                 return -ENOMEM;
480         }
481
482         pinfo->i2o_addr = ioremap_nocache(bar0, i2o_len);
483         if (!pinfo->i2o_addr) {
484                 BCMLOG_ERR("Failed to remap mem region...\n");
485                 return -ENOMEM;
486         }
487
488         pinfo->pci_i2o_start = bar0;
489         pinfo->pci_i2o_len   = i2o_len;
490
491         rc = pci_request_regions(pinfo->pdev, pinfo->name);
492         if (rc < 0) {
493                 BCMLOG_ERR("Region request failed: %d\n", rc);
494                 return rc;
495         }
496
497         BCMLOG(BCMLOG_SSTEP, "Mapped addr:0x%08lx  i2o_addr:0x%08lx\n",
498                (unsigned long)pinfo->addr, (unsigned long)pinfo->i2o_addr);
499
500         return 0;
501 }
502
503 static void chd_pci_release_mem(struct crystalhd_adp *pinfo)
504 {
505         if (!pinfo)
506                 return;
507
508         if (pinfo->addr)
509                 iounmap(pinfo->addr);
510
511         if (pinfo->i2o_addr)
512                 iounmap(pinfo->i2o_addr);
513
514         pci_release_regions(pinfo->pdev);
515 }
516
517
518 static void chd_dec_pci_remove(struct pci_dev *pdev)
519 {
520         struct crystalhd_adp *pinfo;
521         enum BC_STATUS sts = BC_STS_SUCCESS;
522
523         pinfo = pci_get_drvdata(pdev);
524         if (!pinfo) {
525                 BCMLOG_ERR("could not get adp\n");
526                 return;
527         }
528
529         sts = crystalhd_delete_cmd_context(&pinfo->cmds);
530         if (sts != BC_STS_SUCCESS)
531                 BCMLOG_ERR("cmd delete :%d\n", sts);
532
533         chd_dec_release_chdev(pinfo);
534
535         chd_dec_disable_int(pinfo);
536
537         chd_pci_release_mem(pinfo);
538         pci_disable_device(pinfo->pdev);
539
540         kfree(pinfo);
541         g_adp_info = NULL;
542 }
543
544 static int chd_dec_pci_probe(struct pci_dev *pdev,
545                              const struct pci_device_id *entry)
546 {
547         struct crystalhd_adp *pinfo;
548         int rc;
549         enum BC_STATUS sts = BC_STS_SUCCESS;
550
551         BCMLOG(BCMLOG_DBG,
552                 "PCI_INFO: Vendor:0x%04x Device:0x%04x s_vendor:0x%04x s_device: 0x%04x\n",
553                 pdev->vendor, pdev->device, pdev->subsystem_vendor,
554                 pdev->subsystem_device);
555
556         pinfo = kzalloc(sizeof(struct crystalhd_adp), GFP_KERNEL);
557         if (!pinfo) {
558                 BCMLOG_ERR("Failed to allocate memory\n");
559                 return -ENOMEM;
560         }
561
562         pinfo->pdev = pdev;
563
564         rc = pci_enable_device(pdev);
565         if (rc) {
566                 BCMLOG_ERR("Failed to enable PCI device\n");
567                 goto err;
568         }
569
570         snprintf(pinfo->name, sizeof(pinfo->name), "crystalhd_pci_e:%d:%d:%d",
571                  pdev->bus->number, PCI_SLOT(pdev->devfn),
572                  PCI_FUNC(pdev->devfn));
573
574         rc = chd_pci_reserve_mem(pinfo);
575         if (rc) {
576                 BCMLOG_ERR("Failed to setup memory regions.\n");
577                 pci_disable_device(pdev);
578                 rc = -ENOMEM;
579                 goto err;
580         }
581
582         pinfo->present  = 1;
583         pinfo->drv_data = entry->driver_data;
584
585         /* Setup adapter level lock.. */
586         spin_lock_init(&pinfo->lock);
587
588         /* setup api stuff.. */
589         chd_dec_init_chdev(pinfo);
590         rc = chd_dec_enable_int(pinfo);
591         if (rc) {
592                 BCMLOG_ERR("_enable_int err:%d\n", rc);
593                 pci_disable_device(pdev);
594                 rc = -ENODEV;
595                 goto err;
596         }
597
598         /* Set dma mask... */
599         if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
600                 pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
601                 pinfo->dmabits = 64;
602         } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
603                 pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
604                 pinfo->dmabits = 32;
605         } else {
606                 BCMLOG_ERR("Unabled to setup DMA %d\n", rc);
607                 pci_disable_device(pdev);
608                 rc = -ENODEV;
609                 goto err;
610         }
611
612         sts = crystalhd_setup_cmd_context(&pinfo->cmds, pinfo);
613         if (sts != BC_STS_SUCCESS) {
614                 BCMLOG_ERR("cmd setup :%d\n", sts);
615                 pci_disable_device(pdev);
616                 rc = -ENODEV;
617                 goto err;
618         }
619
620         pci_set_master(pdev);
621
622         pci_set_drvdata(pdev, pinfo);
623
624         g_adp_info = pinfo;
625
626         return 0;
627
628 err:
629         kfree(pinfo);
630         return rc;
631 }
632
633 #ifdef CONFIG_PM
634 static int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state)
635 {
636         struct crystalhd_adp *adp;
637         struct crystalhd_ioctl_data *temp;
638         enum BC_STATUS sts = BC_STS_SUCCESS;
639
640         adp = pci_get_drvdata(pdev);
641         if (!adp) {
642                 BCMLOG_ERR("could not get adp\n");
643                 return -ENODEV;
644         }
645
646         temp = chd_dec_alloc_iodata(adp, false);
647         if (!temp) {
648                 BCMLOG_ERR("could not get ioctl data\n");
649                 return -ENODEV;
650         }
651
652         sts = crystalhd_suspend(&adp->cmds, temp);
653         if (sts != BC_STS_SUCCESS) {
654                 BCMLOG_ERR("BCM70012 Suspend %d\n", sts);
655                 return -ENODEV;
656         }
657
658         chd_dec_free_iodata(adp, temp, false);
659         chd_dec_disable_int(adp);
660         pci_save_state(pdev);
661
662         /* Disable IO/bus master/irq router */
663         pci_disable_device(pdev);
664         pci_set_power_state(pdev, pci_choose_state(pdev, state));
665         return 0;
666 }
667
668 static int chd_dec_pci_resume(struct pci_dev *pdev)
669 {
670         struct crystalhd_adp *adp;
671         enum BC_STATUS sts = BC_STS_SUCCESS;
672         int rc;
673
674         adp = pci_get_drvdata(pdev);
675         if (!adp) {
676                 BCMLOG_ERR("could not get adp\n");
677                 return -ENODEV;
678         }
679
680         pci_set_power_state(pdev, PCI_D0);
681         pci_restore_state(pdev);
682
683         /* device's irq possibly is changed, driver should take care */
684         if (pci_enable_device(pdev)) {
685                 BCMLOG_ERR("Failed to enable PCI device\n");
686                 return 1;
687         }
688
689         pci_set_master(pdev);
690
691         rc = chd_dec_enable_int(adp);
692         if (rc) {
693                 BCMLOG_ERR("_enable_int err:%d\n", rc);
694                 pci_disable_device(pdev);
695                 return -ENODEV;
696         }
697
698         sts = crystalhd_resume(&adp->cmds);
699         if (sts != BC_STS_SUCCESS) {
700                 BCMLOG_ERR("BCM70012 Resume %d\n", sts);
701                 pci_disable_device(pdev);
702                 return -ENODEV;
703         }
704
705         return 0;
706 }
707 #endif
708
709 static const struct pci_device_id chd_dec_pci_id_table[] = {
710         { PCI_VDEVICE(BROADCOM, 0x1612), 8 },
711         { 0, },
712 };
713 MODULE_DEVICE_TABLE(pci, chd_dec_pci_id_table);
714
715 static struct pci_driver bc_chd_70012_driver = {
716         .name     = "Broadcom 70012 Decoder",
717         .probe    = chd_dec_pci_probe,
718         .remove   = chd_dec_pci_remove,
719         .id_table = chd_dec_pci_id_table,
720 #ifdef CONFIG_PM
721         .suspend  = chd_dec_pci_suspend,
722         .resume   = chd_dec_pci_resume
723 #endif
724 };
725
726 void chd_set_log_level(struct crystalhd_adp *adp, char *arg)
727 {
728         if ((!arg) || (strlen(arg) < 3))
729                 g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA;
730         else if (!strncmp(arg, "sstep", 5))
731                 g_linklog_level = BCMLOG_INFO | BCMLOG_DATA | BCMLOG_DBG |
732                                   BCMLOG_SSTEP | BCMLOG_ERROR;
733         else if (!strncmp(arg, "info", 4))
734                 g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO;
735         else if (!strncmp(arg, "debug", 5))
736                 g_linklog_level = BCMLOG_ERROR | BCMLOG_DATA | BCMLOG_INFO |
737                                   BCMLOG_DBG;
738         else if (!strncmp(arg, "pball", 5))
739                 g_linklog_level = 0xFFFFFFFF & ~(BCMLOG_SPINLOCK);
740         else if (!strncmp(arg, "silent", 6))
741                 g_linklog_level = 0;
742         else
743                 g_linklog_level = 0;
744 }
745
746 struct crystalhd_adp *chd_get_adp(void)
747 {
748         return g_adp_info;
749 }
750
751 static int __init chd_dec_module_init(void)
752 {
753         int rc;
754
755         chd_set_log_level(NULL, "debug");
756         BCMLOG(BCMLOG_DATA, "Loading crystalhd %d.%d.%d\n",
757                crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
758
759         rc = pci_register_driver(&bc_chd_70012_driver);
760
761         if (rc < 0)
762                 BCMLOG_ERR("Could not find any devices. err:%d\n", rc);
763
764         return rc;
765 }
766 module_init(chd_dec_module_init);
767
768 static void __exit chd_dec_module_cleanup(void)
769 {
770         BCMLOG(BCMLOG_DATA, "unloading crystalhd %d.%d.%d\n",
771                crystalhd_kmod_major, crystalhd_kmod_minor, crystalhd_kmod_rev);
772
773         pci_unregister_driver(&bc_chd_70012_driver);
774 }
775 module_exit(chd_dec_module_cleanup);
776
777 MODULE_AUTHOR("Naren Sankar <nsankar@broadcom.com>");
778 MODULE_AUTHOR("Prasad Bolisetty <prasadb@broadcom.com>");
779 MODULE_DESCRIPTION(CRYSTAL_HD_NAME);
780 MODULE_LICENSE("GPL");
781 MODULE_ALIAS("bcm70012");