#define DHP    0xffde  /* hierarchical progression */
 #define EXP    0xffdf  /* expand reference */
 #define APP0   0xffe0  /* application data */
+#define APP14  0xffee  /* application data for colour encoding */
 #define APP15  0xffef
 #define JPG0   0xfff0  /* extensions */
 #define JPG13  0xfffd
        return jpeg_skip(stream, len - 2);
 }
 
+/* Rec. ITU-T T.872 (06/2012) 6.5.3 */
+static int jpeg_parse_app14_data(struct jpeg_stream *stream,
+                                enum v4l2_jpeg_app14_tf *tf)
+{
+       int ret;
+       int lp;
+       int skip;
+
+       lp = jpeg_get_word_be(stream);
+       if (lp < 0)
+               return lp;
+
+       /* Check for "Adobe\0" in Ap1..6 */
+       if (stream->curr + 6 > stream->end ||
+           strncmp(stream->curr, "Adobe\0", 6))
+               return -EINVAL;
+
+       /* get to Ap12 */
+       ret = jpeg_skip(stream, 11);
+       if (ret < 0)
+               return ret;
+
+       ret = jpeg_get_byte(stream);
+       if (ret < 0)
+               return ret;
+
+       *tf = ret;
+
+       /* skip the rest of the segment, this ensures at least it is complete */
+       skip = lp - 2 - 11;
+       return jpeg_skip(stream, skip);
+}
+
 /**
  * v4l2_jpeg_parse_header - locate marker segments and optionally parse headers
  * @buf: address of the JPEG buffer, should start with a SOI marker
        if (marker != SOI)
                return -EINVAL;
 
+       /* init value to signal if this marker is not present */
+       out->app14_tf = V4L2_JPEG_APP14_TF_UNKNOWN;
+
        /* loop through marker segments */
        while ((marker = jpeg_next_marker(&stream)) >= 0) {
                switch (marker) {
                        ret = jpeg_parse_restart_interval(&stream,
                                                        &out->restart_interval);
                        break;
-
+               case APP14:
+                       ret = jpeg_parse_app14_data(&stream,
+                                                   &out->app14_tf);
+                       break;
                case SOS:
                        ret = jpeg_reference_segment(&stream, &out->sos);
                        if (ret < 0)
 
        /* Ss, Se, Ah, and Al are not used by any driver */
 };
 
+/**
+ * enum v4l2_jpeg_app14_tf - APP14 transform flag
+ * According to Rec. ITU-T T.872 (06/2012) 6.5.3
+ * APP14 segment is for color encoding, it contains a transform flag,
+ * which may have values of 0, 1 and 2 and are interpreted as follows:
+ * @V4L2_JPEG_APP14_TF_CMYK_RGB: CMYK for images encoded with four components
+ *                               RGB for images encoded with three components
+ * @V4L2_JPEG_APP14_TF_YCBCR: an image encoded with three components using YCbCr
+ * @V4L2_JPEG_APP14_TF_YCCK: an image encoded with four components using YCCK
+ * @V4L2_JPEG_APP14_TF_UNKNOWN: indicate app14 is not present
+ */
+enum v4l2_jpeg_app14_tf {
+       V4L2_JPEG_APP14_TF_CMYK_RGB     = 0,
+       V4L2_JPEG_APP14_TF_YCBCR        = 1,
+       V4L2_JPEG_APP14_TF_YCCK         = 2,
+       V4L2_JPEG_APP14_TF_UNKNOWN      = -1,
+};
+
 /**
  * struct v4l2_jpeg_header - parsed JPEG header
  * @sof: pointer to frame header and size
  *                  order, optional
  * @restart_interval: number of MCU per restart interval, Ri
  * @ecs_offset: buffer offset in bytes to the entropy coded segment
+ * @app14_tf: transform flag from app14 data
  *
  * When this structure is passed to v4l2_jpeg_parse_header, the optional scan,
  * quantization_tables, and huffman_tables pointers must be initialized to NULL
        struct v4l2_jpeg_reference *huffman_tables;
        u16 restart_interval;
        size_t ecs_offset;
+       enum v4l2_jpeg_app14_tf app14_tf;
 };
 
 int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out);