--- zzzz-none-000/linux-3.10.107/drivers/media/platform/soc_camera/pxa_camera.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/platform/soc_camera/pxa_camera.c 2021-02-04 17:41:59.000000000 +0000 @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -186,7 +187,7 @@ struct pxa_buffer { /* common v4l buffer stuff -- must be first */ struct videobuf_buffer vb; - enum v4l2_mbus_pixelcode code; + u32 code; /* our descriptor lists for Y, U and V channels */ struct pxa_cam_dma dmas[3]; int inwork; @@ -200,7 +201,6 @@ * interface. If anyone ever builds hardware to enable more than * one camera, they will have to modify this driver too */ - struct soc_camera_device *icd; struct clk *clk; unsigned int irq; @@ -956,40 +956,39 @@ return IRQ_HANDLED; } +static int pxa_camera_add_device(struct soc_camera_device *icd) +{ + dev_info(icd->parent, "PXA Camera driver attached to camera %d\n", + icd->devnum); + + return 0; +} + +static void pxa_camera_remove_device(struct soc_camera_device *icd) +{ + dev_info(icd->parent, "PXA Camera driver detached from camera %d\n", + icd->devnum); +} + /* * The following two functions absolutely depend on the fact, that * there can be only one camera on PXA quick capture interface * Called with .host_lock held */ -static int pxa_camera_add_device(struct soc_camera_device *icd) +static int pxa_camera_clock_start(struct soc_camera_host *ici) { - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct pxa_camera_dev *pcdev = ici->priv; - if (pcdev->icd) - return -EBUSY; - pxa_camera_activate(pcdev); - pcdev->icd = icd; - - dev_info(icd->parent, "PXA Camera driver attached to camera %d\n", - icd->devnum); - return 0; } /* Called with .host_lock held */ -static void pxa_camera_remove_device(struct soc_camera_device *icd) +static void pxa_camera_clock_stop(struct soc_camera_host *ici) { - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct pxa_camera_dev *pcdev = ici->priv; - BUG_ON(icd != pcdev->icd); - - dev_info(icd->parent, "PXA Camera driver detached from camera %d\n", - icd->devnum); - /* disable capture, disable interrupts */ __raw_writel(0x3ff, pcdev->base + CICR0); @@ -999,8 +998,6 @@ DCSR(pcdev->dma_chans[2]) = 0; pxa_camera_deactivate(pcdev); - - pcdev->icd = NULL; } static int test_platform_param(struct pxa_camera_dev *pcdev, @@ -1256,17 +1253,20 @@ struct device *dev = icd->parent; int formats = 0, ret; struct pxa_cam *cam; - enum v4l2_mbus_pixelcode code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); return 0; } @@ -1285,21 +1285,21 @@ cam = icd->host_priv; } - switch (code) { - case V4L2_MBUS_FMT_UYVY8_2X8: + switch (code.code) { + case MEDIA_BUS_FMT_UYVY8_2X8: formats++; if (xlate) { xlate->host_fmt = &pxa_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", - pxa_camera_formats[0].name, code); + pxa_camera_formats[0].name, code.code); } - case V4L2_MBUS_FMT_VYUY8_2X8: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_YVYU8_2X8: - case V4L2_MBUS_FMT_RGB565_2X8_LE: - case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: if (xlate) dev_dbg(dev, "Providing format %s packed\n", fmt->name); @@ -1317,7 +1317,7 @@ formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } @@ -1349,7 +1349,10 @@ .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct pxa_cam *cam = icd->host_priv; u32 fourcc = icd->current_fmt->host_fmt->fourcc; int ret; @@ -1368,23 +1371,23 @@ return ret; } - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { /* * Camera cropping produced a frame beyond our capabilities. * FIXME: just extract a subframe, that we can process. */ - v4l_bound_align_image(&mf.width, 48, 2048, 1, - &mf.height, 32, 2048, 0, + v4l_bound_align_image(&mf->width, 48, 2048, 1, + &mf->height, 32, 2048, 0, fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(icd->parent, "Inconsistent state. Use S_FMT to repair\n"); return -EINVAL; @@ -1401,8 +1404,8 @@ recalculate_fifo_timeout(pcdev, sense.pixel_clock); } - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; pxa_camera_setup_cicr(icd, cam->flags, fourcc); @@ -1422,7 +1425,10 @@ .pixel_clock_max = pcdev->ciclk / 4, }; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1436,15 +1442,15 @@ /* The caller holds a mutex. */ icd->sense = &sense; - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; icd->sense = NULL; @@ -1452,10 +1458,10 @@ if (ret < 0) { dev_warn(dev, "Failed to configure for format %x\n", pix->pixelformat); - } else if (pxa_camera_check_frame(mf.width, mf.height)) { + } else if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(dev, "Camera driver produced an unsupported frame %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); ret = -EINVAL; } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { @@ -1470,10 +1476,10 @@ if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; return ret; @@ -1485,7 +1491,11 @@ struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int ret; @@ -1506,22 +1516,22 @@ pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; + mf->width = pix->width; + mf->height = pix->height; /* Only progressive video supported so far */ - mf.field = V4L2_FIELD_NONE; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: case V4L2_FIELD_NONE: pix->field = V4L2_FIELD_NONE; @@ -1529,7 +1539,7 @@ default: /* TODO: support interlaced at least in pass-through mode */ dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); return -EINVAL; } @@ -1579,7 +1589,8 @@ { /* cap->name is set by the firendly caller:-> */ strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1596,8 +1607,8 @@ pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); - if (pcdev->icd) { - struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd); + if (pcdev->soc_host.icd) { + struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); ret = v4l2_subdev_call(sd, core, s_power, 0); if (ret == -ENOIOCTLCMD) ret = 0; @@ -1622,8 +1633,8 @@ __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); - if (pcdev->icd) { - struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->icd); + if (pcdev->soc_host.icd) { + struct v4l2_subdev *sd = soc_camera_to_subdev(pcdev->soc_host.icd); ret = v4l2_subdev_call(sd, core, s_power, 1); if (ret == -ENOIOCTLCMD) ret = 0; @@ -1640,6 +1651,8 @@ .owner = THIS_MODULE, .add = pxa_camera_add_device, .remove = pxa_camera_remove_device, + .clock_start = pxa_camera_clock_start, + .clock_stop = pxa_camera_clock_stop, .set_crop = pxa_camera_set_crop, .get_formats = pxa_camera_get_formats, .put_formats = pxa_camera_put_formats, @@ -1652,6 +1665,68 @@ .set_bus_param = pxa_camera_set_bus_param, }; +static int pxa_camera_pdata_from_dt(struct device *dev, + struct pxa_camera_dev *pcdev) +{ + u32 mclk_rate; + struct device_node *np = dev->of_node; + struct v4l2_of_endpoint ep; + int err = of_property_read_u32(np, "clock-frequency", + &mclk_rate); + if (!err) { + pcdev->platform_flags |= PXA_CAMERA_MCLK_EN; + pcdev->mclk = mclk_rate; + } + + np = of_graph_get_next_endpoint(np, NULL); + if (!np) { + dev_err(dev, "could not find endpoint\n"); + return -EINVAL; + } + + err = v4l2_of_parse_endpoint(np, &ep); + if (err) { + dev_err(dev, "could not parse endpoint\n"); + goto out; + } + + switch (ep.bus.parallel.bus_width) { + case 4: + pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_4; + break; + case 5: + pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_5; + break; + case 8: + pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_8; + break; + case 9: + pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_9; + break; + case 10: + pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; + break; + default: + break; + } + + if (ep.bus.parallel.flags & V4L2_MBUS_MASTER) + pcdev->platform_flags |= PXA_CAMERA_MASTER; + if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + pcdev->platform_flags |= PXA_CAMERA_HSP; + if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + pcdev->platform_flags |= PXA_CAMERA_VSP; + if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + pcdev->platform_flags |= PXA_CAMERA_PCLK_EN | PXA_CAMERA_PCP; + if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; + +out: + of_node_put(np); + + return err; +} + static int pxa_camera_probe(struct platform_device *pdev) { struct pxa_camera_dev *pcdev; @@ -1678,7 +1753,15 @@ pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; - pcdev->platform_flags = pcdev->pdata->flags; + if (&pdev->dev.of_node && !pcdev->pdata) { + err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev); + } else { + pcdev->platform_flags = pcdev->pdata->flags; + pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; + } + if (err < 0) + return err; + if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { /* @@ -1695,7 +1778,6 @@ pcdev->width_flags |= 1 << 8; if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) pcdev->width_flags |= 1 << 9; - pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; if (!pcdev->mclk) { dev_warn(&pdev->dev, "mclk == 0! Please, fix your platform data. " @@ -1801,10 +1883,17 @@ .resume = pxa_camera_resume, }; +static const struct of_device_id pxa_camera_of_match[] = { + { .compatible = "marvell,pxa270-qci", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pxa_camera_of_match); + static struct platform_driver pxa_camera_driver = { .driver = { .name = PXA_CAM_DRV_NAME, .pm = &pxa_camera_pm, + .of_match_table = of_match_ptr(pxa_camera_of_match), }, .probe = pxa_camera_probe, .remove = pxa_camera_remove,