2 * vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
4 * Copyright (C) 2013-2014 Renesas Electronics 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>
17 #include <media/v4l2-subdev.h>
22 #define LIF_MIN_SIZE 2U
23 #define LIF_MAX_SIZE 2048U
25 /* -----------------------------------------------------------------------------
29 static inline void vsp1_lif_write(struct vsp1_lif
*lif
, u32 reg
, u32 data
)
31 vsp1_mod_write(&lif
->entity
, reg
, data
);
34 /* -----------------------------------------------------------------------------
35 * V4L2 Subdevice Core Operations
38 static int lif_s_stream(struct v4l2_subdev
*subdev
, int enable
)
40 const struct v4l2_mbus_framefmt
*format
;
41 struct vsp1_lif
*lif
= to_lif(subdev
);
42 unsigned int hbth
= 1300;
43 unsigned int obth
= 400;
44 unsigned int lbth
= 200;
47 vsp1_write(lif
->entity
.vsp1
, VI6_LIF_CTRL
, 0);
51 format
= &lif
->entity
.formats
[LIF_PAD_SOURCE
];
53 obth
= min(obth
, (format
->width
+ 1) / 2 * format
->height
- 4);
55 vsp1_lif_write(lif
, VI6_LIF_CSBTH
,
56 (hbth
<< VI6_LIF_CSBTH_HBTH_SHIFT
) |
57 (lbth
<< VI6_LIF_CSBTH_LBTH_SHIFT
));
59 vsp1_lif_write(lif
, VI6_LIF_CTRL
,
60 (obth
<< VI6_LIF_CTRL_OBTH_SHIFT
) |
61 (format
->code
== 0 ? VI6_LIF_CTRL_CFMT
: 0) |
62 VI6_LIF_CTRL_REQSEL
| VI6_LIF_CTRL_LIF_EN
);
67 /* -----------------------------------------------------------------------------
68 * V4L2 Subdevice Pad Operations
71 static int lif_enum_mbus_code(struct v4l2_subdev
*subdev
,
72 struct v4l2_subdev_pad_config
*cfg
,
73 struct v4l2_subdev_mbus_code_enum
*code
)
75 static const unsigned int codes
[] = {
76 MEDIA_BUS_FMT_ARGB8888_1X32
,
77 MEDIA_BUS_FMT_AYUV8_1X32
,
79 struct vsp1_lif
*lif
= to_lif(subdev
);
81 if (code
->pad
== LIF_PAD_SINK
) {
82 if (code
->index
>= ARRAY_SIZE(codes
))
85 code
->code
= codes
[code
->index
];
87 struct v4l2_mbus_framefmt
*format
;
89 /* The LIF can't perform format conversion, the sink format is
90 * always identical to the source format.
95 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
,
96 LIF_PAD_SINK
, code
->which
);
97 code
->code
= format
->code
;
103 static int lif_enum_frame_size(struct v4l2_subdev
*subdev
,
104 struct v4l2_subdev_pad_config
*cfg
,
105 struct v4l2_subdev_frame_size_enum
*fse
)
107 struct vsp1_lif
*lif
= to_lif(subdev
);
108 struct v4l2_mbus_framefmt
*format
;
110 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, LIF_PAD_SINK
,
113 if (fse
->index
|| fse
->code
!= format
->code
)
116 if (fse
->pad
== LIF_PAD_SINK
) {
117 fse
->min_width
= LIF_MIN_SIZE
;
118 fse
->max_width
= LIF_MAX_SIZE
;
119 fse
->min_height
= LIF_MIN_SIZE
;
120 fse
->max_height
= LIF_MAX_SIZE
;
122 fse
->min_width
= format
->width
;
123 fse
->max_width
= format
->width
;
124 fse
->min_height
= format
->height
;
125 fse
->max_height
= format
->height
;
131 static int lif_get_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
132 struct v4l2_subdev_format
*fmt
)
134 struct vsp1_lif
*lif
= to_lif(subdev
);
136 fmt
->format
= *vsp1_entity_get_pad_format(&lif
->entity
, cfg
, fmt
->pad
,
142 static int lif_set_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
143 struct v4l2_subdev_format
*fmt
)
145 struct vsp1_lif
*lif
= to_lif(subdev
);
146 struct v4l2_mbus_framefmt
*format
;
148 /* Default to YUV if the requested format is not supported. */
149 if (fmt
->format
.code
!= MEDIA_BUS_FMT_ARGB8888_1X32
&&
150 fmt
->format
.code
!= MEDIA_BUS_FMT_AYUV8_1X32
)
151 fmt
->format
.code
= MEDIA_BUS_FMT_AYUV8_1X32
;
153 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, fmt
->pad
,
156 if (fmt
->pad
== LIF_PAD_SOURCE
) {
157 /* The LIF source format is always identical to its sink
160 fmt
->format
= *format
;
164 format
->code
= fmt
->format
.code
;
165 format
->width
= clamp_t(unsigned int, fmt
->format
.width
,
166 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
167 format
->height
= clamp_t(unsigned int, fmt
->format
.height
,
168 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
169 format
->field
= V4L2_FIELD_NONE
;
170 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
172 fmt
->format
= *format
;
174 /* Propagate the format to the source pad. */
175 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, LIF_PAD_SOURCE
,
177 *format
= fmt
->format
;
182 /* -----------------------------------------------------------------------------
183 * V4L2 Subdevice Operations
186 static struct v4l2_subdev_video_ops lif_video_ops
= {
187 .s_stream
= lif_s_stream
,
190 static struct v4l2_subdev_pad_ops lif_pad_ops
= {
191 .enum_mbus_code
= lif_enum_mbus_code
,
192 .enum_frame_size
= lif_enum_frame_size
,
193 .get_fmt
= lif_get_format
,
194 .set_fmt
= lif_set_format
,
197 static struct v4l2_subdev_ops lif_ops
= {
198 .video
= &lif_video_ops
,
202 /* -----------------------------------------------------------------------------
203 * Initialization and Cleanup
206 struct vsp1_lif
*vsp1_lif_create(struct vsp1_device
*vsp1
)
208 struct v4l2_subdev
*subdev
;
209 struct vsp1_lif
*lif
;
212 lif
= devm_kzalloc(vsp1
->dev
, sizeof(*lif
), GFP_KERNEL
);
214 return ERR_PTR(-ENOMEM
);
216 lif
->entity
.type
= VSP1_ENTITY_LIF
;
218 ret
= vsp1_entity_init(vsp1
, &lif
->entity
, 2);
222 /* Initialize the V4L2 subdev. */
223 subdev
= &lif
->entity
.subdev
;
224 v4l2_subdev_init(subdev
, &lif_ops
);
226 subdev
->entity
.ops
= &vsp1
->media_ops
;
227 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
228 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s lif",
229 dev_name(vsp1
->dev
));
230 v4l2_set_subdevdata(subdev
, lif
);
231 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
233 vsp1_entity_init_formats(subdev
, NULL
);