* Based on the soc-camera rcar_vin driver
*/
+#include <linux/idr.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
* be only one group for all instances.
*/
+static DEFINE_IDA(rvin_ida);
static DEFINE_MUTEX(rvin_group_lock);
static struct rvin_group *rvin_group_data;
const struct media_device_ops *ops)
{
struct rvin_group *group;
- u32 id;
int ret;
- /* Make sure VIN id is present and sane */
- ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id);
- if (ret) {
- vin_err(vin, "%pOF: No renesas,id property found\n",
- vin->dev->of_node);
- return -EINVAL;
- }
-
- if (id >= RCAR_VIN_NUM) {
- vin_err(vin, "%pOF: Invalid renesas,id '%u'\n",
- vin->dev->of_node, id);
- return -EINVAL;
- }
-
/* Join or create a VIN group */
mutex_lock(&rvin_group_lock);
if (rvin_group_data) {
/* Add VIN to group */
mutex_lock(&group->lock);
- if (group->vin[id]) {
- vin_err(vin, "Duplicate renesas,id property value %u\n", id);
+ if (group->vin[vin->id]) {
+ vin_err(vin, "Duplicate renesas,id property value %u\n", vin->id);
mutex_unlock(&group->lock);
kref_put(&group->refcount, rvin_group_release);
return -EINVAL;
}
- group->vin[id] = vin;
+ group->vin[vin->id] = vin;
- vin->id = id;
vin->group = group;
vin->v4l2_dev.mdev = &group->mdev;
};
MODULE_DEVICE_TABLE(of, rvin_of_id_table);
+static int rvin_id_get(struct rvin_dev *vin)
+{
+ u32 oid;
+ int id;
+
+ switch (vin->info->model) {
+ case RCAR_GEN3:
+ case RCAR_GEN4:
+ if (of_property_read_u32(vin->dev->of_node, "renesas,id", &oid)) {
+ vin_err(vin, "%pOF: No renesas,id property found\n",
+ vin->dev->of_node);
+ return -EINVAL;
+ }
+
+ if (oid < 0 || oid >= RCAR_VIN_NUM) {
+ vin_err(vin, "%pOF: Invalid renesas,id '%u'\n",
+ vin->dev->of_node, oid);
+ return -EINVAL;
+ }
+
+ vin->id = oid;
+ break;
+ default:
+ id = ida_alloc_range(&rvin_ida, 0, RCAR_VIN_NUM - 1,
+ GFP_KERNEL);
+ if (id < 0) {
+ vin_err(vin, "%pOF: Failed to allocate VIN group ID\n",
+ vin->dev->of_node);
+ return -EINVAL;
+ }
+
+ vin->id = id;
+ break;
+ }
+
+ return 0;
+}
+
+static void rvin_id_put(struct rvin_dev *vin)
+{
+ switch (vin->info->model) {
+ case RCAR_GEN3:
+ case RCAR_GEN4:
+ break;
+ default:
+ ida_free(&rvin_ida, vin->id);
+ break;
+ }
+}
+
static int rcar_vin_probe(struct platform_device *pdev)
{
struct rvin_dev *vin;
platform_set_drvdata(pdev, vin);
+ if (rvin_id_get(vin)) {
+ ret = -EINVAL;
+ goto err_dma;
+ }
+
if (vin->info->use_isp) {
ret = rvin_isp_init(vin);
} else if (vin->info->use_mc) {
}
if (ret)
- goto err_dma;
+ goto err_id;
pm_suspend_ignore_children(&pdev->dev, true);
pm_runtime_enable(&pdev->dev);
return 0;
+err_id:
+ rvin_id_put(vin);
err_dma:
rvin_dma_unregister(vin);
else
rvin_parallel_cleanup(vin);
+ rvin_id_put(vin);
+
rvin_dma_unregister(vin);
}