V4L/DVB (10072): soc-camera: Add signal inversion flags to be used by camera drivers
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Tue, 23 Dec 2008 08:54:45 +0000 (05:54 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:40:17 +0000 (09:40 -0200)
As reported by Antonio Ospite <ospite@studenti.unina.it> two platforms with a
mt9m111 camera require opposite pixel clock polarity, which means one of them
inverts it. This patch adds support for inversion flags and switches all
available camera drivers to using them.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9v022.c
drivers/media/video/ov772x.c
drivers/media/video/soc_camera.c
include/media/soc_camera.h

index a7f0e6971fe1137efe3a80ea5e594d6f7804f874..b58f0f85e30fb21508426e56e7fee6a8317afa75 100644 (file)
@@ -272,17 +272,16 @@ static int mt9m001_set_bus_param(struct soc_camera_device *icd,
 static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       unsigned int width_flag = SOCAM_DATAWIDTH_10;
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       /* MT9M001 has all capture_format parameters fixed */
+       unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
+               SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+               SOCAM_MASTER;
 
        if (bus_switch_possible(mt9m001))
-               width_flag |= SOCAM_DATAWIDTH_8;
+               flags |= SOCAM_DATAWIDTH_8;
 
-       /* MT9M001 has all capture_format parameters fixed */
-       return SOCAM_PCLK_SAMPLE_RISING |
-               SOCAM_HSYNC_ACTIVE_HIGH |
-               SOCAM_VSYNC_ACTIVE_HIGH |
-               SOCAM_MASTER |
-               width_flag;
+       return soc_camera_apply_sensor_flags(icl, flags);
 }
 
 static int mt9m001_set_fmt(struct soc_camera_device *icd,
index b4a238f49600aa296a0b81089b13fb5f9fe83eff..b0e6046ea9679bd74fab89a8315f4c4cbc6c824a 100644 (file)
@@ -415,9 +415,13 @@ static int mt9m111_stop_capture(struct soc_camera_device *icd)
 
 static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
 {
-       return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
+       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
                SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
                SOCAM_DATAWIDTH_8;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
 }
 
 static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f)
index 82e1a3381a7ac2cb53550ef0ad181e888db312f5..3b3a6a027b1db563639726d910ea1f0fc0d1f22c 100644 (file)
@@ -273,6 +273,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
        unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
        int ret;
        u16 pixclk = 0;
@@ -296,6 +297,8 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
        }
 
+       flags = soc_camera_apply_sensor_flags(icl, flags);
+
        if (flags & SOCAM_PCLK_SAMPLE_RISING)
                pixclk |= 0x10;
 
index 99dd943aacf33452c25b6369013ed0c662d6e3e0..110cb9be09d6b3da92d7bd3310970fe00f20fece 100644 (file)
@@ -716,12 +716,12 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd,
 static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
 {
        struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
-
-       return  SOCAM_PCLK_SAMPLE_RISING |
-               SOCAM_HSYNC_ACTIVE_HIGH  |
-               SOCAM_VSYNC_ACTIVE_HIGH  |
-               SOCAM_MASTER             |
+       struct soc_camera_link *icl = priv->client->dev.platform_data;
+       unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+               SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
                priv->info->buswidth;
+
+       return soc_camera_apply_sensor_flags(icl, flags);
 }
 
 static int ov772x_get_chip_id(struct soc_camera_device *icd,
index 5e48c2cc1a44513ab8eb2a78fbd16d7ac01f240c..176017501055cdc1500063bbb21812ac340cc6b0 100644 (file)
@@ -59,6 +59,40 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
 }
 EXPORT_SYMBOL(soc_camera_xlate_by_fourcc);
 
+/**
+ * soc_camera_apply_sensor_flags() - apply platform SOCAM_SENSOR_INVERT_* flags
+ * @icl:       camera platform parameters
+ * @flags:     flags to be inverted according to platform configuration
+ * @return:    resulting flags
+ */
+unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+                                           unsigned long flags)
+{
+       unsigned long f;
+
+       /* If only one of the two polarities is supported, switch to the opposite */
+       if (icl->flags & SOCAM_SENSOR_INVERT_HSYNC) {
+               f = flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+               if (f == SOCAM_HSYNC_ACTIVE_HIGH || f == SOCAM_HSYNC_ACTIVE_LOW)
+                       flags ^= SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW;
+       }
+
+       if (icl->flags & SOCAM_SENSOR_INVERT_VSYNC) {
+               f = flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+               if (f == SOCAM_VSYNC_ACTIVE_HIGH || f == SOCAM_VSYNC_ACTIVE_LOW)
+                       flags ^= SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW;
+       }
+
+       if (icl->flags & SOCAM_SENSOR_INVERT_PCLK) {
+               f = flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+               if (f == SOCAM_PCLK_SAMPLE_RISING || f == SOCAM_PCLK_SAMPLE_FALLING)
+                       flags ^= SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING;
+       }
+
+       return flags;
+}
+EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
+
 static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
                                      struct v4l2_format *f)
 {
index da57ffdaec4d8832db447d7786f88dcb142961f9..e6ed0d94ac1b3d98502da7580e176e0dd22c6202 100644 (file)
@@ -81,11 +81,19 @@ struct soc_camera_host_ops {
        unsigned int (*poll)(struct file *, poll_table *);
 };
 
+#define SOCAM_SENSOR_INVERT_PCLK       (1 << 0)
+#define SOCAM_SENSOR_INVERT_MCLK       (1 << 1)
+#define SOCAM_SENSOR_INVERT_HSYNC      (1 << 2)
+#define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
+#define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
+
 struct soc_camera_link {
        /* Camera bus id, used to match a camera and a bus */
        int bus_id;
        /* GPIO number to switch between 8 and 10 bit modes */
        unsigned int gpio;
+       /* Per camera SOCAM_SENSOR_* bus flags */
+       unsigned long flags;
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -206,4 +214,7 @@ static inline unsigned long soc_camera_bus_param_compatible(
        return (!hsync || !vsync || !pclk) ? 0 : common_flags;
 }
 
+extern unsigned long soc_camera_apply_sensor_flags(struct soc_camera_link *icl,
+                                                  unsigned long flags);
+
 #endif