aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-11-02 08:59:04 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-29 14:53:26 -0500
commitced07371d931884c9c89b66bfe951ea0148a8d08 (patch)
tree607a83c66ff40f43bb9ce28839cb5ff9c35736a5
parent48fc6bb37ba8ee278a8cc647a4ef2bf529b519dd (diff)
V4L/DVB (9512): cx18: Fix write retries for registers that always change - part 3.
cx18: Fix write retries for registers that always change - part 3. Fix the io for the rest of the registers that will often not read back the value just written. Modified register readback checks to make sure the intended effect was achieved without constantly rewriting the registers. The one outstanding register remaining is 0xc72014 CX18_AUDIO_ENABLE, whose behavior on writes I have yet to determine. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c41
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c95
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h3
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c18
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c60
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c24
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c24
7 files changed, 185 insertions, 80 deletions
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
index 0b55837880a7..486cad0c26e0 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -215,12 +215,15 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq)
215void cx18_av_audio_set_path(struct cx18 *cx) 215void cx18_av_audio_set_path(struct cx18 *cx)
216{ 216{
217 struct cx18_av_state *state = &cx->av_state; 217 struct cx18_av_state *state = &cx->av_state;
218 u8 v;
218 219
219 /* stop microcontroller */ 220 /* stop microcontroller */
220 cx18_av_and_or(cx, 0x803, ~0x10, 0); 221 v = cx18_av_read(cx, 0x803) & ~0x10;
222 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
221 223
222 /* assert soft reset */ 224 /* assert soft reset */
223 cx18_av_and_or(cx, 0x810, ~0x1, 0x01); 225 v = cx18_av_read(cx, 0x810) | 0x01;
226 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
224 227
225 /* Mute everything to prevent the PFFT! */ 228 /* Mute everything to prevent the PFFT! */
226 cx18_av_write(cx, 0x8d3, 0x1f); 229 cx18_av_write(cx, 0x8d3, 0x1f);
@@ -240,12 +243,14 @@ void cx18_av_audio_set_path(struct cx18 *cx)
240 set_audclk_freq(cx, state->audclk_freq); 243 set_audclk_freq(cx, state->audclk_freq);
241 244
242 /* deassert soft reset */ 245 /* deassert soft reset */
243 cx18_av_and_or(cx, 0x810, ~0x1, 0x00); 246 v = cx18_av_read(cx, 0x810) & ~0x01;
247 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
244 248
245 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { 249 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
246 /* When the microcontroller detects the 250 /* When the microcontroller detects the
247 * audio format, it will unmute the lines */ 251 * audio format, it will unmute the lines */
248 cx18_av_and_or(cx, 0x803, ~0x10, 0x10); 252 v = cx18_av_read(cx, 0x803) | 0x10;
253 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
249 } 254 }
250} 255}
251 256
@@ -347,19 +352,23 @@ static int get_mute(struct cx18 *cx)
347static void set_mute(struct cx18 *cx, int mute) 352static void set_mute(struct cx18 *cx, int mute)
348{ 353{
349 struct cx18_av_state *state = &cx->av_state; 354 struct cx18_av_state *state = &cx->av_state;
355 u8 v;
350 356
351 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { 357 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
352 /* Must turn off microcontroller in order to mute sound. 358 /* Must turn off microcontroller in order to mute sound.
353 * Not sure if this is the best method, but it does work. 359 * Not sure if this is the best method, but it does work.
354 * If the microcontroller is running, then it will undo any 360 * If the microcontroller is running, then it will undo any
355 * changes to the mute register. */ 361 * changes to the mute register. */
362 v = cx18_av_read(cx, 0x803);
356 if (mute) { 363 if (mute) {
357 /* disable microcontroller */ 364 /* disable microcontroller */
358 cx18_av_and_or(cx, 0x803, ~0x10, 0x00); 365 v &= ~0x10;
366 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
359 cx18_av_write(cx, 0x8d3, 0x1f); 367 cx18_av_write(cx, 0x8d3, 0x1f);
360 } else { 368 } else {
361 /* enable microcontroller */ 369 /* enable microcontroller */
362 cx18_av_and_or(cx, 0x803, ~0x10, 0x10); 370 v |= 0x10;
371 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
363 } 372 }
364 } else { 373 } else {
365 /* SRC1_MUTE_EN */ 374 /* SRC1_MUTE_EN */
@@ -375,16 +384,26 @@ int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
375 384
376 switch (cmd) { 385 switch (cmd) {
377 case VIDIOC_INT_AUDIO_CLOCK_FREQ: 386 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
387 {
388 u8 v;
378 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { 389 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
379 cx18_av_and_or(cx, 0x803, ~0x10, 0); 390 v = cx18_av_read(cx, 0x803) & ~0x10;
391 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
380 cx18_av_write(cx, 0x8d3, 0x1f); 392 cx18_av_write(cx, 0x8d3, 0x1f);
381 } 393 }
382 cx18_av_and_or(cx, 0x810, ~0x1, 1); 394 v = cx18_av_read(cx, 0x810) | 0x1;
395 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
396
383 retval = set_audclk_freq(cx, *(u32 *)arg); 397 retval = set_audclk_freq(cx, *(u32 *)arg);
384 cx18_av_and_or(cx, 0x810, ~0x1, 0); 398
385 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) 399 v = cx18_av_read(cx, 0x810) & ~0x1;
386 cx18_av_and_or(cx, 0x803, ~0x10, 0x10); 400 cx18_av_write_expect(cx, 0x810, v, v, 0x0f);
401 if (state->aud_input > CX18_AV_AUDIO_SERIAL2) {
402 v = cx18_av_read(cx, 0x803) | 0x10;
403 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
404 }
387 return retval; 405 return retval;
406 }
388 407
389 case VIDIOC_G_CTRL: 408 case VIDIOC_G_CTRL:
390 switch (ctrl->id) { 409 switch (ctrl->id) {
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 73f5141a42d1..5c079e35e611 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -36,12 +36,31 @@ int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
36 return 0; 36 return 0;
37} 37}
38 38
39int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask)
40{
41 u32 reg = 0xc40000 + (addr & ~3);
42 int shift = (addr & 3) * 8;
43 u32 x = cx18_read_reg(cx, reg);
44
45 x = (x & ~((u32)0xff << shift)) | ((u32)value << shift);
46 cx18_write_reg_expect(cx, x, reg,
47 ((u32)eval << shift), ((u32)mask << shift));
48 return 0;
49}
50
39int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) 51int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
40{ 52{
41 cx18_write_reg(cx, value, 0xc40000 + addr); 53 cx18_write_reg(cx, value, 0xc40000 + addr);
42 return 0; 54 return 0;
43} 55}
44 56
57int
58cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask)
59{
60 cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask);
61 return 0;
62}
63
45int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) 64int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value)
46{ 65{
47 cx18_write_reg_noretry(cx, value, 0xc40000 + addr); 66 cx18_write_reg_noretry(cx, value, 0xc40000 + addr);
@@ -98,14 +117,16 @@ static void cx18_av_initialize(struct cx18 *cx)
98 117
99 cx18_av_loadfw(cx); 118 cx18_av_loadfw(cx);
100 /* Stop 8051 code execution */ 119 /* Stop 8051 code execution */
101 cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); 120 cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000,
121 0x03000000, 0x13000000);
102 122
103 /* initallize the PLL by toggling sleep bit */ 123 /* initallize the PLL by toggling sleep bit */
104 v = cx18_av_read4(cx, CXADEC_HOST_REG1); 124 v = cx18_av_read4(cx, CXADEC_HOST_REG1);
105 /* enable sleep mode */ 125 /* enable sleep mode - register appears to be read only... */
106 cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); 126 cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe);
107 /* disable sleep mode */ 127 /* disable sleep mode */
108 cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); 128 cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe,
129 v & 0xfffe, 0xffff);
109 130
110 /* initialize DLLs */ 131 /* initialize DLLs */
111 v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; 132 v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
@@ -125,9 +146,10 @@ static void cx18_av_initialize(struct cx18 *cx)
125 146
126 v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; 147 v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
127 /* enable TUNE_FIL_RST */ 148 /* enable TUNE_FIL_RST */
128 cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); 149 cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F);
129 /* disable TUNE_FIL_RST */ 150 /* disable TUNE_FIL_RST */
130 cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); 151 cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3,
152 v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F);
131 153
132 /* enable 656 output */ 154 /* enable 656 output */
133 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); 155 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
@@ -324,6 +346,7 @@ static void input_change(struct cx18 *cx)
324{ 346{
325 struct cx18_av_state *state = &cx->av_state; 347 struct cx18_av_state *state = &cx->av_state;
326 v4l2_std_id std = state->std; 348 v4l2_std_id std = state->std;
349 u8 v;
327 350
328 /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ 351 /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
329 cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); 352 cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
@@ -333,31 +356,34 @@ static void input_change(struct cx18 *cx)
333 if (std & V4L2_STD_525_60) { 356 if (std & V4L2_STD_525_60) {
334 if (std == V4L2_STD_NTSC_M_JP) { 357 if (std == V4L2_STD_NTSC_M_JP) {
335 /* Japan uses EIAJ audio standard */ 358 /* Japan uses EIAJ audio standard */
336 cx18_av_write(cx, 0x808, 0xf7); 359 cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff);
337 cx18_av_write(cx, 0x80b, 0x02); 360 cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f);
338 } else if (std == V4L2_STD_NTSC_M_KR) { 361 } else if (std == V4L2_STD_NTSC_M_KR) {
339 /* South Korea uses A2 audio standard */ 362 /* South Korea uses A2 audio standard */
340 cx18_av_write(cx, 0x808, 0xf8); 363 cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff);
341 cx18_av_write(cx, 0x80b, 0x03); 364 cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
342 } else { 365 } else {
343 /* Others use the BTSC audio standard */ 366 /* Others use the BTSC audio standard */
344 cx18_av_write(cx, 0x808, 0xf6); 367 cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff);
345 cx18_av_write(cx, 0x80b, 0x01); 368 cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f);
346 } 369 }
347 } else if (std & V4L2_STD_PAL) { 370 } else if (std & V4L2_STD_PAL) {
348 /* Follow tuner change procedure for PAL */ 371 /* Follow tuner change procedure for PAL */
349 cx18_av_write(cx, 0x808, 0xff); 372 cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
350 cx18_av_write(cx, 0x80b, 0x03); 373 cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
351 } else if (std & V4L2_STD_SECAM) { 374 } else if (std & V4L2_STD_SECAM) {
352 /* Select autodetect for SECAM */ 375 /* Select autodetect for SECAM */
353 cx18_av_write(cx, 0x808, 0xff); 376 cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff);
354 cx18_av_write(cx, 0x80b, 0x03); 377 cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f);
355 } 378 }
356 379
357 if (cx18_av_read(cx, 0x803) & 0x10) { 380 v = cx18_av_read(cx, 0x803);
381 if (v & 0x10) {
358 /* restart audio decoder microcontroller */ 382 /* restart audio decoder microcontroller */
359 cx18_av_and_or(cx, 0x803, ~0x10, 0x00); 383 v &= ~0x10;
360 cx18_av_and_or(cx, 0x803, ~0x10, 0x10); 384 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
385 v |= 0x10;
386 cx18_av_write_expect(cx, 0x803, v, v, 0x1f);
361 } 387 }
362} 388}
363 389
@@ -368,6 +394,7 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
368 u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && 394 u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
369 vid_input <= CX18_AV_COMPOSITE8); 395 vid_input <= CX18_AV_COMPOSITE8);
370 u8 reg; 396 u8 reg;
397 u8 v;
371 398
372 CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", 399 CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
373 vid_input, aud_input); 400 vid_input, aud_input);
@@ -413,16 +440,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
413 return -EINVAL; 440 return -EINVAL;
414 } 441 }
415 442
416 cx18_av_write(cx, 0x103, reg); 443 cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
417 /* Set INPUT_MODE to Composite (0) or S-Video (1) */ 444 /* Set INPUT_MODE to Composite (0) or S-Video (1) */
418 cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); 445 cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
446
419 /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ 447 /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
420 cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); 448 v = cx18_av_read(cx, 0x102);
449 if (reg & 0x80)
450 v &= ~0x2;
451 else
452 v |= 0x2;
421 /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ 453 /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
422 if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) 454 if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
423 cx18_av_and_or(cx, 0x102, ~0x4, 4); 455 v |= 0x4;
424 else 456 else
425 cx18_av_and_or(cx, 0x102, ~0x4, 0); 457 v &= ~0x4;
458 cx18_av_write_expect(cx, 0x102, v, v, 0x17);
459
426 /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ 460 /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
427 461
428 state->vid_input = vid_input; 462 state->vid_input = vid_input;
@@ -799,40 +833,47 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
799 } 833 }
800 834
801 case VIDIOC_S_TUNER: 835 case VIDIOC_S_TUNER:
836 {
837 u8 v;
838
802 if (state->radio) 839 if (state->radio)
803 break; 840 break;
804 841
842 v = cx18_av_read(cx, 0x809);
843 v &= ~0xf;
844
805 switch (vt->audmode) { 845 switch (vt->audmode) {
806 case V4L2_TUNER_MODE_MONO: 846 case V4L2_TUNER_MODE_MONO:
807 /* mono -> mono 847 /* mono -> mono
808 stereo -> mono 848 stereo -> mono
809 bilingual -> lang1 */ 849 bilingual -> lang1 */
810 cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
811 break; 850 break;
812 case V4L2_TUNER_MODE_STEREO: 851 case V4L2_TUNER_MODE_STEREO:
813 case V4L2_TUNER_MODE_LANG1: 852 case V4L2_TUNER_MODE_LANG1:
814 /* mono -> mono 853 /* mono -> mono
815 stereo -> stereo 854 stereo -> stereo
816 bilingual -> lang1 */ 855 bilingual -> lang1 */
817 cx18_av_and_or(cx, 0x809, ~0xf, 0x04); 856 v |= 0x4;
818 break; 857 break;
819 case V4L2_TUNER_MODE_LANG1_LANG2: 858 case V4L2_TUNER_MODE_LANG1_LANG2:
820 /* mono -> mono 859 /* mono -> mono
821 stereo -> stereo 860 stereo -> stereo
822 bilingual -> lang1/lang2 */ 861 bilingual -> lang1/lang2 */
823 cx18_av_and_or(cx, 0x809, ~0xf, 0x07); 862 v |= 0x7;
824 break; 863 break;
825 case V4L2_TUNER_MODE_LANG2: 864 case V4L2_TUNER_MODE_LANG2:
826 /* mono -> mono 865 /* mono -> mono
827 stereo -> stereo 866 stereo -> stereo
828 bilingual -> lang2 */ 867 bilingual -> lang2 */
829 cx18_av_and_or(cx, 0x809, ~0xf, 0x01); 868 v |= 0x1;
830 break; 869 break;
831 default: 870 default:
832 return -EINVAL; 871 return -EINVAL;
833 } 872 }
873 cx18_av_write_expect(cx, 0x809, v, v, 0xff);
834 state->audmode = vt->audmode; 874 state->audmode = vt->audmode;
835 break; 875 break;
876 }
836 877
837 case VIDIOC_G_FMT: 878 case VIDIOC_G_FMT:
838 return get_v4lfmt(cx, (struct v4l2_format *)arg); 879 return get_v4lfmt(cx, (struct v4l2_format *)arg);
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index b67d8df20cc6..a07988c6f5cd 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -302,6 +302,9 @@ struct cx18_av_state {
302int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); 302int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
303int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); 303int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
304int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); 304int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value);
305int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask);
306int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval,
307 u32 mask);
305u8 cx18_av_read(struct cx18 *cx, u16 addr); 308u8 cx18_av_read(struct cx18 *cx, u16 addr);
306u32 cx18_av_read4(struct cx18 *cx, u16 addr); 309u32 cx18_av_read4(struct cx18 *cx, u16 addr);
307u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr); 310u32 cx18_av_read4_noretry(struct cx18 *cx, u16 addr);
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index 522a035b2e8f..caa748a1add1 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -43,11 +43,13 @@ int cx18_av_loadfw(struct cx18 *cx)
43 /* The firmware load often has byte errors, so allow for several 43 /* The firmware load often has byte errors, so allow for several
44 retries, both at byte level and at the firmware load level. */ 44 retries, both at byte level and at the firmware load level. */
45 while (retries1 < 5) { 45 while (retries1 < 5) {
46 cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); 46 cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000,
47 cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); 47 0x00008430, 0xffffffff); /* cx25843 */
48 cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff);
48 49
49 /* Reset the Mako core (Register is undocumented.) */ 50 /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */
50 cx18_av_write4(cx, 0x8100, 0x00010000); 51 cx18_av_write4_expect(cx, 0x8100, 0x00010000,
52 0x00008430, 0xffffffff); /* cx25843 */
51 53
52 /* Put the 8051 in reset and enable firmware upload */ 54 /* Put the 8051 in reset and enable firmware upload */
53 cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); 55 cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000);
@@ -93,7 +95,8 @@ int cx18_av_loadfw(struct cx18 *cx)
93 return -EIO; 95 return -EIO;
94 } 96 }
95 97
96 cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); 98 cx18_av_write4_expect(cx, CXADEC_DL_CTL,
99 0x13000000 | fw->size, 0x13000000, 0x13000000);
97 100
98 /* Output to the 416 */ 101 /* Output to the 416 */
99 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); 102 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
@@ -118,7 +121,8 @@ int cx18_av_loadfw(struct cx18 *cx)
118 passthrough */ 121 passthrough */
119 cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); 122 cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
120 123
121 cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); 124 cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6,
125 0x3F00FFFF);
122 /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ 126 /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
123 127
124 /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ 128 /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
@@ -136,7 +140,7 @@ int cx18_av_loadfw(struct cx18 *cx)
136 v |= 0xFF; /* Auto by default */ 140 v |= 0xFF; /* Auto by default */
137 v |= 0x400; /* Stereo by default */ 141 v |= 0x400; /* Stereo by default */
138 v |= 0x14000000; 142 v |= 0x14000000;
139 cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); 143 cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
140 144
141 release_firmware(fw); 145 release_firmware(fw);
142 146
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 51534428cd00..7a7c89032caa 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -200,8 +200,10 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx)
200void cx18_halt_firmware(struct cx18 *cx) 200void cx18_halt_firmware(struct cx18 *cx)
201{ 201{
202 CX18_DEBUG_INFO("Preparing for firmware halt.\n"); 202 CX18_DEBUG_INFO("Preparing for firmware halt.\n");
203 cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ 203 cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
204 cx18_write_reg(cx, 0x00020002, CX18_ADEC_CONTROL); 204 0x0000000F, 0x000F000F);
205 cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL,
206 0x00000002, 0x00020002);
205} 207}
206 208
207void cx18_init_power(struct cx18 *cx, int lowpwr) 209void cx18_init_power(struct cx18 *cx, int lowpwr)
@@ -211,7 +213,8 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
211 cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); 213 cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN);
212 214
213 /* ADEC out of sleep */ 215 /* ADEC out of sleep */
214 cx18_write_reg(cx, 0x00020000, CX18_ADEC_CONTROL); 216 cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL,
217 0x00000000, 0x00020002);
215 218
216 /* The fast clock is at 200/245 MHz */ 219 /* The fast clock is at 200/245 MHz */
217 cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); 220 cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
@@ -248,22 +251,34 @@ void cx18_init_power(struct cx18 *cx, int lowpwr)
248 /* VFC = disabled */ 251 /* VFC = disabled */
249 /* USB = disabled */ 252 /* USB = disabled */
250 253
251 cx18_write_reg(cx, lowpwr ? 0xFFFF0020 : 0x00060004, 254 if (lowpwr) {
252 CX18_CLOCK_SELECT1); 255 cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1,
253 cx18_write_reg(cx, lowpwr ? 0xFFFF0004 : 0x00060006, 256 0x00000020, 0xFFFFFFFF);
254 CX18_CLOCK_SELECT2); 257 cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2,
255 258 0x00000004, 0xFFFFFFFF);
256 cx18_write_reg(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1); 259 } else {
257 cx18_write_reg(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2); 260 /* This doesn't explicitly set every clock select */
261 cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1,
262 0x00000004, 0x00060006);
263 cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2,
264 0x00000006, 0x00060006);
265 }
258 266
259 cx18_write_reg(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1); 267 cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1,
260 cx18_write_reg(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2); 268 0x00000002, 0xFFFFFFFF);
269 cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2,
270 0x00000104, 0xFFFFFFFF);
271 cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1,
272 0x00009026, 0xFFFFFFFF);
273 cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2,
274 0x00003105, 0xFFFFFFFF);
261} 275}
262 276
263void cx18_init_memory(struct cx18 *cx) 277void cx18_init_memory(struct cx18 *cx)
264{ 278{
265 cx18_msleep_timeout(10, 0); 279 cx18_msleep_timeout(10, 0);
266 cx18_write_reg(cx, 0x10000, CX18_DDR_SOFT_RESET); 280 cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET,
281 0x00000000, 0x00010001);
267 cx18_msleep_timeout(10, 0); 282 cx18_msleep_timeout(10, 0);
268 283
269 cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); 284 cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
@@ -282,13 +297,15 @@ void cx18_init_memory(struct cx18 *cx)
282 297
283 cx18_msleep_timeout(10, 0); 298 cx18_msleep_timeout(10, 0);
284 299
285 cx18_write_reg(cx, 0x20000, CX18_DDR_SOFT_RESET); 300 cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET,
301 0x00000000, 0x00020002);
286 cx18_msleep_timeout(10, 0); 302 cx18_msleep_timeout(10, 0);
287 303
288 /* use power-down mode when idle */ 304 /* use power-down mode when idle */
289 cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); 305 cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG);
290 306
291 cx18_write_reg(cx, 0x10001, CX18_REG_BUS_TIMEOUT_EN); 307 cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN,
308 0x00000001, 0x00010001);
292 309
293 cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); 310 cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7);
294 cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); 311 cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR);
@@ -310,7 +327,9 @@ int cx18_firmware_init(struct cx18 *cx)
310 /* Allow chip to control CLKRUN */ 327 /* Allow chip to control CLKRUN */
311 cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); 328 cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK);
312 329
313 cx18_write_reg(cx, 0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ 330 /* Stop the firmware */
331 cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET,
332 0x0000000F, 0x000F000F);
314 333
315 cx18_msleep_timeout(1, 0); 334 cx18_msleep_timeout(1, 0);
316 335
@@ -325,7 +344,8 @@ int cx18_firmware_init(struct cx18 *cx)
325 cx18_write_enc(cx, 0xE51FF004, 0); 344 cx18_write_enc(cx, 0xE51FF004, 0);
326 cx18_write_enc(cx, 0xa00000, 4); /* todo: not hardcoded */ 345 cx18_write_enc(cx, 0xa00000, 4); /* todo: not hardcoded */
327 /* Start APU */ 346 /* Start APU */
328 cx18_write_reg(cx, 0x00010000, CX18_PROC_SOFT_RESET); 347 cx18_write_reg_expect(cx, 0x00010000, CX18_PROC_SOFT_RESET,
348 0x00000000, 0x00010001);
329 cx18_msleep_timeout(500, 0); 349 cx18_msleep_timeout(500, 0);
330 350
331 sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", 351 sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
@@ -335,7 +355,9 @@ int cx18_firmware_init(struct cx18 *cx)
335 int retries = 0; 355 int retries = 0;
336 356
337 /* start the CPU */ 357 /* start the CPU */
338 cx18_write_reg(cx, 0x00080000, CX18_PROC_SOFT_RESET); 358 cx18_write_reg_expect(cx,
359 0x00080000, CX18_PROC_SOFT_RESET,
360 0x00000000, 0x00080008);
339 while (retries++ < 50) { /* Loop for max 500mS */ 361 while (retries++ < 50) { /* Loop for max 500mS */
340 if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) 362 if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET)
341 & 1) == 0) 363 & 1) == 0)
@@ -352,6 +374,6 @@ int cx18_firmware_init(struct cx18 *cx)
352 return -EIO; 374 return -EIO;
353 } 375 }
354 /* initialize GPIO */ 376 /* initialize GPIO */
355 cx18_write_reg(cx, 0x14001400, 0xC78110); 377 cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
356 return 0; 378 return 0;
357} 379}
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 0e560421989e..17b7a32fcc31 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -47,15 +47,21 @@
47 47
48static void gpio_write(struct cx18 *cx) 48static void gpio_write(struct cx18 *cx)
49{ 49{
50 u32 dir = cx->gpio_dir; 50 u32 dir_lo = cx->gpio_dir & 0xffff;
51 u32 val = cx->gpio_val; 51 u32 val_lo = cx->gpio_val & 0xffff;
52 52 u32 dir_hi = cx->gpio_dir >> 16;
53 cx18_write_reg(cx, (dir & 0xffff) << 16, CX18_REG_GPIO_DIR1); 53 u32 val_hi = cx->gpio_val >> 16;
54 cx18_write_reg(cx, ((dir & 0xffff) << 16) | (val & 0xffff), 54
55 CX18_REG_GPIO_OUT1); 55 cx18_write_reg_expect(cx, dir_lo << 16,
56 cx18_write_reg(cx, dir & 0xffff0000, CX18_REG_GPIO_DIR2); 56 CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo);
57 cx18_write_reg_sync(cx, (dir & 0xffff0000) | ((val & 0xffff0000) >> 16), 57 cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo,
58 CX18_REG_GPIO_OUT2); 58 CX18_REG_GPIO_OUT1, val_lo, dir_lo);
59 cx18_write_reg_expect(cx, dir_hi << 16,
60 CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi);
61 cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi,
62 CX18_REG_GPIO_OUT2, val_hi, dir_hi);
63 if (!cx18_retry_mmio)
64 (void) cx18_read_reg(cx, CX18_REG_GPIO_OUT2); /* sync */
59} 65}
60 66
61void cx18_reset_i2c_slaves_gpio(struct cx18 *cx) 67void cx18_reset_i2c_slaves_gpio(struct cx18 *cx)
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index aa09e557b195..824efbecb34c 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -27,6 +27,7 @@
27#include "cx18-gpio.h" 27#include "cx18-gpio.h"
28#include "cx18-av-core.h" 28#include "cx18-av-core.h"
29#include "cx18-i2c.h" 29#include "cx18-i2c.h"
30#include "cx18-irq.h"
30 31
31#define CX18_REG_I2C_1_WR 0xf15000 32#define CX18_REG_I2C_1_WR 0xf15000
32#define CX18_REG_I2C_1_RD 0xf15008 33#define CX18_REG_I2C_1_RD 0xf15008
@@ -396,22 +397,31 @@ int init_cx18_i2c(struct cx18 *cx)
396 if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { 397 if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) {
397 /* Reset/Unreset I2C hardware block */ 398 /* Reset/Unreset I2C hardware block */
398 /* Clock select 220MHz */ 399 /* Clock select 220MHz */
399 cx18_write_reg(cx, 0x10000000, 0xc71004); 400 cx18_write_reg_expect(cx, 0x10000000, 0xc71004,
401 0x00000000, 0x10001000);
400 /* Clock Enable */ 402 /* Clock Enable */
401 cx18_write_reg_sync(cx, 0x10001000, 0xc71024); 403 cx18_write_reg_expect(cx, 0x10001000, 0xc71024,
404 0x00001000, 0x10001000);
402 } 405 }
403 /* courtesy of Steven Toth <stoth@hauppauge.com> */ 406 /* courtesy of Steven Toth <stoth@hauppauge.com> */
404 cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c); 407 cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
408 if (!cx18_retry_mmio)
409 (void) cx18_read_reg(cx, 0xc7001c); /* sync */
405 mdelay(10); 410 mdelay(10);
406 cx18_write_reg_sync(cx, 0x00c000c0, 0xc7001c); 411 cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0);
412 if (!cx18_retry_mmio)
413 (void) cx18_read_reg(cx, 0xc7001c); /* sync */
407 mdelay(10); 414 mdelay(10);
408 cx18_write_reg_sync(cx, 0x00c00000, 0xc7001c); 415 cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0);
416 if (!cx18_retry_mmio)
417 (void) cx18_read_reg(cx, 0xc7001c); /* sync */
409 mdelay(10); 418 mdelay(10);
410 419
411 /* Set to edge-triggered intrs. */ 420 /* Set to edge-triggered intrs. */
412 cx18_write_reg_sync(cx, 0x00c00000, 0xc730c8); 421 cx18_write_reg(cx, 0x00c00000, 0xc730c8);
413 /* Clear any stale intrs */ 422 /* Clear any stale intrs */
414 cx18_write_reg_sync(cx, 0x00c00000, 0xc730c4); 423 cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS,
424 ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT);
415 425
416 /* Hw I2C1 Clock Freq ~100kHz */ 426 /* Hw I2C1 Clock Freq ~100kHz */
417 cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); 427 cx18_write_reg_sync(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR);