]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00227502-1 csi/v4l2: Implement probe and remove function for csi v4l2 driver
authorRobby Cai <R63905@freescale.com>
Tue, 9 Oct 2012 08:36:41 +0000 (16:36 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:32 +0000 (08:35 +0200)
Because csi_v4l2 driver will only be loaded when needed(by assign 'csi' in
kernel cmdline), we use standard driver framework to easily bind the device and
driver. Otherwise, we will meet the problem like the crash as below when do
suspend/resume due to the resource of csi not assigned at all if 'csi' not
passed in cmdline.

root@freescale ~$ echo mem > /sys/power/state
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.01 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = 9a8ac000
[00000000] *pgd=9a783831, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] PREEMPT
Modules linked in:
CPU: 0    Not tainted  (3.0.35-02115-g08f4436 #233)
PC is at csi_enable_mclk+0x40/0x68
LR is at camera_power+0x1c/0x5c
pc : [<80357f08>]    lr : [<80358154>]    psr: 60000013
sp : 9a8ebe30  ip : 00000009  fp : 00000006
r10: 1c6bddf7  r9 : 00000000  r8 : 00000000
r7 : 00000002  r6 : 804fd0ac  r5 : 9a013000  r4 : 00000000
r3 : 80aa8bbc  r2 : 00000000  r1 : 00000000  r0 : 00000008
...

Signed-off-by: Robby Cai <R63905@freescale.com>
drivers/media/video/mxc/capture/csi_v4l2_capture.c

index ada6d5e8afbd641752a5bb0d60e77cf85fcd5992..a0887b930ea469d09a71161eecd79c62a840f76e 100644 (file)
@@ -1365,22 +1365,6 @@ static struct video_device csi_v4l_template = {
        .release = video_device_release,
 };
 
-/*!
- * This function can be used to release any platform data on closing.
- */
-static void camera_platform_release(struct device *device)
-{
-}
-
-/*! Device Definition for csi v4l2 device */
-static struct platform_device csi_v4l2_devices = {
-       .name = "csi_v4l2",
-       .dev = {
-               .release = camera_platform_release,
-               },
-       .id = 0,
-};
-
 /*!
  * initialize cam_data structure
  *
@@ -1405,7 +1389,6 @@ static void init_camera_struct(cam_data *cam)
        *(cam->video_dev) = csi_v4l_template;
 
        video_set_drvdata(cam->video_dev, cam);
-       dev_set_drvdata(&csi_v4l2_devices.dev, (void *)cam);
        cam->video_dev->minor = -1;
 
        init_waitqueue_head(&cam->enc_queue);
@@ -1468,6 +1451,66 @@ static u8 camera_power(cam_data *cam, bool cameraOn)
        return 0;
 }
 
+static int __devinit csi_v4l2_probe(struct platform_device *pdev)
+{
+       struct scatterlist *sg;
+       u8 err = 0;
+
+       /* Create g_cam and initialize it. */
+       g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
+       if (g_cam == NULL) {
+               pr_err("ERROR: v4l2 capture: failed to register camera\n");
+               err = -ENOMEM;
+               goto out;
+       }
+       init_camera_struct(g_cam);
+       platform_set_drvdata(pdev, (void *)g_cam);
+
+       /* Set up the v4l2 device and register it */
+       csi_v4l2_int_device.priv = g_cam;
+       /* This function contains a bug that won't let this be rmmod'd. */
+       v4l2_int_device_register(&csi_v4l2_int_device);
+
+       /* register v4l video device */
+       if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr)
+           == -1) {
+               kfree(g_cam);
+               g_cam = NULL;
+               pr_err("ERROR: v4l2 capture: video_register_device failed\n");
+               err = -ENODEV;
+               goto out;
+       }
+       pr_debug("   Video device registered: %s #%d\n",
+                g_cam->video_dev->name, g_cam->video_dev->minor);
+
+       g_cam->pxp_chan = NULL;
+       /* Initialize Scatter-gather list containing 2 buffer addresses. */
+       sg = g_cam->sg;
+       sg_init_table(sg, 2);
+
+out:
+       return err;
+}
+
+static int __devexit csi_v4l2_remove(struct platform_device *pdev)
+{
+       if (g_cam->open_count) {
+               pr_err("ERROR: v4l2 capture:camera open "
+                      "-- setting ops to NULL\n");
+       } else {
+               pr_info("V4L2 freeing image input device\n");
+               v4l2_int_device_unregister(&csi_v4l2_int_device);
+               csi_stop_callback(g_cam);
+               video_unregister_device(g_cam->video_dev);
+               platform_set_drvdata(pdev, NULL);
+
+               kfree(g_cam);
+               g_cam = NULL;
+       }
+
+       return 0;
+}
+
 /*!
  * This function is called to put the sensor in a low power state.
  * Refer to the document driver-model/driver.txt in the kernel source tree
@@ -1533,8 +1576,8 @@ static struct platform_driver csi_v4l2_driver = {
        .driver = {
                   .name = "csi_v4l2",
                   },
-       .probe = NULL,
-       .remove = NULL,
+       .probe = csi_v4l2_probe,
+       .remove = __devexit_p(csi_v4l2_remove),
 #ifdef CONFIG_PM
        .suspend = csi_v4l2_suspend,
        .resume = csi_v4l2_resume,
@@ -1591,61 +1634,8 @@ static void csi_v4l2_master_detach(struct v4l2_int_device *slave)
  */
 static __init int camera_init(void)
 {
-       struct scatterlist *sg;
-       u8 err = 0;
-
        /* Register the device driver structure. */
-       err = platform_driver_register(&csi_v4l2_driver);
-       if (err != 0) {
-               pr_err("ERROR: v4l2 capture:camera_init: "
-                      "platform_driver_register failed.\n");
-               return err;
-       }
-
-       /* Create g_cam and initialize it. */
-       g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
-       if (g_cam == NULL) {
-               pr_err("ERROR: v4l2 capture: failed to register camera\n");
-               platform_driver_unregister(&csi_v4l2_driver);
-               return -1;
-       }
-       init_camera_struct(g_cam);
-
-       /* Set up the v4l2 device and register it */
-       csi_v4l2_int_device.priv = g_cam;
-       /* This function contains a bug that won't let this be rmmod'd. */
-       v4l2_int_device_register(&csi_v4l2_int_device);
-
-       /* Register the platform device */
-       err = platform_device_register(&csi_v4l2_devices);
-       if (err != 0) {
-               pr_err("ERROR: v4l2 capture: camera_init: "
-                      "platform_device_register failed.\n");
-               platform_driver_unregister(&csi_v4l2_driver);
-               kfree(g_cam);
-               g_cam = NULL;
-               return err;
-       }
-
-       /* register v4l video device */
-       if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr)
-           == -1) {
-               platform_device_unregister(&csi_v4l2_devices);
-               platform_driver_unregister(&csi_v4l2_driver);
-               kfree(g_cam);
-               g_cam = NULL;
-               pr_err("ERROR: v4l2 capture: video_register_device failed\n");
-               return -1;
-       }
-       pr_debug("   Video device registered: %s #%d\n",
-                g_cam->video_dev->name, g_cam->video_dev->minor);
-
-       g_cam->pxp_chan = NULL;
-       /* Initialize Scatter-gather list containing 2 buffer addresses. */
-       sg = g_cam->sg;
-       sg_init_table(sg, 2);
-
-       return err;
+       return platform_driver_register(&csi_v4l2_driver);
 }
 
 /*!
@@ -1653,22 +1643,7 @@ static __init int camera_init(void)
  */
 static void __exit camera_exit(void)
 {
-       pr_debug("In MVC: %s\n", __func__);
-
-       if (g_cam->open_count) {
-               pr_err("ERROR: v4l2 capture:camera open "
-                      "-- setting ops to NULL\n");
-       } else {
-               pr_info("V4L2 freeing image input device\n");
-               v4l2_int_device_unregister(&csi_v4l2_int_device);
-               csi_stop_callback(g_cam);
-               video_unregister_device(g_cam->video_dev);
-               platform_driver_unregister(&csi_v4l2_driver);
-               platform_device_unregister(&csi_v4l2_devices);
-
-               kfree(g_cam);
-               g_cam = NULL;
-       }
+       platform_driver_unregister(&csi_v4l2_driver);
 }
 
 module_init(camera_init);