msm: mpq8064: Allow power up and down to be more dynamic
To save power regulators are only powered on when needed. Also in
this change is that clock rate is not longer set to max rate.
Clock speed set to lowest rate and still remain properly functional
Change-Id: I7141c8d630e4dbf5c2593e0aea9a18dc3866a1fd
Signed-off-by: Terence Hampson <thampson@codeaurora.org>
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index b9617f3..09e30c1 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -2316,13 +2316,21 @@
},
};
-
static struct msm_bus_vectors vcap_480_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_CAP,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1280 * 720 * 3 * 60,
- .ib = 1280 * 720 * 3 * 60 * 1.5,
+ .ab = 480 * 720 * 3 * 60,
+ .ib = 480 * 720 * 3 * 60 * 1.5,
+ },
+};
+
+static struct msm_bus_vectors vcap_576_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_CAP,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 576 * 720 * 3 * 60,
+ .ib = 576 * 720 * 3 * 60 * 1.5,
},
};
@@ -2354,6 +2362,10 @@
vcap_480_vectors,
},
{
+ ARRAY_SIZE(vcap_576_vectors),
+ vcap_576_vectors,
+ },
+ {
ARRAY_SIZE(vcap_720_vectors),
vcap_720_vectors,
},
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 80b576e..db0dbc2 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -59,6 +59,228 @@
printk(KERN_DEBUG "VCAP: " fmt, ## arg); \
} while (0)
+int vcap_reg_powerup(struct vcap_dev *dev)
+{
+ dev->fs_vcap = regulator_get(NULL, "fs_vcap");
+ if (IS_ERR(dev->fs_vcap)) {
+ pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
+ PTR_ERR(dev->fs_vcap));
+ dev->fs_vcap = NULL;
+ return -EINVAL;
+ } else if (regulator_enable(dev->fs_vcap)) {
+ pr_err("%s: Regulator FS_VCAP enable failed\n", __func__);
+ regulator_put(dev->fs_vcap);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void vcap_reg_powerdown(struct vcap_dev *dev)
+{
+ if (dev->fs_vcap == NULL)
+ return;
+ regulator_disable(dev->fs_vcap);
+ regulator_put(dev->fs_vcap);
+ dev->fs_vcap = NULL;
+ return;
+}
+
+int config_gpios(int on, struct vcap_platform_data *pdata)
+{
+ int i, ret;
+ int num_gpios = pdata->num_gpios;
+ unsigned *gpios = pdata->gpios;
+
+ dprintk(4, "GPIO config start\n");
+ if (on) {
+ for (i = 0; i < num_gpios; i++) {
+ ret = gpio_request(gpios[i], "vcap:vc");
+ if (ret) {
+ pr_err("VCAP: failed at GPIO %d to request\n",
+ gpios[i]);
+ goto gpio_failed;
+ }
+ ret = gpio_direction_input(gpios[i]);
+ if (ret) {
+ pr_err("VCAP: failed at GPIO %d to set to input\n",
+ gpios[i]);
+ i++;
+ goto gpio_failed;
+ }
+ }
+ } else {
+ for (i = 0; i < num_gpios; i++)
+ gpio_free(gpios[i]);
+ }
+ dprintk(4, "GPIO config exit\n");
+ return 0;
+gpio_failed:
+ for (i--; i >= 0; i--)
+ gpio_free(gpios[i]);
+ return -EINVAL;
+}
+
+int vcap_clk_powerup(struct vcap_dev *dev, struct device *ddev,
+ unsigned long rate)
+{
+ int ret = 0;
+
+ dev->vcap_clk = clk_get(ddev, "core_clk");
+ if (IS_ERR(dev->vcap_clk)) {
+ dev->vcap_clk = NULL;
+ pr_err("%s: Could not clk_get core_clk\n", __func__);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ return -EINVAL;
+ }
+
+ clk_prepare(dev->vcap_clk);
+ ret = clk_enable(dev->vcap_clk);
+ if (ret) {
+ pr_err("%s: Failed core clk_enable %d\n", __func__, ret);
+ goto fail_vcap_clk_unprep;
+ }
+
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate < 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ goto fail_vcap_clk;
+ }
+ ret = clk_set_rate(dev->vcap_clk, rate);
+ if (ret < 0) {
+ pr_err("%s: Failed core set_rate %d\n", __func__, ret);
+ goto fail_vcap_clk;
+ }
+
+ dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
+ if (IS_ERR(dev->vcap_npl_clk)) {
+ dev->vcap_npl_clk = NULL;
+ pr_err("%s: Could not clk_get npl\n", __func__);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+ goto fail_vcap_clk;
+ }
+
+ clk_prepare(dev->vcap_npl_clk);
+ ret = clk_enable(dev->vcap_npl_clk);
+ if (ret) {
+ pr_err("%s:Failed npl clk_enable %d\n", __func__, ret);
+ goto fail_vcap_npl_clk_unprep;
+ }
+
+ dev->vcap_p_clk = clk_get(ddev, "iface_clk");
+ if (IS_ERR(dev->vcap_p_clk)) {
+ dev->vcap_p_clk = NULL;
+ pr_err("%s: Could not clk_get pix(AHB)\n", __func__);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+ goto fail_vcap_npl_clk;
+ }
+
+ clk_prepare(dev->vcap_p_clk);
+ ret = clk_enable(dev->vcap_p_clk);
+ if (ret) {
+ pr_err("%s: Failed pix(AHB) clk_enable %d\n", __func__, ret);
+ goto fail_vcap_p_clk_unprep;
+ }
+ return 0;
+
+fail_vcap_p_clk_unprep:
+ clk_unprepare(dev->vcap_p_clk);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+
+fail_vcap_npl_clk:
+ clk_disable(dev->vcap_npl_clk);
+fail_vcap_npl_clk_unprep:
+ clk_unprepare(dev->vcap_npl_clk);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+
+fail_vcap_clk:
+ clk_disable(dev->vcap_clk);
+fail_vcap_clk_unprep:
+ clk_unprepare(dev->vcap_clk);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ return -EINVAL;
+}
+
+void vcap_clk_powerdown(struct vcap_dev *dev)
+{
+ if (dev->vcap_p_clk != NULL) {
+ clk_disable(dev->vcap_p_clk);
+ clk_unprepare(dev->vcap_p_clk);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+ }
+
+ if (dev->vcap_npl_clk != NULL) {
+ clk_disable(dev->vcap_npl_clk);
+ clk_unprepare(dev->vcap_npl_clk);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+ }
+
+ if (dev->vcap_clk != NULL) {
+ clk_disable(dev->vcap_clk);
+ clk_unprepare(dev->vcap_clk);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ }
+}
+
+int vcap_get_bus_client_handle(struct vcap_dev *dev)
+{
+ struct msm_bus_scale_pdata *vcap_axi_client_pdata =
+ dev->vcap_pdata->bus_client_pdata;
+ dev->bus_client_handle =
+ msm_bus_scale_register_client(vcap_axi_client_pdata);
+
+ return 0;
+}
+
+int vcap_enable(struct vcap_dev *dev, struct device *ddev,
+ unsigned long rate)
+{
+ int rc;
+
+ rc = vcap_reg_powerup(dev);
+ if (rc < 0)
+ goto reg_failed;
+ rc = vcap_clk_powerup(dev, ddev, rate);
+ if (rc < 0)
+ goto clk_failed;
+ rc = vcap_get_bus_client_handle(dev);
+ if (rc < 0)
+ goto bus_r_failed;
+ rc = config_gpios(1, dev->vcap_pdata);
+ if (rc < 0)
+ goto gpio_failed;
+ return 0;
+
+gpio_failed:
+ msm_bus_scale_unregister_client(dev->bus_client_handle);
+ dev->bus_client_handle = 0;
+bus_r_failed:
+ vcap_clk_powerdown(dev);
+clk_failed:
+ vcap_reg_powerdown(dev);
+reg_failed:
+ return rc;
+}
+
+int vcap_disable(struct vcap_dev *dev)
+{
+ config_gpios(0, dev->vcap_pdata);
+
+ msm_bus_scale_unregister_client(dev->bus_client_handle);
+ dev->bus_client_handle = 0;
+ vcap_clk_powerdown(dev);
+ vcap_reg_powerdown(dev);
+ return 0;
+}
+
enum vcap_op_mode determine_mode(struct vcap_client_data *cd)
{
if (cd->set_cap == 1 && cd->set_vp_o == 0 &&
@@ -512,8 +734,6 @@
vc_format = (struct v4l2_format_vc_ext *) &priv_fmt->u.timing;
c_data->vc_format = *vc_format;
- config_vc_format(c_data);
-
size = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -526,11 +746,9 @@
size *= (c_data->vc_format.vactive_end -
c_data->vc_format.vactive_start);
priv_fmt->u.timing.sizeimage = size;
- vcap_ctrl->vc_client = c_data;
c_data->set_cap = true;
break;
case VP_IN_TYPE:
- vcap_ctrl->vp_client = c_data;
c_data->vp_in_fmt.width = priv_fmt->u.pix.width;
c_data->vp_in_fmt.height = priv_fmt->u.pix.height;
c_data->vp_in_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
@@ -547,7 +765,6 @@
c_data->set_decode = true;
break;
case VP_OUT_TYPE:
- vcap_ctrl->vp_client = c_data;
c_data->vp_out_fmt.width = priv_fmt->u.pix.width;
c_data->vp_out_fmt.height = priv_fmt->u.pix.height;
c_data->vp_out_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
@@ -765,10 +982,33 @@
return 0;
}
+int request_bus_bw(struct vcap_dev *dev, unsigned long rate)
+{
+ struct msm_bus_paths *bus_vectors;
+ int idx, length;
+ bus_vectors = dev->vcap_pdata->bus_client_pdata->usecase;
+ length = dev->vcap_pdata->bus_client_pdata->num_usecases;
+ idx = 0;
+ do {
+ if (rate <= bus_vectors[idx].vectors[0].ab)
+ break;
+ idx++;
+ } while (idx < length);
+ if (idx == length) {
+ pr_err("VCAP: Defaulting to highest BW request\n");
+ idx--;
+ }
+ msm_bus_scale_client_update_request(dev->bus_client_handle, idx);
+ return 0;
+}
+
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
+ unsigned long flags;
int rc;
+ unsigned long rate;
dprintk(3, "In Stream ON\n");
if (determine_mode(c_data) != c_data->op_mode) {
@@ -778,25 +1018,97 @@
switch (c_data->op_mode) {
case VC_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vc_resource) {
+ pr_err("VCAP Err: %s: VC resource taken", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+
c_data->dev->vc_client = c_data;
+
+ if (!c_data->vc_format.clk_freq) {
+ rc = -EINVAL;
+ goto free_res;
+ }
+
+ rate = c_data->vc_format.clk_freq;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = (c_data->vc_format.hactive_end -
+ c_data->vc_format.hactive_start);
+
+ if (c_data->vc_format.color_space)
+ rate *= 3;
+ else
+ rate *= 2;
+
+ rate *= (c_data->vc_format.vactive_end -
+ c_data->vc_format.vactive_start);
+ rate *= c_data->vc_format.frame_rate;
+ if (rate == 0)
+ goto free_res;
+
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
config_vc_format(c_data);
- return vb2_streamon(&c_data->vc_vidq, i);
+ rc = vb2_streamon(&c_data->vc_vidq, i);
+ if (rc < 0)
+ goto free_res;
+ break;
case VP_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vp_resource) {
+ pr_err("VCAP Err: %s: VP resource taken", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vp_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ c_data->dev->vp_client = c_data;
+
+ rate = 160000000;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = c_data->vp_out_fmt.width *
+ c_data->vp_out_fmt.height * 240;
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
rc = streamon_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
- return rc;
+ goto free_res;
rc = streamon_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
- return rc;
-
- c_data->dev->vp_client = c_data;
+ goto free_res;
rc = config_vp_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = init_motion_buf(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
if (c_data->vid_vp_action.nr_enabled) {
rc = init_nr_buf(c_data);
if (rc < 0)
@@ -804,6 +1116,7 @@
}
c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->streaming = 1;
rc = vb2_streamon(&c_data->vp_in_vidq,
V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
@@ -814,39 +1127,85 @@
V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (rc < 0)
goto s_on_deinit_nr_buf;
- return rc;
+ break;
case VC_AND_VP_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vc_resource || dev->vp_resource) {
+ pr_err("VCAP Err: %s: VC/VP resource taken",
+ __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 1;
+ dev->vp_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ c_data->dev->vc_client = c_data;
+ c_data->dev->vp_client = c_data;
+
+ if (!c_data->vc_format.clk_freq) {
+ rc = -EINVAL;
+ goto free_res;
+ }
+
+ rate = c_data->vc_format.clk_freq;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = (c_data->vc_format.hactive_end -
+ c_data->vc_format.hactive_start);
+
+ if (c_data->vc_format.color_space)
+ rate *= 3;
+ else
+ rate *= 2;
+
+ rate *= (c_data->vc_format.vactive_end -
+ c_data->vc_format.vactive_start);
+ rate *= c_data->vc_format.frame_rate;
+ rate *= 2;
+ if (rate == 0)
+ goto free_res;
+
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
rc = streamon_validate_q(&c_data->vc_vidq);
if (rc < 0)
return rc;
rc = streamon_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
- return rc;
+ goto free_res;
rc = streamon_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
- return rc;
-
- c_data->dev->vc_client = c_data;
- c_data->dev->vp_client = c_data;
- c_data->dev->vc_to_vp_work.cd = c_data;
+ goto free_res;
rc = config_vc_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = config_vp_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = init_motion_buf(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
+
if (c_data->vid_vp_action.nr_enabled) {
rc = init_nr_buf(c_data);
if (rc < 0)
goto s_on_deinit_m_buf;
}
- c_data->streaming = 1;
+ c_data->dev->vc_to_vp_work.cd = c_data;
c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->streaming = 1;
/* These stream on calls should not fail */
rc = vb2_streamon(&c_data->vc_vidq,
@@ -863,7 +1222,7 @@
V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (rc < 0)
goto s_on_deinit_nr_buf;
- return rc;
+ break;
default:
pr_err("VCAP Error: %s: Operation Mode type", __func__);
return -ENOTRECOVERABLE;
@@ -875,6 +1234,21 @@
deinit_nr_buf(c_data);
s_on_deinit_m_buf:
deinit_motion_buf(c_data);
+free_res:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (c_data->op_mode == VC_VCAP_OP) {
+ dev->vc_resource = 0;
+ c_data->dev->vc_client = NULL;
+ } else if (c_data->op_mode == VP_VCAP_OP) {
+ dev->vp_resource = 0;
+ c_data->dev->vp_client = NULL;
+ } else if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
+ c_data->dev->vc_client = NULL;
+ c_data->dev->vp_client = NULL;
+ dev->vc_resource = 0;
+ dev->vp_resource = 0;
+ }
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
return rc;
}
@@ -895,21 +1269,50 @@
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
+ unsigned long flags;
int rc;
switch (c_data->op_mode) {
case VC_VCAP_OP:
+ if (c_data != dev->vc_client) {
+ pr_err("VCAP Err: %s: VC held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!dev->vc_resource) {
+ pr_err("VCAP Err: %s: VC res not acquired", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = vb2_streamoff(&c_data->vc_vidq, i);
if (rc >= 0)
atomic_set(&c_data->dev->vc_enabled, 0);
return rc;
case VP_VCAP_OP:
+ if (c_data != dev->vp_client) {
+ pr_err("VCAP Err: %s: VP held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!dev->vp_resource) {
+ pr_err("VCAP Err: %s: VP res not acquired", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vp_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = streamoff_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
return rc;
rc = streamoff_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
return rc;
+ c_data->streaming = 0;
/* These stream on calls should not fail */
rc = vb2_streamoff(&c_data->vp_in_vidq,
@@ -928,6 +1331,21 @@
atomic_set(&c_data->dev->vp_enabled, 0);
return rc;
case VC_AND_VP_VCAP_OP:
+ if (c_data != dev->vp_client || c_data != dev->vc_client) {
+ pr_err("VCAP Err: %s: VC/VP held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!(dev->vc_resource || dev->vp_resource)) {
+ pr_err("VCAP Err: %s: VC or VP res not acquired",
+ __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 0;
+ dev->vp_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = streamoff_validate_q(&c_data->vc_vidq);
if (rc < 0)
return rc;
@@ -1026,6 +1444,7 @@
struct vcap_dev *dev = video_drvdata(file);
struct vcap_client_data *c_data;
struct vb2_queue *q;
+ unsigned long flags;
int ret;
c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
if (!dev)
@@ -1081,9 +1500,26 @@
v4l2_fh_init(&c_data->vfh, dev->vfd);
v4l2_fh_add(&c_data->vfh);
+
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ atomic_inc(&dev->open_clients);
+ ret = atomic_read(&dev->open_clients);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ if (ret == 1) {
+ ret = vcap_enable(dev, dev->ddev, 54860000);
+ if (ret < 0) {
+ pr_err("Err: %s: Power on vcap failed", __func__);
+ goto vcap_power_failed;
+ }
+ }
+
file->private_data = &c_data->vfh;
return 0;
+vcap_power_failed:
+ v4l2_fh_del(&c_data->vfh);
+ v4l2_fh_exit(&c_data->vfh);
+ vb2_queue_release(&c_data->vp_out_vidq);
vp_out_q_failed:
vb2_queue_release(&c_data->vp_in_vidq);
vp_in_q_failed:
@@ -1095,9 +1531,20 @@
static int vcap_close(struct file *file)
{
+ struct vcap_dev *dev = video_drvdata(file);
struct vcap_client_data *c_data = to_client_data(file->private_data);
+ unsigned long flags;
+ int ret;
+
if (c_data == NULL)
return 0;
+
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ atomic_dec(&dev->open_clients);
+ ret = atomic_read(&dev->open_clients);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ if (ret == 0)
+ vcap_disable(dev);
v4l2_fh_del(&c_data->vfh);
v4l2_fh_exit(&c_data->vfh);
vb2_queue_release(&c_data->vp_out_vidq);
@@ -1210,220 +1657,6 @@
.release = video_device_release,
};
-int vcap_reg_powerup(struct vcap_dev *dev)
-{
- dev->fs_vcap = regulator_get(NULL, "fs_vcap");
- if (IS_ERR(dev->fs_vcap)) {
- pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
- PTR_ERR(dev->fs_vcap));
- dev->fs_vcap = NULL;
- return -EINVAL;
- } else if (regulator_enable(dev->fs_vcap)) {
- pr_err("%s: Regulator FS_VCAP enable failed\n", __func__);
- regulator_put(dev->fs_vcap);
- return -EINVAL;
- }
- return 0;
-}
-
-void vcap_reg_powerdown(struct vcap_dev *dev)
-{
- if (dev->fs_vcap == NULL)
- return;
- regulator_disable(dev->fs_vcap);
- regulator_put(dev->fs_vcap);
- dev->fs_vcap = NULL;
- return;
-}
-
-int config_gpios(int on, struct vcap_platform_data *pdata)
-{
- int i, ret;
- int num_gpios = pdata->num_gpios;
- unsigned *gpios = pdata->gpios;
-
- if (on) {
- for (i = 0; i < num_gpios; i++) {
- ret = gpio_request(gpios[i], "vcap:vc");
- if (ret) {
- pr_err("VCAP: failed at GPIO %d to request\n",
- gpios[i]);
- goto gpio_failed;
- }
- ret = gpio_direction_input(gpios[i]);
- if (ret) {
- pr_err("VCAP: failed at GPIO %d to set to input\n",
- gpios[i]);
- i++;
- goto gpio_failed;
- }
- }
- } else {
- for (i = 0; i < num_gpios; i++)
- gpio_free(gpios[i]);
- }
- dprintk(2, "GPIO config done\n");
- return 0;
-gpio_failed:
- for (i--; i >= 0; i--)
- gpio_free(gpios[i]);
- return -EINVAL;
-}
-
-int vcap_clk_powerup(struct vcap_dev *dev, struct device *ddev)
-{
- int ret = 0;
-
- dev->vcap_clk = clk_get(ddev, "core_clk");
- if (IS_ERR(dev->vcap_clk)) {
- dev->vcap_clk = NULL;
- pr_err("%s: Could not clk_get core_clk\n", __func__);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- return -EINVAL;
- }
-
- clk_prepare(dev->vcap_clk);
- ret = clk_enable(dev->vcap_clk);
- if (ret) {
- pr_err("%s: Failed core clk_enable %d\n", __func__, ret);
- goto fail_vcap_clk_unprep;
- }
-
- clk_set_rate(dev->vcap_clk, 160000000);
- if (ret) {
- pr_err("%s: Failed core set_rate %d\n", __func__, ret);
- goto fail_vcap_clk;
- }
-
- dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
- if (IS_ERR(dev->vcap_npl_clk)) {
- dev->vcap_npl_clk = NULL;
- pr_err("%s: Could not clk_get npl\n", __func__);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
- goto fail_vcap_clk;
- }
-
- clk_prepare(dev->vcap_npl_clk);
- ret = clk_enable(dev->vcap_npl_clk);
- if (ret) {
- pr_err("%s:Failed npl clk_enable %d\n", __func__, ret);
- goto fail_vcap_npl_clk_unprep;
- }
-
- dev->vcap_p_clk = clk_get(ddev, "iface_clk");
- if (IS_ERR(dev->vcap_p_clk)) {
- dev->vcap_p_clk = NULL;
- pr_err("%s: Could not clk_get pix(AHB)\n", __func__);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
- goto fail_vcap_npl_clk;
- }
-
- clk_prepare(dev->vcap_p_clk);
- ret = clk_enable(dev->vcap_p_clk);
- if (ret) {
- pr_err("%s: Failed pix(AHB) clk_enable %d\n", __func__, ret);
- goto fail_vcap_p_clk_unprep;
- }
- return 0;
-
-fail_vcap_p_clk_unprep:
- clk_unprepare(dev->vcap_p_clk);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
-
-fail_vcap_npl_clk:
- clk_disable(dev->vcap_npl_clk);
-fail_vcap_npl_clk_unprep:
- clk_unprepare(dev->vcap_npl_clk);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
-
-fail_vcap_clk:
- clk_disable(dev->vcap_clk);
-fail_vcap_clk_unprep:
- clk_unprepare(dev->vcap_clk);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- return -EINVAL;
-}
-
-void vcap_clk_powerdown(struct vcap_dev *dev)
-{
- if (dev->vcap_p_clk != NULL) {
- clk_disable(dev->vcap_p_clk);
- clk_unprepare(dev->vcap_p_clk);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
- }
-
- if (dev->vcap_npl_clk != NULL) {
- clk_disable(dev->vcap_npl_clk);
- clk_unprepare(dev->vcap_npl_clk);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
- }
-
- if (dev->vcap_clk != NULL) {
- clk_disable(dev->vcap_clk);
- clk_unprepare(dev->vcap_clk);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- }
-}
-
-int vcap_get_bus_client_handle(struct vcap_dev *dev)
-{
- struct msm_bus_scale_pdata *vcap_axi_client_pdata =
- dev->vcap_pdata->bus_client_pdata;
- dev->bus_client_handle =
- msm_bus_scale_register_client(vcap_axi_client_pdata);
-
- return 0;
-}
-
-int vcap_enable(struct vcap_dev *dev, struct device *ddev)
-{
- int rc;
-
- rc = vcap_reg_powerup(dev);
- if (rc < 0)
- goto reg_failed;
- rc = vcap_clk_powerup(dev, ddev);
- if (rc < 0)
- goto clk_failed;
- rc = vcap_get_bus_client_handle(dev);
- if (rc < 0)
- goto bus_r_failed;
- config_gpios(1, dev->vcap_pdata);
- if (rc < 0)
- goto gpio_failed;
- return 0;
-
-gpio_failed:
- msm_bus_scale_unregister_client(dev->bus_client_handle);
- dev->bus_client_handle = 0;
-bus_r_failed:
- vcap_clk_powerdown(dev);
-clk_failed:
- vcap_reg_powerdown(dev);
-reg_failed:
- return rc;
-}
-
-int vcap_disable(struct vcap_dev *dev)
-{
- config_gpios(0, dev->vcap_pdata);
-
- msm_bus_scale_unregister_client(dev->bus_client_handle);
- dev->bus_client_handle = 0;
- vcap_clk_powerdown(dev);
- vcap_reg_powerdown(dev);
- return 0;
-}
-
static irqreturn_t vcap_vp_handler(int irq_num, void *data)
{
return vp_handler(vcap_ctrl);
@@ -1513,10 +1746,10 @@
if (ret)
goto free_resource;
- ret = vcap_enable(dev, &pdev->dev);
+ ret = vcap_enable(dev, &pdev->dev, 54860000);
if (ret)
goto unreg_dev;
- msm_bus_scale_client_update_request(dev->bus_client_handle, 3);
+ msm_bus_scale_client_update_request(dev->bus_client_handle, 0);
ret = detect_vc(dev);
@@ -1552,6 +1785,10 @@
atomic_set(&dev->vc_enabled, 0);
atomic_set(&dev->vp_enabled, 0);
+ atomic_set(&dev->open_clients, 0);
+ dev->ddev = &pdev->dev;
+ spin_lock_init(&dev->dev_slock);
+ vcap_disable(dev);
dprintk(1, "Exit probe succesfully");
return 0;
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 75663ee..ad0718e 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -166,8 +166,11 @@
spin_lock(&dev->vc_client->cap_slock);
if (list_empty(&dev->vc_client->vid_vc_action.active)) {
/* Just leave we have no new queued buffers */
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
spin_unlock(&dev->vc_client->cap_slock);
+ writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_BUF_OVERWRITE_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
dprintk(1, "We have no more avilable buffers\n");
return IRQ_HANDLED;
}
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index d8daecd..1b503ba 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -283,7 +283,7 @@
}
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
- if (!irq & VP_PIC_DONE) {
+ if (!(irq & VP_PIC_DONE)) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
return IRQ_HANDLED;
@@ -553,7 +553,7 @@
chroma_fmt << 11 | 0x2 << 4, VCAP_VP_IN_CONFIG);
chroma_fmt = 0;
- if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+ if (c_data->vp_out_fmt.pixfmt == V4L2_PIX_FMT_NV16)
chroma_fmt = 1;
writel_relaxed((c_data->vp_in_fmt.width / 16) << 20 |
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index dfb62c4..92240bf1 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -51,7 +51,8 @@
enum hal_vcap_polar d_polar;
enum hal_vcap_color color_space;
- float clk_freq;
+ uint32_t clk_freq;
+ uint32_t frame_rate;
uint32_t vtotal;
uint32_t htotal;
uint32_t hactive_start;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index bdc3c61..045c107 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -148,6 +148,7 @@
struct clk *vcap_clk;
struct clk *vcap_p_clk;
struct clk *vcap_npl_clk;
+ struct device *ddev;
/*struct platform_device *pdev;*/
uint32_t bus_client_handle;
@@ -158,8 +159,10 @@
atomic_t vc_enabled;
atomic_t vp_enabled;
- atomic_t vc_resource;
- atomic_t vp_resource;
+ spinlock_t dev_slock;
+ atomic_t open_clients;
+ bool vc_resource;
+ bool vp_resource;
struct workqueue_struct *vcap_wq;
struct vp_work_t vp_work;