aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2010-07-26 11:13:34 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 15:43:40 -0400
commitb3b5020d8c12037f030242aab8e272148bf1f472 (patch)
treeef61f21075c46a5c13252adccc50c303ed9dfd94
parent077e2c10c9cb618d571bf16475db696610bdb24a (diff)
V4L/DVB: V4L2: sh_mobile_camera_ceu: add support for CSI2
Using CEU with CSI2 on SH-Mobile requires some special configuration of the former. We also have to switch from calling only one subdev .s_mbus_fmt and .try_mbus_fmt to calling all subdevices. Take care to increment CSI2 driver use count to prevent it from unloading, while in use. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c131
-rw-r--r--include/media/sh_mobile_ceu.h3
2 files changed, 119 insertions, 15 deletions
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 86869dbcbab0..2b24bd0de3ad 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -633,6 +633,12 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
633 cdwdr_width *= 2; 633 cdwdr_width *= 2;
634 } 634 }
635 635
636 /* CSI2 special configuration */
637 if (pcdev->pdata->csi2_dev) {
638 in_width = ((in_width - 2) * 2);
639 left_offset *= 2;
640 }
641
636 /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */ 642 /* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
637 camor = left_offset | (top_offset << 16); 643 camor = left_offset | (top_offset << 16);
638 644
@@ -767,6 +773,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
767 value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; 773 value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
768 value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; 774 value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
769 value |= pcdev->is_16bit ? 1 << 12 : 0; 775 value |= pcdev->is_16bit ? 1 << 12 : 0;
776
777 /* CSI2 mode */
778 if (pcdev->pdata->csi2_dev)
779 value |= 3 << 12;
780
770 ceu_write(pcdev, CAMCR, value); 781 ceu_write(pcdev, CAMCR, value);
771 782
772 ceu_write(pcdev, CAPCR, 0x00300000); 783 ceu_write(pcdev, CAPCR, 0x00300000);
@@ -883,6 +894,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
883{ 894{
884 struct v4l2_subdev *sd = soc_camera_to_subdev(icd); 895 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
885 struct device *dev = icd->dev.parent; 896 struct device *dev = icd->dev.parent;
897 struct soc_camera_host *ici = to_soc_camera_host(dev);
898 struct sh_mobile_ceu_dev *pcdev = ici->priv;
886 int ret, k, n; 899 int ret, k, n;
887 int formats = 0; 900 int formats = 0;
888 struct sh_mobile_ceu_cam *cam; 901 struct sh_mobile_ceu_cam *cam;
@@ -896,19 +909,19 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
896 909
897 fmt = soc_mbus_get_fmtdesc(code); 910 fmt = soc_mbus_get_fmtdesc(code);
898 if (!fmt) { 911 if (!fmt) {
899 dev_err(icd->dev.parent, 912 dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
900 "Invalid format code #%u: %d\n", idx, code);
901 return -EINVAL; 913 return -EINVAL;
902 } 914 }
903 915
904 ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); 916 if (!pcdev->pdata->csi2_dev) {
905 if (ret < 0) 917 ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
906 return 0; 918 if (ret < 0)
919 return 0;
920 }
907 921
908 if (!icd->host_priv) { 922 if (!icd->host_priv) {
909 struct v4l2_mbus_framefmt mf; 923 struct v4l2_mbus_framefmt mf;
910 struct v4l2_rect rect; 924 struct v4l2_rect rect;
911 struct device *dev = icd->dev.parent;
912 int shift = 0; 925 int shift = 0;
913 926
914 /* FIXME: subwindow is lost between close / open */ 927 /* FIXME: subwindow is lost between close / open */
@@ -927,7 +940,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
927 /* Try 2560x1920, 1280x960, 640x480, 320x240 */ 940 /* Try 2560x1920, 1280x960, 640x480, 320x240 */
928 mf.width = 2560 >> shift; 941 mf.width = 2560 >> shift;
929 mf.height = 1920 >> shift; 942 mf.height = 1920 >> shift;
930 ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); 943 ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
944 s_mbus_fmt, &mf);
931 if (ret < 0) 945 if (ret < 0)
932 return ret; 946 return ret;
933 shift++; 947 shift++;
@@ -1228,7 +1242,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
1228 struct v4l2_cropcap cap; 1242 struct v4l2_cropcap cap;
1229 int ret; 1243 int ret;
1230 1244
1231 ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); 1245 ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
1246 s_mbus_fmt, mf);
1232 if (ret < 0) 1247 if (ret < 0)
1233 return ret; 1248 return ret;
1234 1249
@@ -1257,7 +1272,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
1257 tmp_h = min(2 * tmp_h, max_height); 1272 tmp_h = min(2 * tmp_h, max_height);
1258 mf->width = tmp_w; 1273 mf->width = tmp_w;
1259 mf->height = tmp_h; 1274 mf->height = tmp_h;
1260 ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); 1275 ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
1276 s_mbus_fmt, mf);
1261 dev_geo(dev, "Camera scaled to %ux%u\n", 1277 dev_geo(dev, "Camera scaled to %ux%u\n",
1262 mf->width, mf->height); 1278 mf->width, mf->height);
1263 if (ret < 0) { 1279 if (ret < 0) {
@@ -1514,7 +1530,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
1514 struct device *dev = icd->dev.parent; 1530 struct device *dev = icd->dev.parent;
1515 __u32 pixfmt = pix->pixelformat; 1531 __u32 pixfmt = pix->pixelformat;
1516 const struct soc_camera_format_xlate *xlate; 1532 const struct soc_camera_format_xlate *xlate;
1517 unsigned int ceu_sub_width, ceu_sub_height; 1533 /* Keep Compiler Happy */
1534 unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
1518 u16 scale_v, scale_h; 1535 u16 scale_v, scale_h;
1519 int ret; 1536 int ret;
1520 bool image_mode; 1537 bool image_mode;
@@ -1569,8 +1586,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
1569 1586
1570 /* Done with the camera. Now see if we can improve the result */ 1587 /* Done with the camera. Now see if we can improve the result */
1571 1588
1572 dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n", 1589 dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
1573 ret, mf.width, mf.height, pix->width, pix->height); 1590 mf.width, mf.height, pix->width, pix->height);
1574 if (ret < 0) 1591 if (ret < 0)
1575 return ret; 1592 return ret;
1576 1593
@@ -1634,6 +1651,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
1634 int width, height; 1651 int width, height;
1635 int ret; 1652 int ret;
1636 1653
1654 dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
1655 pixfmt, pix->width, pix->height);
1656
1637 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); 1657 xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
1638 if (!xlate) { 1658 if (!xlate) {
1639 dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); 1659 dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
@@ -1660,7 +1680,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
1660 mf.code = xlate->code; 1680 mf.code = xlate->code;
1661 mf.colorspace = pix->colorspace; 1681 mf.colorspace = pix->colorspace;
1662 1682
1663 ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); 1683 ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
1664 if (ret < 0) 1684 if (ret < 0)
1665 return ret; 1685 return ret;
1666 1686
@@ -1684,7 +1704,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
1684 */ 1704 */
1685 mf.width = 2560; 1705 mf.width = 2560;
1686 mf.height = 1920; 1706 mf.height = 1920;
1687 ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); 1707 ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
1708 try_mbus_fmt, &mf);
1688 if (ret < 0) { 1709 if (ret < 0) {
1689 /* Shouldn't actually happen... */ 1710 /* Shouldn't actually happen... */
1690 dev_err(icd->dev.parent, 1711 dev_err(icd->dev.parent,
@@ -1699,6 +1720,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
1699 pix->height = height; 1720 pix->height = height;
1700 } 1721 }
1701 1722
1723 dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
1724 __func__, ret, pix->pixelformat, pix->width, pix->height);
1725
1702 return ret; 1726 return ret;
1703} 1727}
1704 1728
@@ -1853,6 +1877,30 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
1853 .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls), 1877 .num_controls = ARRAY_SIZE(sh_mobile_ceu_controls),
1854}; 1878};
1855 1879
1880struct bus_wait {
1881 struct notifier_block notifier;
1882 struct completion completion;
1883 struct device *dev;
1884};
1885
1886static int bus_notify(struct notifier_block *nb,
1887 unsigned long action, void *data)
1888{
1889 struct device *dev = data;
1890 struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
1891
1892 if (wait->dev != dev)
1893 return NOTIFY_DONE;
1894
1895 switch (action) {
1896 case BUS_NOTIFY_UNBOUND_DRIVER:
1897 /* Protect from module unloading */
1898 wait_for_completion(&wait->completion);
1899 return NOTIFY_OK;
1900 }
1901 return NOTIFY_DONE;
1902}
1903
1856static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) 1904static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
1857{ 1905{
1858 struct sh_mobile_ceu_dev *pcdev; 1906 struct sh_mobile_ceu_dev *pcdev;
@@ -1860,6 +1908,11 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
1860 void __iomem *base; 1908 void __iomem *base;
1861 unsigned int irq; 1909 unsigned int irq;
1862 int err = 0; 1910 int err = 0;
1911 struct bus_wait wait = {
1912 .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
1913 .notifier.notifier_call = bus_notify,
1914 };
1915 struct device *csi2;
1863 1916
1864 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1917 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1865 irq = platform_get_irq(pdev, 0); 1918 irq = platform_get_irq(pdev, 0);
@@ -1931,12 +1984,54 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
1931 pcdev->ici.drv_name = dev_name(&pdev->dev); 1984 pcdev->ici.drv_name = dev_name(&pdev->dev);
1932 pcdev->ici.ops = &sh_mobile_ceu_host_ops; 1985 pcdev->ici.ops = &sh_mobile_ceu_host_ops;
1933 1986
1987 /* CSI2 interfacing */
1988 csi2 = pcdev->pdata->csi2_dev;
1989 if (csi2) {
1990 wait.dev = csi2;
1991
1992 err = bus_register_notifier(&platform_bus_type, &wait.notifier);
1993 if (err < 0)
1994 goto exit_free_clk;
1995
1996 /*
1997 * From this point the driver module will not unload, until
1998 * we complete the completion.
1999 */
2000
2001 if (!csi2->driver || !csi2->driver->owner) {
2002 complete(&wait.completion);
2003 /* Either too late, or probing failed */
2004 bus_unregister_notifier(&platform_bus_type, &wait.notifier);
2005 err = -ENXIO;
2006 goto exit_free_clk;
2007 }
2008
2009 /*
2010 * The module is still loaded, in the worst case it is hanging
2011 * in device release on our completion. So, _now_ dereferencing
2012 * the "owner" is safe!
2013 */
2014
2015 err = try_module_get(csi2->driver->owner);
2016
2017 /* Let notifier complete, if it has been locked */
2018 complete(&wait.completion);
2019 bus_unregister_notifier(&platform_bus_type, &wait.notifier);
2020 if (!err) {
2021 err = -ENODEV;
2022 goto exit_free_clk;
2023 }
2024 }
2025
1934 err = soc_camera_host_register(&pcdev->ici); 2026 err = soc_camera_host_register(&pcdev->ici);
1935 if (err) 2027 if (err)
1936 goto exit_free_clk; 2028 goto exit_module_put;
1937 2029
1938 return 0; 2030 return 0;
1939 2031
2032exit_module_put:
2033 if (csi2 && csi2->driver)
2034 module_put(csi2->driver->owner);
1940exit_free_clk: 2035exit_free_clk:
1941 pm_runtime_disable(&pdev->dev); 2036 pm_runtime_disable(&pdev->dev);
1942 free_irq(pcdev->irq, pcdev); 2037 free_irq(pcdev->irq, pcdev);
@@ -1956,6 +2051,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
1956 struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); 2051 struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
1957 struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, 2052 struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
1958 struct sh_mobile_ceu_dev, ici); 2053 struct sh_mobile_ceu_dev, ici);
2054 struct device *csi2 = pcdev->pdata->csi2_dev;
1959 2055
1960 soc_camera_host_unregister(soc_host); 2056 soc_camera_host_unregister(soc_host);
1961 pm_runtime_disable(&pdev->dev); 2057 pm_runtime_disable(&pdev->dev);
@@ -1963,7 +2059,10 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
1963 if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) 2059 if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
1964 dma_release_declared_memory(&pdev->dev); 2060 dma_release_declared_memory(&pdev->dev);
1965 iounmap(pcdev->base); 2061 iounmap(pcdev->base);
2062 if (csi2 && csi2->driver)
2063 module_put(csi2->driver->owner);
1966 kfree(pcdev); 2064 kfree(pcdev);
2065
1967 return 0; 2066 return 0;
1968} 2067}
1969 2068
@@ -1995,6 +2094,8 @@ static struct platform_driver sh_mobile_ceu_driver = {
1995 2094
1996static int __init sh_mobile_ceu_init(void) 2095static int __init sh_mobile_ceu_init(void)
1997{ 2096{
2097 /* Whatever return code */
2098 request_module("sh_mobile_csi2");
1998 return platform_driver_register(&sh_mobile_ceu_driver); 2099 return platform_driver_register(&sh_mobile_ceu_driver);
1999} 2100}
2000 2101
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index b67747836878..80346a6d28a9 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -6,8 +6,11 @@
6#define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */ 6#define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */
7#define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */ 7#define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */
8 8
9struct device;
10
9struct sh_mobile_ceu_info { 11struct sh_mobile_ceu_info {
10 unsigned long flags; 12 unsigned long flags;
13 struct device *csi2_dev;
11}; 14};
12 15
13#endif /* __ASM_SH_MOBILE_CEU_H__ */ 16#endif /* __ASM_SH_MOBILE_CEU_H__ */