diff options
Diffstat (limited to 'drivers/media/platform/mxc/capture/mxc_v4l2_capture.c')
-rw-r--r-- | drivers/media/platform/mxc/capture/mxc_v4l2_capture.c | 181 |
1 files changed, 149 insertions, 32 deletions
diff --git a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c index 936514db9944..4fdec11be414 100644 --- a/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c +++ b/drivers/media/platform/mxc/capture/mxc_v4l2_capture.c @@ -27,8 +27,12 @@ #include <linux/fb.h> #include <linux/dma-mapping.h> #include <linux/delay.h> +#include <linux/mfd/syscon.h> +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/mutex.h> #include <linux/mxcfb.h> #include <linux/of_device.h> +#include <linux/regmap.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-device.h> @@ -37,6 +41,13 @@ #include "mxc_v4l2_capture.h" #include "ipu_prp_sw.h" +#if 0 +#undef dev_dbg +#define dev_dbg(dev, format, arg...) {dev_printk(KERN_ERR, dev, format, ##arg);} +#undef pr_debug +#define pr_debug(fmt, ...) printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) +#endif + #define init_MUTEX(sem) sema_init(sem, 1) static struct platform_device_id imx_v4l2_devtype[] = { @@ -986,7 +997,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->bright = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_BRIGHTNESS\n"); status = -ENODEV; } break; @@ -996,7 +1007,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->hue = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_HUE\n"); status = -ENODEV; } break; @@ -1006,7 +1017,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->contrast = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_CONTRAST\n"); status = -ENODEV; } break; @@ -1016,7 +1027,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->saturation = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_SATURATION\n"); status = -ENODEV; } break; @@ -1026,7 +1037,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->red = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_RED_BALANCE\n"); status = -ENODEV; } break; @@ -1036,7 +1047,7 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->blue = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_BLUE_BALANCE\n"); status = -ENODEV; } break; @@ -1046,12 +1057,12 @@ static int mxc_v4l2_g_ctrl(cam_data *cam, struct v4l2_control *c) status = vidioc_int_g_ctrl(cam->sensor, c); cam->ae_mode = c->value; } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_BLACK_LEVEL\n"); status = -ENODEV; } break; default: - pr_err("ERROR: v4l2 capture: unsupported ioctrl!\n"); + pr_debug("ERROR: v4l2 capture: unsupported ioctrl!\n"); } return status; @@ -1156,7 +1167,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->hue = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_HUE\n"); ret = -ENODEV; } break; @@ -1165,7 +1176,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->contrast = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_CONTRAST\n"); ret = -ENODEV; } break; @@ -1174,7 +1185,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->bright = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_BRIGHTNESS\n"); ret = -ENODEV; } break; @@ -1183,7 +1194,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->saturation = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_SATURATION\n"); ret = -ENODEV; } break; @@ -1192,7 +1203,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->red = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_RED_BALANCE\n"); ret = -ENODEV; } break; @@ -1201,7 +1212,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->blue = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_BLUE_BALANCE\n"); ret = -ENODEV; } break; @@ -1210,7 +1221,7 @@ static int mxc_v4l2_s_ctrl(cam_data *cam, struct v4l2_control *c) cam->ae_mode = c->value; ret = vidioc_int_s_ctrl(cam->sensor, c); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_EXPOSURE\n"); ret = -ENODEV; } break; @@ -1340,6 +1351,8 @@ static int mxc_v4l2_s_param(cam_data *cam, struct v4l2_streamparm *parm) pr_debug(" clock_curr=mclk=%d\n", ifparm.u.bt656.clock_curr); if (ifparm.u.bt656.clock_curr == 0) csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_INTERLACED; + else if (ifparm.u.bt656.clock_curr == 1) + csi_param.clk_mode = IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE; else csi_param.clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; @@ -1548,6 +1561,39 @@ static int mxc_v4l_dqueue(cam_data *cam, struct v4l2_buffer *buf) return retval; } +static void power_down_callback(struct work_struct *work) +{ + cam_data *cam = container_of(work, struct _cam_data, power_down_work.work); + + down(&cam->busy_lock); + if (!cam->open_count) { + vidioc_int_s_power(cam->sensor, 0); + cam->power_on = 0; + } + up(&cam->busy_lock); +} + +/* cam->busy_lock is held */ +void power_up_camera(cam_data *cam) +{ + if (cam->power_on) { + cancel_delayed_work(&cam->power_down_work); + return; + } + vidioc_int_s_power(cam->sensor, 1); + vidioc_int_init(cam->sensor); + vidioc_int_dev_init(cam->sensor); + cam->power_on = 1; +} + + +void power_off_camera(cam_data *cam) +{ + schedule_delayed_work(&cam->power_down_work, (HZ * 2)); +} + +unsigned long csi_in_use; + /*! * V4L interface - open function * @@ -1565,6 +1611,7 @@ static int mxc_v4l_open(struct file *file) cam_data *cam = video_get_drvdata(dev); int err = 0; struct sensor_data *sensor; + int csi_bit; pr_debug("\nIn MVC: mxc_v4l_open\n"); pr_debug(" device name is %s\n", dev->name); @@ -1577,7 +1624,7 @@ static int mxc_v4l_open(struct file *file) if (cam->sensor == NULL || cam->sensor->type != v4l2_int_type_slave) { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! V4L2_CID_HUE\n"); return -EAGAIN; } @@ -1589,11 +1636,45 @@ static int mxc_v4l_open(struct file *file) } down(&cam->busy_lock); + err = 0; if (signal_pending(current)) goto oops; if (cam->open_count++ == 0) { + struct regmap *gpr; + + csi_bit = (cam->ipu_id << 1) | cam->csi; + if (test_and_set_bit(csi_bit, &csi_in_use)) { + pr_err("%s: %s CSI already in use\n", __func__, dev->name); + err = -EBUSY; + cam->open_count = 0; + goto oops; + } + cam->csi_in_use = 1; + + gpr = syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr"); + if (!IS_ERR(gpr)) { + if (of_machine_is_compatible("fsl,imx6q")) { + if (cam->ipu_id == cam->csi) { + unsigned shift = 19 + cam->csi; + unsigned mask = 1 << shift; + unsigned val = (cam->mipi_camera ? 0 : 1) << shift; + + regmap_update_bits(gpr, IOMUXC_GPR1, mask, val); + } + } else if (of_machine_is_compatible("fsl,imx6dl")) { + unsigned shift = cam->csi * 3; + unsigned mask = 7 << shift; + unsigned val = (cam->mipi_camera ? csi_bit : 4) << shift; + + regmap_update_bits(gpr, IOMUXC_GPR13, mask, val); + } + } else { + pr_err("%s: failed to find fsl,imx6q-iomux-gpr regmap\n", + __func__); + } + wait_event_interruptible(cam->power_queue, cam->low_power == false); @@ -1691,9 +1772,7 @@ static int mxc_v4l_open(struct file *file) cam_fmt.fmt.pix.pixelformat, csi_param); clk_prepare_enable(sensor->sensor_clk); - vidioc_int_s_power(cam->sensor, 1); - vidioc_int_init(cam->sensor); - vidioc_int_dev_init(cam->sensor); + power_up_camera(cam); } file->private_data = dev; @@ -1750,7 +1829,6 @@ static int mxc_v4l_close(struct file *file) } if (--cam->open_count == 0) { - vidioc_int_s_power(cam->sensor, 0); clk_disable_unprepare(sensor->sensor_clk); wait_event_interruptible(cam->power_queue, cam->low_power == false); @@ -1775,6 +1853,14 @@ static int mxc_v4l_close(struct file *file) wake_up_interruptible(&cam->enc_queue); mxc_free_frames(cam); cam->enc_counter++; + power_off_camera(cam); + + if (cam->csi_in_use) { + int csi_bit = (cam->ipu_id << 1) | cam->csi; + + clear_bit(csi_bit, &csi_in_use); + cam->csi_in_use = 0; + } } up(&cam->busy_lock); @@ -2219,7 +2305,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = vidioc_int_g_parm(cam->sensor, parm); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_G_PARM\n"); retval = -ENODEV; } break; @@ -2231,7 +2317,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = mxc_v4l2_s_param(cam, parm); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_S_PARM\n"); retval = -ENODEV; } break; @@ -2241,6 +2327,10 @@ static long mxc_v4l_do_ioctl(struct file *file, case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; pr_debug(" case VIDIOC_ENUMSTD\n"); + if (e->index > 0) { + retval = -EINVAL; + break; + } *e = cam->standard; break; } @@ -2251,7 +2341,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = mxc_v4l2_g_std(cam, e); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_G_STD\n"); retval = -ENODEV; } break; @@ -2356,7 +2446,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = vidioc_int_enum_fmt_cap(cam->sensor, f); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_ENUM_FMT\n"); retval = -ENODEV; } break; @@ -2366,7 +2456,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = vidioc_int_enum_framesizes(cam->sensor, fsize); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_ENUM_FRAMESIZES\n"); retval = -ENODEV; } break; @@ -2377,7 +2467,7 @@ static long mxc_v4l_do_ioctl(struct file *file, retval = vidioc_int_enum_frameintervals(cam->sensor, fival); } else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_ENUM_FRAMEINTERVALS\n"); retval = -ENODEV; } break; @@ -2389,7 +2479,7 @@ static long mxc_v4l_do_ioctl(struct file *file, if (cam->sensor) retval = vidioc_int_g_chip_ident(cam->sensor, (int *)p); else { - pr_err("ERROR: v4l2 capture: slave not found!\n"); + pr_err("ERROR: v4l2 capture: slave not found! VIDIOC_DBG_G_CHIP_IDENT\n"); retval = -ENODEV; } break; @@ -2617,9 +2707,10 @@ static int init_camera_struct(cam_data *cam, struct platform_device *pdev) const struct of_device_id *of_id = of_match_device(mxc_v4l2_dt_ids, &pdev->dev); struct device_node *np = pdev->dev.of_node; - int ipu_id, csi_id, mclk_source; + int ipu_id, csi_id, mclk_source, mipi_camera; int ret = 0; struct v4l2_device *v4l2_dev; + static int camera_id; pr_debug("In MVC: init_camera_struct\n"); @@ -2641,6 +2732,10 @@ static int init_camera_struct(cam_data *cam, struct platform_device *pdev) return ret; } + ret = of_property_read_u32(np, "mipi_camera", &mipi_camera); + if (ret) + mipi_camera = 0; + /* Default everything to 0 */ memset(cam, 0, sizeof(cam_data)); @@ -2663,6 +2758,7 @@ static int init_camera_struct(cam_data *cam, struct platform_device *pdev) init_MUTEX(&cam->param_lock); init_MUTEX(&cam->busy_lock); + INIT_DELAYED_WORK(&cam->power_down_work, power_down_callback); cam->video_dev = video_device_alloc(); if (cam->video_dev == NULL) @@ -2729,6 +2825,7 @@ static int init_camera_struct(cam_data *cam, struct platform_device *pdev) cam->ipu_id = ipu_id; cam->csi = csi_id; + cam->mipi_camera = mipi_camera; cam->mclk_source = mclk_source; cam->mclk_on[cam->mclk_source] = false; @@ -2739,7 +2836,7 @@ static int init_camera_struct(cam_data *cam, struct platform_device *pdev) cam->self = kmalloc(sizeof(struct v4l2_int_device), GFP_KERNEL); cam->self->module = THIS_MODULE; - sprintf(cam->self->name, "mxc_v4l2_cap%d", cam->csi); + sprintf(cam->self->name, "mxc_v4l2_cap%d", camera_id++); cam->self->type = v4l2_int_type_master; cam->self->u.master = &mxc_v4l2_master; @@ -2951,7 +3048,8 @@ static int mxc_v4l2_resume(struct platform_device *pdev) wake_up_interruptible(&cam->power_queue); if (cam->sensor && cam->open_count) { - vidioc_int_s_power(cam->sensor, 1); + if ((cam->overlay_on == true) || (cam->capture_on == true)) + vidioc_int_s_power(cam->sensor, 1); if (!cam->mclk_on[cam->mclk_source]) { ipu_csi_enable_mclk_if(cam->ipu, CSI_MCLK_I2C, @@ -3012,8 +3110,9 @@ static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) return -1; } - if (sdata->csi != cam->csi) { - pr_debug("%s: csi doesn't match\n", __func__); + if ((sdata->ipu_id != cam->ipu_id) || (sdata->csi != cam->csi) || (sdata->mipi_camera != cam->mipi_camera)) { + pr_info("%s: ipu(%d:%d)/csi(%d:%d)/mipi(%d:%d) doesn't match\n", __func__, + sdata->ipu_id, cam->ipu_id, sdata->csi, cam->csi, sdata->mipi_camera, cam->mipi_camera); return -1; } @@ -3067,6 +3166,10 @@ static int mxc_v4l2_master_attach(struct v4l2_int_device *slave) __func__, cam->crop_current.width, cam->crop_current.height); + pr_info("%s: ipu%d:/csi%d %s attached %s:%s\n", __func__, + cam->ipu_id, cam->csi, cam->mipi_camera ? "mipi" : "parallel", + slave->name, slave->u.slave->master->name); + return 0; } @@ -3100,6 +3203,20 @@ static void mxc_v4l2_master_detach(struct v4l2_int_device *slave) vidioc_int_dev_exit(slave); } +DEFINE_MUTEX(camera_common_mutex); + +void mxc_camera_common_lock(void) +{ + mutex_lock(&camera_common_mutex); +} +EXPORT_SYMBOL(mxc_camera_common_lock); + +void mxc_camera_common_unlock(void) +{ + mutex_unlock(&camera_common_mutex); +} +EXPORT_SYMBOL(mxc_camera_common_unlock); + /*! * Entry point for the V4L2 * |