1 /* 2 * V4L2 Image Converter Subdev for Freescale i.MX5/6 SOC 3 * 4 * Copyright (c) 2014-2016 Mentor Graphics Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 */ 11 #include <linux/module.h> 12 #include <linux/platform_device.h> 13 #include <media/v4l2-device.h> 14 #include <media/v4l2-subdev.h> 15 #include "imx-media.h" 16 #include "imx-ic.h" 17 18 #define IC_TASK_PRP IC_NUM_TASKS 19 #define IC_NUM_OPS (IC_NUM_TASKS + 1) 20 21 static struct imx_ic_ops *ic_ops[IC_NUM_OPS] = { 22 [IC_TASK_PRP] = &imx_ic_prp_ops, 23 [IC_TASK_ENCODER] = &imx_ic_prpencvf_ops, 24 [IC_TASK_VIEWFINDER] = &imx_ic_prpencvf_ops, 25 }; 26 27 static int imx_ic_probe(struct platform_device *pdev) 28 { 29 struct imx_media_internal_sd_platformdata *pdata; 30 struct imx_ic_priv *priv; 31 int ret; 32 33 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 34 if (!priv) 35 return -ENOMEM; 36 37 platform_set_drvdata(pdev, &priv->sd); 38 priv->dev = &pdev->dev; 39 40 /* get our ipu_id, grp_id and IC task id */ 41 pdata = priv->dev->platform_data; 42 priv->ipu_id = pdata->ipu_id; 43 switch (pdata->grp_id) { 44 case IMX_MEDIA_GRP_ID_IC_PRP: 45 priv->task_id = IC_TASK_PRP; 46 break; 47 case IMX_MEDIA_GRP_ID_IC_PRPENC: 48 priv->task_id = IC_TASK_ENCODER; 49 break; 50 case IMX_MEDIA_GRP_ID_IC_PRPVF: 51 priv->task_id = IC_TASK_VIEWFINDER; 52 break; 53 default: 54 return -EINVAL; 55 } 56 57 v4l2_subdev_init(&priv->sd, ic_ops[priv->task_id]->subdev_ops); 58 v4l2_set_subdevdata(&priv->sd, priv); 59 priv->sd.internal_ops = ic_ops[priv->task_id]->internal_ops; 60 priv->sd.entity.ops = ic_ops[priv->task_id]->entity_ops; 61 priv->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; 62 priv->sd.dev = &pdev->dev; 63 priv->sd.owner = THIS_MODULE; 64 priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; 65 priv->sd.grp_id = pdata->grp_id; 66 strncpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); 67 68 ret = ic_ops[priv->task_id]->init(priv); 69 if (ret) 70 return ret; 71 72 ret = v4l2_async_register_subdev(&priv->sd); 73 if (ret) 74 ic_ops[priv->task_id]->remove(priv); 75 76 return ret; 77 } 78 79 static int imx_ic_remove(struct platform_device *pdev) 80 { 81 struct v4l2_subdev *sd = platform_get_drvdata(pdev); 82 struct imx_ic_priv *priv = container_of(sd, struct imx_ic_priv, sd); 83 84 v4l2_info(sd, "Removing\n"); 85 86 ic_ops[priv->task_id]->remove(priv); 87 88 v4l2_async_unregister_subdev(sd); 89 media_entity_cleanup(&sd->entity); 90 91 return 0; 92 } 93 94 static const struct platform_device_id imx_ic_ids[] = { 95 { .name = "imx-ipuv3-ic" }, 96 { }, 97 }; 98 MODULE_DEVICE_TABLE(platform, imx_ic_ids); 99 100 static struct platform_driver imx_ic_driver = { 101 .probe = imx_ic_probe, 102 .remove = imx_ic_remove, 103 .id_table = imx_ic_ids, 104 .driver = { 105 .name = "imx-ipuv3-ic", 106 }, 107 }; 108 module_platform_driver(imx_ic_driver); 109 110 MODULE_DESCRIPTION("i.MX IC subdev driver"); 111 MODULE_AUTHOR("Steve Longerbeam <steve_longerbeam@mentor.com>"); 112 MODULE_LICENSE("GPL"); 113 MODULE_ALIAS("platform:imx-ipuv3-ic"); 114