2 * vsp1_lut.c -- R-Car VSP1 Look-Up Table
4 * Copyright (C) 2013 Renesas Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/device.h>
15 #include <linux/gfp.h>
16 #include <linux/vsp1.h>
18 #include <media/v4l2-subdev.h>
23 #define LUT_MIN_SIZE 4U
24 #define LUT_MAX_SIZE 8190U
26 /* -----------------------------------------------------------------------------
30 static inline void vsp1_lut_write(struct vsp1_lut
*lut
, u32 reg
, u32 data
)
32 vsp1_write(lut
->entity
.vsp1
, reg
, data
);
35 /* -----------------------------------------------------------------------------
36 * V4L2 Subdevice Core Operations
39 static void lut_configure(struct vsp1_lut
*lut
, struct vsp1_lut_config
*config
)
41 memcpy_toio(lut
->entity
.vsp1
->mmio
+ VI6_LUT_TABLE
, config
->lut
,
45 static long lut_ioctl(struct v4l2_subdev
*subdev
, unsigned int cmd
, void *arg
)
47 struct vsp1_lut
*lut
= to_lut(subdev
);
50 case VIDIOC_VSP1_LUT_CONFIG
:
51 lut_configure(lut
, arg
);
59 /* -----------------------------------------------------------------------------
60 * V4L2 Subdevice Video Operations
63 static int lut_s_stream(struct v4l2_subdev
*subdev
, int enable
)
65 struct vsp1_lut
*lut
= to_lut(subdev
);
70 vsp1_lut_write(lut
, VI6_LUT_CTRL
, VI6_LUT_CTRL_EN
);
75 /* -----------------------------------------------------------------------------
76 * V4L2 Subdevice Pad Operations
79 static int lut_enum_mbus_code(struct v4l2_subdev
*subdev
,
80 struct v4l2_subdev_pad_config
*cfg
,
81 struct v4l2_subdev_mbus_code_enum
*code
)
83 static const unsigned int codes
[] = {
84 MEDIA_BUS_FMT_ARGB8888_1X32
,
85 MEDIA_BUS_FMT_AHSV8888_1X32
,
86 MEDIA_BUS_FMT_AYUV8_1X32
,
88 struct vsp1_lut
*lut
= to_lut(subdev
);
89 struct v4l2_mbus_framefmt
*format
;
91 if (code
->pad
== LUT_PAD_SINK
) {
92 if (code
->index
>= ARRAY_SIZE(codes
))
95 code
->code
= codes
[code
->index
];
97 /* The LUT can't perform format conversion, the sink format is
98 * always identical to the source format.
103 format
= vsp1_entity_get_pad_format(&lut
->entity
, cfg
,
104 LUT_PAD_SINK
, code
->which
);
105 code
->code
= format
->code
;
111 static int lut_enum_frame_size(struct v4l2_subdev
*subdev
,
112 struct v4l2_subdev_pad_config
*cfg
,
113 struct v4l2_subdev_frame_size_enum
*fse
)
115 struct vsp1_lut
*lut
= to_lut(subdev
);
116 struct v4l2_mbus_framefmt
*format
;
118 format
= vsp1_entity_get_pad_format(&lut
->entity
, cfg
,
119 fse
->pad
, fse
->which
);
121 if (fse
->index
|| fse
->code
!= format
->code
)
124 if (fse
->pad
== LUT_PAD_SINK
) {
125 fse
->min_width
= LUT_MIN_SIZE
;
126 fse
->max_width
= LUT_MAX_SIZE
;
127 fse
->min_height
= LUT_MIN_SIZE
;
128 fse
->max_height
= LUT_MAX_SIZE
;
130 /* The size on the source pad are fixed and always identical to
131 * the size on the sink pad.
133 fse
->min_width
= format
->width
;
134 fse
->max_width
= format
->width
;
135 fse
->min_height
= format
->height
;
136 fse
->max_height
= format
->height
;
142 static int lut_get_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
143 struct v4l2_subdev_format
*fmt
)
145 struct vsp1_lut
*lut
= to_lut(subdev
);
147 fmt
->format
= *vsp1_entity_get_pad_format(&lut
->entity
, cfg
, fmt
->pad
,
153 static int lut_set_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
154 struct v4l2_subdev_format
*fmt
)
156 struct vsp1_lut
*lut
= to_lut(subdev
);
157 struct v4l2_mbus_framefmt
*format
;
159 /* Default to YUV if the requested format is not supported. */
160 if (fmt
->format
.code
!= MEDIA_BUS_FMT_ARGB8888_1X32
&&
161 fmt
->format
.code
!= MEDIA_BUS_FMT_AHSV8888_1X32
&&
162 fmt
->format
.code
!= MEDIA_BUS_FMT_AYUV8_1X32
)
163 fmt
->format
.code
= MEDIA_BUS_FMT_AYUV8_1X32
;
165 format
= vsp1_entity_get_pad_format(&lut
->entity
, cfg
, fmt
->pad
,
168 if (fmt
->pad
== LUT_PAD_SOURCE
) {
169 /* The LUT output format can't be modified. */
170 fmt
->format
= *format
;
174 format
->width
= clamp_t(unsigned int, fmt
->format
.width
,
175 LUT_MIN_SIZE
, LUT_MAX_SIZE
);
176 format
->height
= clamp_t(unsigned int, fmt
->format
.height
,
177 LUT_MIN_SIZE
, LUT_MAX_SIZE
);
178 format
->field
= V4L2_FIELD_NONE
;
179 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
181 fmt
->format
= *format
;
183 /* Propagate the format to the source pad. */
184 format
= vsp1_entity_get_pad_format(&lut
->entity
, cfg
, LUT_PAD_SOURCE
,
186 *format
= fmt
->format
;
191 /* -----------------------------------------------------------------------------
192 * V4L2 Subdevice Operations
195 static struct v4l2_subdev_core_ops lut_core_ops
= {
199 static struct v4l2_subdev_video_ops lut_video_ops
= {
200 .s_stream
= lut_s_stream
,
203 static struct v4l2_subdev_pad_ops lut_pad_ops
= {
204 .enum_mbus_code
= lut_enum_mbus_code
,
205 .enum_frame_size
= lut_enum_frame_size
,
206 .get_fmt
= lut_get_format
,
207 .set_fmt
= lut_set_format
,
210 static struct v4l2_subdev_ops lut_ops
= {
211 .core
= &lut_core_ops
,
212 .video
= &lut_video_ops
,
216 /* -----------------------------------------------------------------------------
217 * Initialization and Cleanup
220 struct vsp1_lut
*vsp1_lut_create(struct vsp1_device
*vsp1
)
222 struct v4l2_subdev
*subdev
;
223 struct vsp1_lut
*lut
;
226 lut
= devm_kzalloc(vsp1
->dev
, sizeof(*lut
), GFP_KERNEL
);
228 return ERR_PTR(-ENOMEM
);
230 lut
->entity
.type
= VSP1_ENTITY_LUT
;
232 ret
= vsp1_entity_init(vsp1
, &lut
->entity
, 2);
236 /* Initialize the V4L2 subdev. */
237 subdev
= &lut
->entity
.subdev
;
238 v4l2_subdev_init(subdev
, &lut_ops
);
240 subdev
->entity
.ops
= &vsp1
->media_ops
;
241 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
242 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s lut",
243 dev_name(vsp1
->dev
));
244 v4l2_set_subdevdata(subdev
, lut
);
245 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
247 vsp1_entity_init_formats(subdev
, NULL
);