2 * vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
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>
17 #include <media/v4l2-subdev.h>
22 #define LIF_MIN_SIZE 2U
23 #define LIF_MAX_SIZE 2048U
25 /* -----------------------------------------------------------------------------
29 static inline u32
vsp1_lif_read(struct vsp1_lif
*lif
, u32 reg
)
31 return vsp1_read(lif
->entity
.vsp1
, reg
);
34 static inline void vsp1_lif_write(struct vsp1_lif
*lif
, u32 reg
, u32 data
)
36 vsp1_write(lif
->entity
.vsp1
, reg
, data
);
39 /* -----------------------------------------------------------------------------
40 * V4L2 Subdevice Core Operations
43 static int lif_s_stream(struct v4l2_subdev
*subdev
, int enable
)
45 const struct v4l2_mbus_framefmt
*format
;
46 struct vsp1_lif
*lif
= to_lif(subdev
);
47 unsigned int hbth
= 1300;
48 unsigned int obth
= 400;
49 unsigned int lbth
= 200;
52 vsp1_lif_write(lif
, VI6_LIF_CTRL
, 0);
56 format
= &lif
->entity
.formats
[LIF_PAD_SOURCE
];
58 obth
= min(obth
, (format
->width
+ 1) / 2 * format
->height
- 4);
60 vsp1_lif_write(lif
, VI6_LIF_CSBTH
,
61 (hbth
<< VI6_LIF_CSBTH_HBTH_SHIFT
) |
62 (lbth
<< VI6_LIF_CSBTH_LBTH_SHIFT
));
64 vsp1_lif_write(lif
, VI6_LIF_CTRL
,
65 (obth
<< VI6_LIF_CTRL_OBTH_SHIFT
) |
66 (format
->code
== 0 ? VI6_LIF_CTRL_CFMT
: 0) |
67 VI6_LIF_CTRL_REQSEL
| VI6_LIF_CTRL_LIF_EN
);
72 /* -----------------------------------------------------------------------------
73 * V4L2 Subdevice Pad Operations
76 static int lif_enum_mbus_code(struct v4l2_subdev
*subdev
,
77 struct v4l2_subdev_fh
*fh
,
78 struct v4l2_subdev_mbus_code_enum
*code
)
80 static const unsigned int codes
[] = {
81 V4L2_MBUS_FMT_ARGB8888_1X32
,
82 V4L2_MBUS_FMT_AYUV8_1X32
,
85 if (code
->pad
== LIF_PAD_SINK
) {
86 if (code
->index
>= ARRAY_SIZE(codes
))
89 code
->code
= codes
[code
->index
];
91 struct v4l2_mbus_framefmt
*format
;
93 /* The LIF can't perform format conversion, the sink format is
94 * always identical to the source format.
99 format
= v4l2_subdev_get_try_format(fh
, LIF_PAD_SINK
);
100 code
->code
= format
->code
;
106 static int lif_enum_frame_size(struct v4l2_subdev
*subdev
,
107 struct v4l2_subdev_fh
*fh
,
108 struct v4l2_subdev_frame_size_enum
*fse
)
110 struct v4l2_mbus_framefmt
*format
;
112 format
= v4l2_subdev_get_try_format(fh
, LIF_PAD_SINK
);
114 if (fse
->index
|| fse
->code
!= format
->code
)
117 if (fse
->pad
== LIF_PAD_SINK
) {
118 fse
->min_width
= LIF_MIN_SIZE
;
119 fse
->max_width
= LIF_MAX_SIZE
;
120 fse
->min_height
= LIF_MIN_SIZE
;
121 fse
->max_height
= LIF_MAX_SIZE
;
123 fse
->min_width
= format
->width
;
124 fse
->max_width
= format
->width
;
125 fse
->min_height
= format
->height
;
126 fse
->max_height
= format
->height
;
132 static int lif_get_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
,
133 struct v4l2_subdev_format
*fmt
)
135 struct vsp1_lif
*lif
= to_lif(subdev
);
137 fmt
->format
= *vsp1_entity_get_pad_format(&lif
->entity
, fh
, fmt
->pad
,
143 static int lif_set_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_fh
*fh
,
144 struct v4l2_subdev_format
*fmt
)
146 struct vsp1_lif
*lif
= to_lif(subdev
);
147 struct v4l2_mbus_framefmt
*format
;
149 /* Default to YUV if the requested format is not supported. */
150 if (fmt
->format
.code
!= V4L2_MBUS_FMT_ARGB8888_1X32
&&
151 fmt
->format
.code
!= V4L2_MBUS_FMT_AYUV8_1X32
)
152 fmt
->format
.code
= V4L2_MBUS_FMT_AYUV8_1X32
;
154 format
= vsp1_entity_get_pad_format(&lif
->entity
, fh
, fmt
->pad
,
157 if (fmt
->pad
== LIF_PAD_SOURCE
) {
158 /* The LIF source format is always identical to its sink
161 fmt
->format
= *format
;
165 format
->code
= fmt
->format
.code
;
166 format
->width
= clamp_t(unsigned int, fmt
->format
.width
,
167 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
168 format
->height
= clamp_t(unsigned int, fmt
->format
.height
,
169 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
170 format
->field
= V4L2_FIELD_NONE
;
171 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
173 fmt
->format
= *format
;
175 /* Propagate the format to the source pad. */
176 format
= vsp1_entity_get_pad_format(&lif
->entity
, fh
, LIF_PAD_SOURCE
,
178 *format
= fmt
->format
;
183 /* -----------------------------------------------------------------------------
184 * V4L2 Subdevice Operations
187 static struct v4l2_subdev_video_ops lif_video_ops
= {
188 .s_stream
= lif_s_stream
,
191 static struct v4l2_subdev_pad_ops lif_pad_ops
= {
192 .enum_mbus_code
= lif_enum_mbus_code
,
193 .enum_frame_size
= lif_enum_frame_size
,
194 .get_fmt
= lif_get_format
,
195 .set_fmt
= lif_set_format
,
198 static struct v4l2_subdev_ops lif_ops
= {
199 .video
= &lif_video_ops
,
203 /* -----------------------------------------------------------------------------
204 * Initialization and Cleanup
207 struct vsp1_lif
*vsp1_lif_create(struct vsp1_device
*vsp1
)
209 struct v4l2_subdev
*subdev
;
210 struct vsp1_lif
*lif
;
213 lif
= devm_kzalloc(vsp1
->dev
, sizeof(*lif
), GFP_KERNEL
);
215 return ERR_PTR(-ENOMEM
);
217 lif
->entity
.type
= VSP1_ENTITY_LIF
;
218 lif
->entity
.id
= VI6_DPR_NODE_LIF
;
220 ret
= vsp1_entity_init(vsp1
, &lif
->entity
, 2);
224 /* Initialize the V4L2 subdev. */
225 subdev
= &lif
->entity
.subdev
;
226 v4l2_subdev_init(subdev
, &lif_ops
);
228 subdev
->entity
.ops
= &vsp1_media_ops
;
229 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
230 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s lif",
231 dev_name(vsp1
->dev
));
232 v4l2_set_subdevdata(subdev
, lif
);
233 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
235 vsp1_entity_init_formats(subdev
, NULL
);