vsp1_hsit.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * vsp1_hsit.c -- R-Car VSP1 Hue Saturation value (Inverse) Transform
  3. *
  4. * Copyright (C) 2013 Renesas Corporation
  5. *
  6. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. */
  13. #include <linux/device.h>
  14. #include <linux/gfp.h>
  15. #include <media/v4l2-subdev.h>
  16. #include "vsp1.h"
  17. #include "vsp1_hsit.h"
  18. #define HSIT_MIN_SIZE 4U
  19. #define HSIT_MAX_SIZE 8190U
  20. /* -----------------------------------------------------------------------------
  21. * Device Access
  22. */
  23. static inline u32 vsp1_hsit_read(struct vsp1_hsit *hsit, u32 reg)
  24. {
  25. return vsp1_read(hsit->entity.vsp1, reg);
  26. }
  27. static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
  28. {
  29. vsp1_write(hsit->entity.vsp1, reg, data);
  30. }
  31. /* -----------------------------------------------------------------------------
  32. * V4L2 Subdevice Core Operations
  33. */
  34. static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
  35. {
  36. struct vsp1_hsit *hsit = to_hsit(subdev);
  37. if (!enable)
  38. return 0;
  39. if (hsit->inverse)
  40. vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
  41. else
  42. vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
  43. return 0;
  44. }
  45. /* -----------------------------------------------------------------------------
  46. * V4L2 Subdevice Pad Operations
  47. */
  48. static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
  49. struct v4l2_subdev_fh *fh,
  50. struct v4l2_subdev_mbus_code_enum *code)
  51. {
  52. struct vsp1_hsit *hsit = to_hsit(subdev);
  53. if (code->index > 0)
  54. return -EINVAL;
  55. if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
  56. (code->pad == HSIT_PAD_SOURCE && hsit->inverse))
  57. code->code = V4L2_MBUS_FMT_ARGB8888_1X32;
  58. else
  59. code->code = V4L2_MBUS_FMT_AHSV8888_1X32;
  60. return 0;
  61. }
  62. static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
  63. struct v4l2_subdev_fh *fh,
  64. struct v4l2_subdev_frame_size_enum *fse)
  65. {
  66. struct v4l2_mbus_framefmt *format;
  67. format = v4l2_subdev_get_try_format(fh, fse->pad);
  68. if (fse->index || fse->code != format->code)
  69. return -EINVAL;
  70. if (fse->pad == HSIT_PAD_SINK) {
  71. fse->min_width = HSIT_MIN_SIZE;
  72. fse->max_width = HSIT_MAX_SIZE;
  73. fse->min_height = HSIT_MIN_SIZE;
  74. fse->max_height = HSIT_MAX_SIZE;
  75. } else {
  76. /* The size on the source pad are fixed and always identical to
  77. * the size on the sink pad.
  78. */
  79. fse->min_width = format->width;
  80. fse->max_width = format->width;
  81. fse->min_height = format->height;
  82. fse->max_height = format->height;
  83. }
  84. return 0;
  85. }
  86. static int hsit_get_format(struct v4l2_subdev *subdev,
  87. struct v4l2_subdev_fh *fh,
  88. struct v4l2_subdev_format *fmt)
  89. {
  90. struct vsp1_hsit *hsit = to_hsit(subdev);
  91. fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
  92. fmt->which);
  93. return 0;
  94. }
  95. static int hsit_set_format(struct v4l2_subdev *subdev,
  96. struct v4l2_subdev_fh *fh,
  97. struct v4l2_subdev_format *fmt)
  98. {
  99. struct vsp1_hsit *hsit = to_hsit(subdev);
  100. struct v4l2_mbus_framefmt *format;
  101. format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
  102. fmt->which);
  103. if (fmt->pad == HSIT_PAD_SOURCE) {
  104. /* The HST and HSI output format code and resolution can't be
  105. * modified.
  106. */
  107. fmt->format = *format;
  108. return 0;
  109. }
  110. format->code = hsit->inverse ? V4L2_MBUS_FMT_AHSV8888_1X32
  111. : V4L2_MBUS_FMT_ARGB8888_1X32;
  112. format->width = clamp_t(unsigned int, fmt->format.width,
  113. HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  114. format->height = clamp_t(unsigned int, fmt->format.height,
  115. HSIT_MIN_SIZE, HSIT_MAX_SIZE);
  116. format->field = V4L2_FIELD_NONE;
  117. format->colorspace = V4L2_COLORSPACE_SRGB;
  118. fmt->format = *format;
  119. /* Propagate the format to the source pad. */
  120. format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE,
  121. fmt->which);
  122. *format = fmt->format;
  123. format->code = hsit->inverse ? V4L2_MBUS_FMT_ARGB8888_1X32
  124. : V4L2_MBUS_FMT_AHSV8888_1X32;
  125. return 0;
  126. }
  127. /* -----------------------------------------------------------------------------
  128. * V4L2 Subdevice Operations
  129. */
  130. static struct v4l2_subdev_video_ops hsit_video_ops = {
  131. .s_stream = hsit_s_stream,
  132. };
  133. static struct v4l2_subdev_pad_ops hsit_pad_ops = {
  134. .enum_mbus_code = hsit_enum_mbus_code,
  135. .enum_frame_size = hsit_enum_frame_size,
  136. .get_fmt = hsit_get_format,
  137. .set_fmt = hsit_set_format,
  138. };
  139. static struct v4l2_subdev_ops hsit_ops = {
  140. .video = &hsit_video_ops,
  141. .pad = &hsit_pad_ops,
  142. };
  143. /* -----------------------------------------------------------------------------
  144. * Initialization and Cleanup
  145. */
  146. struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
  147. {
  148. struct v4l2_subdev *subdev;
  149. struct vsp1_hsit *hsit;
  150. int ret;
  151. hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
  152. if (hsit == NULL)
  153. return ERR_PTR(-ENOMEM);
  154. hsit->inverse = inverse;
  155. if (inverse)
  156. hsit->entity.type = VSP1_ENTITY_HSI;
  157. else
  158. hsit->entity.type = VSP1_ENTITY_HST;
  159. ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
  160. if (ret < 0)
  161. return ERR_PTR(ret);
  162. /* Initialize the V4L2 subdev. */
  163. subdev = &hsit->entity.subdev;
  164. v4l2_subdev_init(subdev, &hsit_ops);
  165. subdev->entity.ops = &vsp1_media_ops;
  166. subdev->internal_ops = &vsp1_subdev_internal_ops;
  167. snprintf(subdev->name, sizeof(subdev->name), "%s %s",
  168. dev_name(vsp1->dev), inverse ? "hsi" : "hst");
  169. v4l2_set_subdevdata(subdev, hsit);
  170. subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
  171. vsp1_entity_init_formats(subdev, NULL);
  172. return hsit;
  173. }