summaryrefslogtreecommitdiff
path: root/drivers/media/platform/qcom/camss/camss-csid.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/qcom/camss/camss-csid.c')
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c91
1 files changed, 67 insertions, 24 deletions
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index a1637b78568b..f993f349b66b 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -25,6 +25,10 @@
#include "camss-csid-gen1.h"
#include "camss.h"
+/* offset of CSID registers in VFE region for VFE 480 */
+#define VFE_480_CSID_OFFSET 0x1200
+#define VFE_480_LITE_CSID_OFFSET 0x200
+
#define MSM_CSID_NAME "msm_csid"
const char * const csid_testgen_modes[] = {
@@ -152,15 +156,25 @@ static int csid_set_clock_rates(struct csid_device *csid)
static int csid_set_power(struct v4l2_subdev *sd, int on)
{
struct csid_device *csid = v4l2_get_subdevdata(sd);
- struct device *dev = csid->camss->dev;
- int ret;
+ struct camss *camss = csid->camss;
+ struct device *dev = camss->dev;
+ struct vfe_device *vfe = &camss->vfe[csid->id];
+ u32 version = camss->version;
+ int ret = 0;
if (on) {
+ if (version == CAMSS_8250 || version == CAMSS_845) {
+ ret = vfe_get(vfe);
+ if (ret < 0)
+ return ret;
+ }
+
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
- ret = regulator_enable(csid->vdda);
+ ret = regulator_bulk_enable(csid->num_supplies,
+ csid->supplies);
if (ret < 0) {
pm_runtime_put_sync(dev);
return ret;
@@ -168,14 +182,16 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
ret = csid_set_clock_rates(csid);
if (ret < 0) {
- regulator_disable(csid->vdda);
+ regulator_bulk_disable(csid->num_supplies,
+ csid->supplies);
pm_runtime_put_sync(dev);
return ret;
}
ret = camss_enable_clocks(csid->nclocks, csid->clock, dev);
if (ret < 0) {
- regulator_disable(csid->vdda);
+ regulator_bulk_disable(csid->num_supplies,
+ csid->supplies);
pm_runtime_put_sync(dev);
return ret;
}
@@ -186,7 +202,8 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
if (ret < 0) {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
- regulator_disable(csid->vdda);
+ regulator_bulk_disable(csid->num_supplies,
+ csid->supplies);
pm_runtime_put_sync(dev);
return ret;
}
@@ -195,8 +212,11 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
} else {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
- ret = regulator_disable(csid->vdda);
+ regulator_bulk_disable(csid->num_supplies,
+ csid->supplies);
pm_runtime_put_sync(dev);
+ if (version == CAMSS_8250 || version == CAMSS_845)
+ vfe_put(vfe);
}
return ret;
@@ -544,7 +564,6 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
{
struct device *dev = camss->dev;
struct platform_device *pdev = to_platform_device(dev);
- struct resource *r;
int i, j;
int ret;
@@ -556,8 +575,9 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
} else if (camss->version == CAMSS_8x96 ||
camss->version == CAMSS_660) {
csid->ops = &csid_ops_4_7;
- } else if (camss->version == CAMSS_845) {
- csid->ops = &csid_ops_170;
+ } else if (camss->version == CAMSS_845 ||
+ camss->version == CAMSS_8250) {
+ csid->ops = &csid_ops_gen2;
} else {
return -EINVAL;
}
@@ -565,20 +585,28 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
/* Memory */
- csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
- if (IS_ERR(csid->base))
- return PTR_ERR(csid->base);
+ if (camss->version == CAMSS_8250) {
+ /* for titan 480, CSID registers are inside the VFE region,
+ * between the VFE "top" and "bus" registers. this requires
+ * VFE to be initialized before CSID
+ */
+ if (id >= 2) /* VFE/CSID lite */
+ csid->base = camss->vfe[id].base + VFE_480_LITE_CSID_OFFSET;
+ else
+ csid->base = camss->vfe[id].base + VFE_480_CSID_OFFSET;
+ } else {
+ csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
+ if (IS_ERR(csid->base))
+ return PTR_ERR(csid->base);
+ }
/* Interrupt */
- r = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- res->interrupt[0]);
- if (!r) {
- dev_err(dev, "missing IRQ\n");
- return -EINVAL;
- }
+ ret = platform_get_irq_byname(pdev, res->interrupt[0]);
+ if (ret < 0)
+ return ret;
- csid->irq = r->start;
+ csid->irq = ret;
snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
dev_name(dev), MSM_CSID_NAME, csid->id);
ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
@@ -630,13 +658,28 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
}
/* Regulator */
+ for (i = 0; i < ARRAY_SIZE(res->regulators); i++) {
+ if (res->regulators[i])
+ csid->num_supplies++;
+ }
- csid->vdda = devm_regulator_get(dev, res->regulator[0]);
- if (IS_ERR(csid->vdda)) {
- dev_err(dev, "could not get regulator\n");
- return PTR_ERR(csid->vdda);
+ if (csid->num_supplies) {
+ csid->supplies = devm_kmalloc_array(camss->dev,
+ csid->num_supplies,
+ sizeof(csid->supplies),
+ GFP_KERNEL);
+ if (!csid->supplies)
+ return -ENOMEM;
}
+ for (i = 0; i < csid->num_supplies; i++)
+ csid->supplies[i].supply = res->regulators[i];
+
+ ret = devm_regulator_bulk_get(camss->dev, csid->num_supplies,
+ csid->supplies);
+ if (ret)
+ return ret;
+
init_completion(&csid->reset_complete);
return 0;