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 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_pad_config
*cfg
,
78 struct v4l2_subdev_mbus_code_enum
*code
)
80 static const unsigned int codes
[] = {
81 MEDIA_BUS_FMT_ARGB8888_1X32
,
82 MEDIA_BUS_FMT_AYUV8_1X32
,
84 struct vsp1_lif
*lif
= to_lif(subdev
);
86 if (code
->pad
== LIF_PAD_SINK
) {
87 if (code
->index
>= ARRAY_SIZE(codes
))
90 code
->code
= codes
[code
->index
];
92 struct v4l2_mbus_framefmt
*format
;
94 /* The LIF can't perform format conversion, the sink format is
95 * always identical to the source format.
100 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
,
101 LIF_PAD_SINK
, code
->which
);
102 code
->code
= format
->code
;
108 static int lif_enum_frame_size(struct v4l2_subdev
*subdev
,
109 struct v4l2_subdev_pad_config
*cfg
,
110 struct v4l2_subdev_frame_size_enum
*fse
)
112 struct vsp1_lif
*lif
= to_lif(subdev
);
113 struct v4l2_mbus_framefmt
*format
;
115 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, LIF_PAD_SINK
,
118 if (fse
->index
|| fse
->code
!= format
->code
)
121 if (fse
->pad
== LIF_PAD_SINK
) {
122 fse
->min_width
= LIF_MIN_SIZE
;
123 fse
->max_width
= LIF_MAX_SIZE
;
124 fse
->min_height
= LIF_MIN_SIZE
;
125 fse
->max_height
= LIF_MAX_SIZE
;
127 fse
->min_width
= format
->width
;
128 fse
->max_width
= format
->width
;
129 fse
->min_height
= format
->height
;
130 fse
->max_height
= format
->height
;
136 static int lif_get_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
137 struct v4l2_subdev_format
*fmt
)
139 struct vsp1_lif
*lif
= to_lif(subdev
);
141 fmt
->format
= *vsp1_entity_get_pad_format(&lif
->entity
, cfg
, fmt
->pad
,
147 static int lif_set_format(struct v4l2_subdev
*subdev
, struct v4l2_subdev_pad_config
*cfg
,
148 struct v4l2_subdev_format
*fmt
)
150 struct vsp1_lif
*lif
= to_lif(subdev
);
151 struct v4l2_mbus_framefmt
*format
;
153 /* Default to YUV if the requested format is not supported. */
154 if (fmt
->format
.code
!= MEDIA_BUS_FMT_ARGB8888_1X32
&&
155 fmt
->format
.code
!= MEDIA_BUS_FMT_AYUV8_1X32
)
156 fmt
->format
.code
= MEDIA_BUS_FMT_AYUV8_1X32
;
158 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, fmt
->pad
,
161 if (fmt
->pad
== LIF_PAD_SOURCE
) {
162 /* The LIF source format is always identical to its sink
165 fmt
->format
= *format
;
169 format
->code
= fmt
->format
.code
;
170 format
->width
= clamp_t(unsigned int, fmt
->format
.width
,
171 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
172 format
->height
= clamp_t(unsigned int, fmt
->format
.height
,
173 LIF_MIN_SIZE
, LIF_MAX_SIZE
);
174 format
->field
= V4L2_FIELD_NONE
;
175 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
177 fmt
->format
= *format
;
179 /* Propagate the format to the source pad. */
180 format
= vsp1_entity_get_pad_format(&lif
->entity
, cfg
, LIF_PAD_SOURCE
,
182 *format
= fmt
->format
;
187 /* -----------------------------------------------------------------------------
188 * V4L2 Subdevice Operations
191 static struct v4l2_subdev_video_ops lif_video_ops
= {
192 .s_stream
= lif_s_stream
,
195 static struct v4l2_subdev_pad_ops lif_pad_ops
= {
196 .enum_mbus_code
= lif_enum_mbus_code
,
197 .enum_frame_size
= lif_enum_frame_size
,
198 .get_fmt
= lif_get_format
,
199 .set_fmt
= lif_set_format
,
202 static struct v4l2_subdev_ops lif_ops
= {
203 .video
= &lif_video_ops
,
207 /* -----------------------------------------------------------------------------
208 * Initialization and Cleanup
211 struct vsp1_lif
*vsp1_lif_create(struct vsp1_device
*vsp1
)
213 struct v4l2_subdev
*subdev
;
214 struct vsp1_lif
*lif
;
217 lif
= devm_kzalloc(vsp1
->dev
, sizeof(*lif
), GFP_KERNEL
);
219 return ERR_PTR(-ENOMEM
);
221 lif
->entity
.type
= VSP1_ENTITY_LIF
;
223 ret
= vsp1_entity_init(vsp1
, &lif
->entity
, 2);
227 /* Initialize the V4L2 subdev. */
228 subdev
= &lif
->entity
.subdev
;
229 v4l2_subdev_init(subdev
, &lif_ops
);
231 subdev
->entity
.ops
= &vsp1_media_ops
;
232 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
233 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s lif",
234 dev_name(vsp1
->dev
));
235 v4l2_set_subdevdata(subdev
, lif
);
236 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
238 vsp1_entity_init_formats(subdev
, NULL
);