Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 124547
b: refs/heads/master
c: cf34cba
h: refs/heads/master
i:
  124545: c23de9a
  124543: 8c744bc
v: v3
  • Loading branch information
Guennadi Liakhovetski authored and Mauro Carvalho Chehab committed Dec 30, 2008
1 parent 3c864cb commit d1c9c3b
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a9bef518cd78d569a3ff0b1ac2afa5e2d8b3573a
refs/heads/master: cf34cba78d0e0a7244bd7f11addb4d971293fb30
90 changes: 69 additions & 21 deletions trunk/drivers/media/video/pxa_camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,9 @@ struct pxa_camera_dev {
struct pxacamera_platform_data *pdata;
struct resource *res;
unsigned long platform_flags;
unsigned long platform_mclk_10khz;
unsigned long ciclk;
unsigned long mclk;
u32 mclk_divisor;

struct list_head capture;

Expand Down Expand Up @@ -707,24 +709,43 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
sizeof(struct pxa_buffer), icd);
}

static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
{
unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
unsigned long div;
unsigned long mclk = pcdev->mclk;
u32 div;
unsigned long lcdclk;

lcdclk = clk_get_rate(pcdev->clk) / 10000;
lcdclk = clk_get_rate(pcdev->clk);
pcdev->ciclk = lcdclk;

/* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
* they get a nice Oops */
div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
/* mclk <= ciclk / 4 (27.4.2) */
if (mclk > lcdclk / 4) {
mclk = lcdclk / 4;
dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
}

/* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;

/* If we're not supplying MCLK, leave it at 0 */
if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
pcdev->mclk = lcdclk / (2 * (div + 1));

dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
"divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
"divisor %u\n", lcdclk, mclk, div);

return div;
}

static void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev,
unsigned long pclk)
{
/* We want a timeout > 1 pixel time, not ">=" */
u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1;

__raw_writel(ciclk_per_pixel, pcdev->base + CITOR);
}

static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
{
struct pxacamera_platform_data *pdata = pcdev->pdata;
Expand Down Expand Up @@ -752,8 +773,14 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
if (pcdev->platform_flags & PXA_CAMERA_VSP)
cicr4 |= CICR4_VSP;

cicr4 |= mclk_get_divisor(pcdev);
__raw_writel(cicr4, pcdev->base + CICR4);
__raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4);

if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
/* Initialise the timeout under the assumption pclk = mclk */
recalculate_fifo_timeout(pcdev, pcdev->mclk);
else
/* "Safe default" - 13MHz */
recalculate_fifo_timeout(pcdev, 13000000);

clk_enable(pcdev->clk);
}
Expand Down Expand Up @@ -1000,7 +1027,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
cicr2 = 0;
cicr3 = CICR3_LPF_VAL(icd->height - 1) |
CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
cicr4 |= mclk_get_divisor(pcdev);
cicr4 |= pcdev->mclk_divisor;

__raw_writel(cicr1, pcdev->base + CICR1);
__raw_writel(cicr2, pcdev->base + CICR2);
Expand All @@ -1019,8 +1046,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
static int pxa_camera_try_bus_param(struct soc_camera_device *icd,
unsigned char buswidth)
{
struct soc_camera_host *ici =
to_soc_camera_host(icd->dev.parent);
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags;
int ret = test_platform_param(pcdev, buswidth, &bus_flags);
Expand Down Expand Up @@ -1136,8 +1162,13 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
const struct soc_camera_format_xlate *xlate;
struct soc_camera_sense sense = {
.master_clock = pcdev->mclk,
.pixel_clock_max = pcdev->ciclk / 4,
};
int ret, buswidth;

xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
Expand All @@ -1150,6 +1181,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
host_fmt = xlate->host_fmt;
cam_fmt = xlate->cam_fmt;

/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
icd->sense = &sense;

switch (pixfmt) {
case 0: /* Only geometry change */
ret = icd->ops->set_fmt(icd, pixfmt, rect);
Expand All @@ -1158,9 +1193,20 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
ret = icd->ops->set_fmt(icd, cam_fmt->fourcc, rect);
}

if (ret < 0)
icd->sense = NULL;

if (ret < 0) {
dev_warn(&ici->dev, "Failed to configure for format %x\n",
pixfmt);
} else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
if (sense.pixel_clock > sense.pixel_clock_max) {
dev_err(&ici->dev,
"pixel clock %lu set by the camera too high!",
sense.pixel_clock);
return -EIO;
}
recalculate_fifo_timeout(pcdev, sense.pixel_clock);
}

if (pixfmt && !ret) {
icd->buswidth = buswidth;
Expand Down Expand Up @@ -1369,14 +1415,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
"data widths, using default 10 bit\n");
pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
}
pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
if (!pcdev->platform_mclk_10khz) {
pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
if (!pcdev->mclk) {
dev_warn(&pdev->dev,
"mclk_10khz == 0! Please, fix your platform data. "
"mclk == 0! Please, fix your platform data. "
"Using default 20MHz\n");
pcdev->platform_mclk_10khz = 2000;
pcdev->mclk = 20000000;
}

pcdev->dev = &pdev->dev;
pcdev->mclk_divisor = mclk_get_divisor(pcdev);

INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);

Expand All @@ -1396,7 +1445,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
}
pcdev->irq = irq;
pcdev->base = base;
pcdev->dev = &pdev->dev;

/* request dma */
err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
Expand Down

0 comments on commit d1c9c3b

Please sign in to comment.