112 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Driver for STM32 Digital Camera Memory Interface Pixel Processor4 *5 * Copyright (C) STMicroelectronics SA 20236 * Authors: Hugues Fruchet <hugues.fruchet@foss.st.com>7 * Alain Volmat <alain.volmat@foss.st.com>8 * for STMicroelectronics.9 */10 11#include <linux/init.h>12#include <linux/module.h>13 14#include "dcmipp-common.h"15 16/* Helper function to allocate and initialize pads */17struct media_pad *dcmipp_pads_init(u16 num_pads, const unsigned long *pads_flags)18{19 struct media_pad *pads;20 unsigned int i;21 22 /* Allocate memory for the pads */23 pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);24 if (!pads)25 return ERR_PTR(-ENOMEM);26 27 /* Initialize the pads */28 for (i = 0; i < num_pads; i++) {29 pads[i].index = i;30 pads[i].flags = pads_flags[i];31 }32 33 return pads;34}35 36static const struct media_entity_operations dcmipp_entity_ops = {37 .link_validate = v4l2_subdev_link_validate,38};39 40int dcmipp_ent_sd_register(struct dcmipp_ent_device *ved,41 struct v4l2_subdev *sd,42 struct v4l2_device *v4l2_dev,43 const char *const name,44 u32 function,45 u16 num_pads,46 const unsigned long *pads_flag,47 const struct v4l2_subdev_internal_ops *sd_int_ops,48 const struct v4l2_subdev_ops *sd_ops,49 irq_handler_t handler,50 irq_handler_t thread_fn)51{52 int ret;53 54 /* Allocate the pads. Should be released from the sd_int_op release */55 ved->pads = dcmipp_pads_init(num_pads, pads_flag);56 if (IS_ERR(ved->pads))57 return PTR_ERR(ved->pads);58 59 /* Fill the dcmipp_ent_device struct */60 ved->ent = &sd->entity;61 62 /* Initialize the subdev */63 v4l2_subdev_init(sd, sd_ops);64 sd->internal_ops = sd_int_ops;65 sd->entity.function = function;66 sd->entity.ops = &dcmipp_entity_ops;67 sd->owner = THIS_MODULE;68 strscpy(sd->name, name, sizeof(sd->name));69 v4l2_set_subdevdata(sd, ved);70 71 /* Expose this subdev to user space */72 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;73 if (sd->ctrl_handler)74 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;75 76 /* Initialize the media entity */77 ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);78 if (ret)79 goto err_clean_pads;80 81 ret = v4l2_subdev_init_finalize(sd);82 if (ret < 0)83 goto err_clean_m_ent;84 85 /* Register the subdev with the v4l2 and the media framework */86 ret = v4l2_device_register_subdev(v4l2_dev, sd);87 if (ret) {88 dev_err(v4l2_dev->dev,89 "%s: subdev register failed (err=%d)\n",90 name, ret);91 goto err_clean_m_ent;92 }93 94 ved->handler = handler;95 ved->thread_fn = thread_fn;96 97 return 0;98 99err_clean_m_ent:100 media_entity_cleanup(&sd->entity);101err_clean_pads:102 dcmipp_pads_cleanup(ved->pads);103 return ret;104}105 106void107dcmipp_ent_sd_unregister(struct dcmipp_ent_device *ved, struct v4l2_subdev *sd)108{109 media_entity_cleanup(ved->ent);110 v4l2_device_unregister_subdev(sd);111}112