Commit fa3e70360c86480acbaa54c9791e843196327a66
Committed by
Mauro Carvalho Chehab
1 parent
5811cf99df
Exists in
master
and in
4 other branches
V4L/DVB (10757): cx18, v4l2-chip-ident: Finish conversion of AV decoder core to v4l2_subdev
Added a new chip identifer to v4l2-chip-ident for the integrated A/V broadcast decoder core internal to the CX23418. Completed separation and encapsulation of the A/V decoder core interface as a v4l2_subdevice. The cx18 driver now compiles and links again. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 12 changed files with 100 additions and 67 deletions Side-by-side Diff
- drivers/media/video/cx18/cx18-av-core.c
- drivers/media/video/cx18/cx18-av-core.h
- drivers/media/video/cx18/cx18-controls.c
- drivers/media/video/cx18/cx18-driver.c
- drivers/media/video/cx18/cx18-driver.h
- drivers/media/video/cx18/cx18-firmware.c
- drivers/media/video/cx18/cx18-i2c.c
- drivers/media/video/cx18/cx18-ioctl.c
- drivers/media/video/cx18/cx18-streams.c
- drivers/media/video/cx18/cx18-vbi.c
- drivers/media/video/cx18/cx18-video.c
- include/media/v4l2-chip-ident.h
drivers/media/video/cx18/cx18-av-core.c
... | ... | @@ -201,15 +201,45 @@ |
201 | 201 | return 0; |
202 | 202 | } |
203 | 203 | |
204 | -static int cx18_av_init_hardware(struct v4l2_subdev *sd, u32 val) | |
204 | +static int cx18_av_init(struct v4l2_subdev *sd, u32 val) | |
205 | 205 | { |
206 | 206 | struct cx18_av_state *state = to_cx18_av_state(sd); |
207 | 207 | struct cx18 *cx = v4l2_get_subdevdata(sd); |
208 | 208 | |
209 | - if (!state->is_initialized) { | |
210 | - /* initialize on first use */ | |
211 | - state->is_initialized = 1; | |
212 | - cx18_av_initialize(cx); | |
209 | + switch (val) { | |
210 | + case CX18_AV_INIT_PLLS: | |
211 | + /* | |
212 | + * The crystal freq used in calculations in this driver will be | |
213 | + * 28.636360 MHz. | |
214 | + * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. | |
215 | + */ | |
216 | + | |
217 | + /* | |
218 | + * VDCLK Integer = 0x0f, Post Divider = 0x04 | |
219 | + * AIMCLK Integer = 0x0e, Post Divider = 0x16 | |
220 | + */ | |
221 | + cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); | |
222 | + | |
223 | + /* VDCLK Fraction = 0x2be2fe */ | |
224 | + /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ | |
225 | + cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); | |
226 | + | |
227 | + /* AIMCLK Fraction = 0x05227ad */ | |
228 | + /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ | |
229 | + cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); | |
230 | + | |
231 | + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ | |
232 | + cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); | |
233 | + break; | |
234 | + | |
235 | + case CX18_AV_INIT_NORMAL: | |
236 | + default: | |
237 | + if (!state->is_initialized) { | |
238 | + /* initialize on first use */ | |
239 | + state->is_initialized = 1; | |
240 | + cx18_av_initialize(cx); | |
241 | + } | |
242 | + break; | |
213 | 243 | } |
214 | 244 | return 0; |
215 | 245 | } |
216 | 246 | |
... | ... | @@ -1095,14 +1125,11 @@ |
1095 | 1125 | static int cx18_av_g_chip_ident(struct v4l2_subdev *sd, |
1096 | 1126 | struct v4l2_dbg_chip_ident *chip) |
1097 | 1127 | { |
1128 | + struct cx18_av_state *state = to_cx18_av_state(sd); | |
1129 | + | |
1098 | 1130 | if (cx18_av_dbg_match(&chip->match)) { |
1099 | - /* | |
1100 | - * Nothing else is going to claim to be this combination, | |
1101 | - * and the real host chip revision will be returned by a host | |
1102 | - * match on address 0. | |
1103 | - */ | |
1104 | - chip->ident = V4L2_IDENT_CX25843; | |
1105 | - chip->revision = V4L2_IDENT_CX23418; /* Why not */ | |
1131 | + chip->ident = state->id; | |
1132 | + chip->revision = state->rev; | |
1106 | 1133 | } |
1107 | 1134 | return 0; |
1108 | 1135 | } |
... | ... | @@ -1143,7 +1170,7 @@ |
1143 | 1170 | static const struct v4l2_subdev_core_ops cx18_av_general_ops = { |
1144 | 1171 | .g_chip_ident = cx18_av_g_chip_ident, |
1145 | 1172 | .log_status = cx18_av_log_status, |
1146 | - .init = cx18_av_init_hardware, | |
1173 | + .init = cx18_av_init, | |
1147 | 1174 | .reset = cx18_av_reset, |
1148 | 1175 | .queryctrl = cx18_av_queryctrl, |
1149 | 1176 | .g_ctrl = cx18_av_g_ctrl, |
1150 | 1177 | |
1151 | 1178 | |
1152 | 1179 | |
... | ... | @@ -1182,19 +1209,31 @@ |
1182 | 1209 | .video = &cx18_av_video_ops, |
1183 | 1210 | }; |
1184 | 1211 | |
1185 | -int cx18_av_init(struct cx18 *cx) | |
1212 | +int cx18_av_probe(struct cx18 *cx, struct v4l2_subdev **sd) | |
1186 | 1213 | { |
1187 | - struct v4l2_subdev *sd = &cx->av_state.sd; | |
1214 | + struct cx18_av_state *state = &cx->av_state; | |
1188 | 1215 | |
1189 | - v4l2_subdev_init(sd, &cx18_av_ops); | |
1190 | - v4l2_set_subdevdata(sd, cx); | |
1191 | - snprintf(sd->name, sizeof(sd->name), | |
1192 | - "%s-internal A/V decoder", cx->v4l2_dev.name); | |
1193 | - sd->grp_id = CX18_HW_CX23418; | |
1194 | - return v4l2_device_register_subdev(&cx->v4l2_dev, sd); | |
1216 | + state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; | |
1217 | + state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) | |
1218 | + ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN; | |
1219 | + | |
1220 | + state->vid_input = CX18_AV_COMPOSITE7; | |
1221 | + state->aud_input = CX18_AV_AUDIO8; | |
1222 | + state->audclk_freq = 48000; | |
1223 | + state->audmode = V4L2_TUNER_MODE_LANG1; | |
1224 | + state->slicer_line_delay = 0; | |
1225 | + state->slicer_line_offset = (10 + state->slicer_line_delay - 2); | |
1226 | + | |
1227 | + *sd = &state->sd; | |
1228 | + v4l2_subdev_init(*sd, &cx18_av_ops); | |
1229 | + v4l2_set_subdevdata(*sd, cx); | |
1230 | + snprintf((*sd)->name, sizeof((*sd)->name), | |
1231 | + "%s internal A/V decoder", cx->v4l2_dev.name); | |
1232 | + (*sd)->grp_id = CX18_HW_CX23418; | |
1233 | + return v4l2_device_register_subdev(&cx->v4l2_dev, *sd); | |
1195 | 1234 | } |
1196 | 1235 | |
1197 | -void cx18_av_fini(struct cx18 *cx) | |
1236 | +void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd) | |
1198 | 1237 | { |
1199 | 1238 | v4l2_device_unregister_subdev(&cx->av_state.sd); |
1200 | 1239 | } |
drivers/media/video/cx18/cx18-av-core.h
... | ... | @@ -323,6 +323,11 @@ |
323 | 323 | return container_of(sd, struct cx18_av_state, sd); |
324 | 324 | } |
325 | 325 | |
326 | +enum cx18_av_subdev_init_arg { | |
327 | + CX18_AV_INIT_NORMAL = 0, | |
328 | + CX18_AV_INIT_PLLS = 1, | |
329 | +}; | |
330 | + | |
326 | 331 | /* ----------------------------------------------------------------------- */ |
327 | 332 | /* cx18_av-core.c */ |
328 | 333 | int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); |
... | ... | @@ -337,9 +342,8 @@ |
337 | 342 | int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); |
338 | 343 | void cx18_av_std_setup(struct cx18 *cx); |
339 | 344 | |
340 | -int cx18_av_cmd(struct cx18 *cx, int cmd, void *arg); /* FIXME - Remove */ | |
341 | -int cx18_av_init(struct cx18 *cx); | |
342 | -void cx18_av_fini(struct cx18 *cx); | |
345 | +int cx18_av_probe(struct cx18 *cx, struct v4l2_subdev **sd); | |
346 | +void cx18_av_exit(struct cx18 *cx, struct v4l2_subdev *sd); | |
343 | 347 | |
344 | 348 | /* ----------------------------------------------------------------------- */ |
345 | 349 | /* cx18_av-firmware.c */ |
drivers/media/video/cx18/cx18-controls.c
... | ... | @@ -67,7 +67,7 @@ |
67 | 67 | case V4L2_CID_HUE: |
68 | 68 | case V4L2_CID_SATURATION: |
69 | 69 | case V4L2_CID_CONTRAST: |
70 | - if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl)) | |
70 | + if (v4l2_subdev_call(cx->sd_av, core, queryctrl, qctrl)) | |
71 | 71 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; |
72 | 72 | return 0; |
73 | 73 | |
... | ... | @@ -126,7 +126,7 @@ |
126 | 126 | case V4L2_CID_HUE: |
127 | 127 | case V4L2_CID_SATURATION: |
128 | 128 | case V4L2_CID_CONTRAST: |
129 | - return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl); | |
129 | + return v4l2_subdev_call(cx->sd_av, core, s_ctrl, vctrl); | |
130 | 130 | |
131 | 131 | case V4L2_CID_AUDIO_VOLUME: |
132 | 132 | case V4L2_CID_AUDIO_MUTE: |
... | ... | @@ -151,7 +151,7 @@ |
151 | 151 | case V4L2_CID_HUE: |
152 | 152 | case V4L2_CID_SATURATION: |
153 | 153 | case V4L2_CID_CONTRAST: |
154 | - return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl); | |
154 | + return v4l2_subdev_call(cx->sd_av, core, g_ctrl, vctrl); | |
155 | 155 | |
156 | 156 | case V4L2_CID_AUDIO_VOLUME: |
157 | 157 | case V4L2_CID_AUDIO_MUTE: |
... | ... | @@ -278,7 +278,7 @@ |
278 | 278 | fmt.fmt.pix.width = cx->params.width |
279 | 279 | / (is_mpeg1 ? 2 : 1); |
280 | 280 | fmt.fmt.pix.height = cx->params.height; |
281 | - cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); | |
281 | + v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt); | |
282 | 282 | } |
283 | 283 | priv.cx = cx; |
284 | 284 | priv.s = &cx->streams[id->type]; |
drivers/media/video/cx18/cx18-driver.c
... | ... | @@ -621,13 +621,6 @@ |
621 | 621 | i = 0; |
622 | 622 | cx->active_input = i; |
623 | 623 | cx->audio_input = cx->card->video_inputs[i].audio_index; |
624 | - cx->av_state.vid_input = CX18_AV_COMPOSITE7; | |
625 | - cx->av_state.aud_input = CX18_AV_AUDIO8; | |
626 | - cx->av_state.audclk_freq = 48000; | |
627 | - cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; | |
628 | - cx->av_state.slicer_line_delay = 0; | |
629 | - cx->av_state.slicer_line_offset = | |
630 | - (10 + cx->av_state.slicer_line_delay - 2); | |
631 | 624 | } |
632 | 625 | |
633 | 626 | static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, |
... | ... | @@ -812,6 +805,14 @@ |
812 | 805 | |
813 | 806 | cx18_gpio_init(cx); |
814 | 807 | |
808 | + retval = cx18_av_probe(cx, &cx->sd_av); | |
809 | + if (retval) { | |
810 | + CX18_ERR("Could not register A/V decoder subdevice\n"); | |
811 | + goto free_map; | |
812 | + } | |
813 | + /* Initialize the A/V decoder PLLs to sane defaults */ | |
814 | + v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_PLLS); | |
815 | + | |
815 | 816 | /* active i2c */ |
816 | 817 | CX18_DEBUG_INFO("activating i2c...\n"); |
817 | 818 | retval = init_cx18_i2c(cx); |
... | ... | @@ -1019,6 +1020,9 @@ |
1019 | 1020 | cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); |
1020 | 1021 | cx18_vapi(cx, CX18_APU_RESETAI, 0); |
1021 | 1022 | cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); |
1023 | + | |
1024 | + /* Init the A/V decoder, if it hasn't been already */ | |
1025 | + v4l2_subdev_call(cx->sd_av, core, init, (u32) CX18_AV_INIT_NORMAL); | |
1022 | 1026 | |
1023 | 1027 | vf.tuner = 0; |
1024 | 1028 | vf.type = V4L2_TUNER_ANALOG_TV; |
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-firmware.c
... | ... | @@ -26,7 +26,6 @@ |
26 | 26 | #include "cx18-irq.h" |
27 | 27 | #include "cx18-firmware.h" |
28 | 28 | #include "cx18-cards.h" |
29 | -#include "cx18-av-core.h" | |
30 | 29 | #include <linux/firmware.h> |
31 | 30 | |
32 | 31 | #define CX18_PROC_SOFT_RESET 0xc70010 |
... | ... | @@ -285,23 +284,6 @@ |
285 | 284 | cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); |
286 | 285 | cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC); |
287 | 286 | cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); |
288 | - | |
289 | - /* | |
290 | - * VDCLK Integer = 0x0f, Post Divider = 0x04 | |
291 | - * AIMCLK Integer = 0x0e, Post Divider = 0x16 | |
292 | - */ | |
293 | - cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); | |
294 | - | |
295 | - /* VDCLK Fraction = 0x2be2fe */ | |
296 | - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ | |
297 | - cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); | |
298 | - | |
299 | - /* AIMCLK Fraction = 0x05227ad */ | |
300 | - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz before post-divide */ | |
301 | - cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); | |
302 | - | |
303 | - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ | |
304 | - cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); | |
305 | 287 | |
306 | 288 | /* Defaults */ |
307 | 289 | /* APU = SC or SC/2 = 125/62.5 */ |
drivers/media/video/cx18/cx18-i2c.c
... | ... | @@ -304,7 +304,7 @@ |
304 | 304 | return cx18_gpio(cx, cmd, arg); |
305 | 305 | |
306 | 306 | if (hw == CX18_HW_CX23418) |
307 | - return cx18_av_cmd(cx, cmd, arg); | |
307 | + return v4l2_subdev_command(cx->sd_av, cmd, arg); | |
308 | 308 | |
309 | 309 | addr = cx18_i2c_hw_addr(cx, hw); |
310 | 310 | if (addr < 0) { |
... | ... | @@ -322,7 +322,7 @@ |
322 | 322 | CX18_ERR("adapter is not set\n"); |
323 | 323 | return; |
324 | 324 | } |
325 | - cx18_av_cmd(cx, cmd, arg); | |
325 | + v4l2_subdev_command(cx->sd_av, cmd, arg); | |
326 | 326 | i2c_clients_command(&cx->i2c_adap[0], cmd, arg); |
327 | 327 | i2c_clients_command(&cx->i2c_adap[1], cmd, arg); |
328 | 328 | if (cx->hw_flags & CX18_HW_GPIO) |
drivers/media/video/cx18/cx18-ioctl.c
... | ... | @@ -208,7 +208,7 @@ |
208 | 208 | * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in |
209 | 209 | * fmt->fmt.sliced under valid calling conditions |
210 | 210 | */ |
211 | - if (cx18_av_cmd(cx, VIDIOC_G_FMT, fmt)) | |
211 | + if (v4l2_subdev_call(cx->sd_av, video, g_fmt, fmt)) | |
212 | 212 | return -EINVAL; |
213 | 213 | |
214 | 214 | /* Ensure V4L2 spec compliant output */ |
... | ... | @@ -295,7 +295,7 @@ |
295 | 295 | |
296 | 296 | cx->params.width = w; |
297 | 297 | cx->params.height = h; |
298 | - cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | |
298 | + v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt); | |
299 | 299 | return cx18_g_fmt_vid_cap(file, fh, fmt); |
300 | 300 | } |
301 | 301 | |
... | ... | @@ -322,7 +322,7 @@ |
322 | 322 | * Note cx18_av_vbi_wipes out alot of the passed in fmt under valid |
323 | 323 | * calling conditions |
324 | 324 | */ |
325 | - ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | |
325 | + ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt); | |
326 | 326 | if (ret) |
327 | 327 | return ret; |
328 | 328 | |
... | ... | @@ -359,7 +359,7 @@ |
359 | 359 | * Note, cx18_av_vbi() wipes some "impossible" service lines in the |
360 | 360 | * passed in fmt->fmt.sliced under valid calling conditions |
361 | 361 | */ |
362 | - ret = cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | |
362 | + ret = v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt); | |
363 | 363 | if (ret) |
364 | 364 | return ret; |
365 | 365 | /* Store our current v4l2 sliced VBI settings */ |
... | ... | @@ -516,7 +516,8 @@ |
516 | 516 | |
517 | 517 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
518 | 518 | return -EINVAL; |
519 | - return cx18_av_cmd(cx, VIDIOC_S_CROP, crop); | |
519 | + CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); | |
520 | + return -EINVAL; | |
520 | 521 | } |
521 | 522 | |
522 | 523 | static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) |
... | ... | @@ -525,7 +526,8 @@ |
525 | 526 | |
526 | 527 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
527 | 528 | return -EINVAL; |
528 | - return cx18_av_cmd(cx, VIDIOC_G_CROP, crop); | |
529 | + CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); | |
530 | + return -EINVAL; | |
529 | 531 | } |
530 | 532 | |
531 | 533 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, |
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-vbi.c
... | ... | @@ -154,7 +154,7 @@ |
154 | 154 | if (p[0] != 0xff || p[1] || p[2] || p[3] != eav) |
155 | 155 | continue; |
156 | 156 | vbi.p = p + 4; |
157 | - cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi); | |
157 | + v4l2_subdev_call(cx->sd_av, video, decode_vbi_line, &vbi); | |
158 | 158 | if (vbi.type) { |
159 | 159 | cx->vbi.sliced_data[line].id = vbi.type; |
160 | 160 | cx->vbi.sliced_data[line].field = vbi.is_second_field; |
drivers/media/video/cx18/cx18-video.c
include/media/v4l2-chip-ident.h
... | ... | @@ -64,7 +64,8 @@ |
64 | 64 | /* module saa7146: reserved range 300-309 */ |
65 | 65 | V4L2_IDENT_SAA7146 = 300, |
66 | 66 | |
67 | - /* Conexant MPEG encoder/decoders: reserved range 410-420 */ | |
67 | + /* Conexant MPEG encoder/decoders: reserved range 400-420 */ | |
68 | + V4L2_IDENT_CX23418_843 = 403, /* Integrated A/V Decoder on the '418 */ | |
68 | 69 | V4L2_IDENT_CX23415 = 415, |
69 | 70 | V4L2_IDENT_CX23416 = 416, |
70 | 71 | V4L2_IDENT_CX23418 = 418, |