diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/media/video/cx25840 | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/media/video/cx25840')
-rw-r--r-- | drivers/media/video/cx25840/cx25840-audio.c | 463 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.c | 372 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-core.h | 22 | ||||
-rw-r--r-- | drivers/media/video/cx25840/cx25840-firmware.c | 10 |
4 files changed, 654 insertions, 213 deletions
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c index 2f846f5e0f9f..45608d50529c 100644 --- a/drivers/media/video/cx25840/cx25840-audio.c +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -23,87 +23,137 @@ | |||
23 | 23 | ||
24 | #include "cx25840-core.h" | 24 | #include "cx25840-core.h" |
25 | 25 | ||
26 | static int set_audclk_freq(struct i2c_client *client, u32 freq) | 26 | /* |
27 | * Note: The PLL and SRC parameters are based on a reference frequency that | ||
28 | * would ideally be: | ||
29 | * | ||
30 | * NTSC Color subcarrier freq * 8 = 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz | ||
31 | * | ||
32 | * However, it's not the exact reference frequency that matters, only that the | ||
33 | * firmware and modules that comprise the driver for a particular board all | ||
34 | * use the same value (close to the ideal value). | ||
35 | * | ||
36 | * Comments below will note which reference frequency is assumed for various | ||
37 | * parameters. They will usually be one of | ||
38 | * | ||
39 | * ref_freq = 28.636360 MHz | ||
40 | * or | ||
41 | * ref_freq = 28.636363 MHz | ||
42 | */ | ||
43 | |||
44 | static int cx25840_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
27 | { | 45 | { |
28 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 46 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
29 | 47 | ||
30 | if (freq != 32000 && freq != 44100 && freq != 48000) | ||
31 | return -EINVAL; | ||
32 | |||
33 | /* common for all inputs and rates */ | ||
34 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ | ||
35 | if (!state->is_cx23885 && !state->is_cx231xx) | ||
36 | cx25840_write(client, 0x127, 0x50); | ||
37 | |||
38 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | 48 | if (state->aud_input != CX25840_AUDIO_SERIAL) { |
39 | switch (freq) { | 49 | switch (freq) { |
40 | case 32000: | 50 | case 32000: |
41 | if (state->is_cx23885) { | 51 | /* |
42 | /* We don't have register values | 52 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
43 | * so avoid destroying registers. */ | 53 | * AUX_PLL Integer = 0x06, AUX PLL Post Divider = 0x10 |
44 | break; | 54 | */ |
45 | } | 55 | cx25840_write4(client, 0x108, 0x1006040f); |
46 | 56 | ||
47 | if (!state->is_cx231xx) { | 57 | /* |
48 | /* VID_PLL and AUX_PLL */ | 58 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe |
49 | cx25840_write4(client, 0x108, 0x1006040f); | 59 | * 28636360 * 0xf.15f17f0/4 = 108 MHz |
50 | 60 | * 432 MHz pre-postdivide | |
51 | /* AUX_PLL_FRAC */ | 61 | */ |
52 | cx25840_write4(client, 0x110, 0x01bb39ee); | 62 | |
53 | } | 63 | /* |
54 | 64 | * AUX_PLL Fraction = 0x1bb39ee | |
55 | if (state->is_cx25836) | 65 | * 28636363 * 0x6.dd9cf70/0x10 = 32000 * 384 |
66 | * 196.6 MHz pre-postdivide | ||
67 | * FIXME < 200 MHz is out of specified valid range | ||
68 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
69 | */ | ||
70 | cx25840_write4(client, 0x110, 0x01bb39ee); | ||
71 | |||
72 | /* | ||
73 | * SA_MCLK_SEL = 1 | ||
74 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
75 | */ | ||
76 | cx25840_write(client, 0x127, 0x50); | ||
77 | |||
78 | if (is_cx2583x(state)) | ||
56 | break; | 79 | break; |
57 | 80 | ||
58 | /* src3/4/6_ctl = 0x0801f77f */ | 81 | /* src3/4/6_ctl */ |
82 | /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ | ||
59 | cx25840_write4(client, 0x900, 0x0801f77f); | 83 | cx25840_write4(client, 0x900, 0x0801f77f); |
60 | cx25840_write4(client, 0x904, 0x0801f77f); | 84 | cx25840_write4(client, 0x904, 0x0801f77f); |
61 | cx25840_write4(client, 0x90c, 0x0801f77f); | 85 | cx25840_write4(client, 0x90c, 0x0801f77f); |
62 | break; | 86 | break; |
63 | 87 | ||
64 | case 44100: | 88 | case 44100: |
65 | if (state->is_cx23885) { | 89 | /* |
66 | /* We don't have register values | 90 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
67 | * so avoid destroying registers. */ | 91 | * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x10 |
92 | */ | ||
93 | cx25840_write4(client, 0x108, 0x1009040f); | ||
94 | |||
95 | /* | ||
96 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
97 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
98 | * 432 MHz pre-postdivide | ||
99 | */ | ||
100 | |||
101 | /* | ||
102 | * AUX_PLL Fraction = 0x0ec6bd6 | ||
103 | * 28636363 * 0x9.7635eb0/0x10 = 44100 * 384 | ||
104 | * 271 MHz pre-postdivide | ||
105 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
106 | */ | ||
107 | cx25840_write4(client, 0x110, 0x00ec6bd6); | ||
108 | |||
109 | /* | ||
110 | * SA_MCLK_SEL = 1 | ||
111 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
112 | */ | ||
113 | cx25840_write(client, 0x127, 0x50); | ||
114 | |||
115 | if (is_cx2583x(state)) | ||
68 | break; | 116 | break; |
69 | } | ||
70 | |||
71 | if (!state->is_cx231xx) { | ||
72 | /* VID_PLL and AUX_PLL */ | ||
73 | cx25840_write4(client, 0x108, 0x1009040f); | ||
74 | |||
75 | /* AUX_PLL_FRAC */ | ||
76 | cx25840_write4(client, 0x110, 0x00ec6bd6); | ||
77 | } | ||
78 | 117 | ||
79 | if (state->is_cx25836) | 118 | /* src3/4/6_ctl */ |
80 | break; | 119 | /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ |
81 | |||
82 | /* src3/4/6_ctl = 0x08016d59 */ | ||
83 | cx25840_write4(client, 0x900, 0x08016d59); | 120 | cx25840_write4(client, 0x900, 0x08016d59); |
84 | cx25840_write4(client, 0x904, 0x08016d59); | 121 | cx25840_write4(client, 0x904, 0x08016d59); |
85 | cx25840_write4(client, 0x90c, 0x08016d59); | 122 | cx25840_write4(client, 0x90c, 0x08016d59); |
86 | break; | 123 | break; |
87 | 124 | ||
88 | case 48000: | 125 | case 48000: |
89 | if (state->is_cx23885) { | 126 | /* |
90 | /* We don't have register values | 127 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
91 | * so avoid destroying registers. */ | 128 | * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x10 |
92 | break; | 129 | */ |
93 | } | 130 | cx25840_write4(client, 0x108, 0x100a040f); |
94 | 131 | ||
95 | if (!state->is_cx231xx) { | 132 | /* |
96 | /* VID_PLL and AUX_PLL */ | 133 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe |
97 | cx25840_write4(client, 0x108, 0x100a040f); | 134 | * 28636360 * 0xf.15f17f0/4 = 108 MHz |
98 | 135 | * 432 MHz pre-postdivide | |
99 | /* AUX_PLL_FRAC */ | 136 | */ |
100 | cx25840_write4(client, 0x110, 0x0098d6e5); | 137 | |
101 | } | 138 | /* |
102 | 139 | * AUX_PLL Fraction = 0x098d6e5 | |
103 | if (state->is_cx25836) | 140 | * 28636363 * 0xa.4c6b728/0x10 = 48000 * 384 |
141 | * 295 MHz pre-postdivide | ||
142 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
143 | */ | ||
144 | cx25840_write4(client, 0x110, 0x0098d6e5); | ||
145 | |||
146 | /* | ||
147 | * SA_MCLK_SEL = 1 | ||
148 | * SA_MCLK_DIV = 0x10 = 384/384 * AUX_PLL post dvivider | ||
149 | */ | ||
150 | cx25840_write(client, 0x127, 0x50); | ||
151 | |||
152 | if (is_cx2583x(state)) | ||
104 | break; | 153 | break; |
105 | 154 | ||
106 | /* src3/4/6_ctl = 0x08014faa */ | 155 | /* src3/4/6_ctl */ |
156 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
107 | cx25840_write4(client, 0x900, 0x08014faa); | 157 | cx25840_write4(client, 0x900, 0x08014faa); |
108 | cx25840_write4(client, 0x904, 0x08014faa); | 158 | cx25840_write4(client, 0x904, 0x08014faa); |
109 | cx25840_write4(client, 0x90c, 0x08014faa); | 159 | cx25840_write4(client, 0x90c, 0x08014faa); |
@@ -112,91 +162,249 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
112 | } else { | 162 | } else { |
113 | switch (freq) { | 163 | switch (freq) { |
114 | case 32000: | 164 | case 32000: |
115 | if (state->is_cx23885) { | 165 | /* |
116 | /* We don't have register values | 166 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
117 | * so avoid destroying registers. */ | 167 | * AUX_PLL Integer = 0x08, AUX PLL Post Divider = 0x1e |
118 | break; | 168 | */ |
119 | } | 169 | cx25840_write4(client, 0x108, 0x1e08040f); |
120 | 170 | ||
121 | if (!state->is_cx231xx) { | 171 | /* |
122 | /* VID_PLL and AUX_PLL */ | 172 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe |
123 | cx25840_write4(client, 0x108, 0x1e08040f); | 173 | * 28636360 * 0xf.15f17f0/4 = 108 MHz |
124 | 174 | * 432 MHz pre-postdivide | |
125 | /* AUX_PLL_FRAC */ | 175 | */ |
126 | cx25840_write4(client, 0x110, 0x012a0869); | 176 | |
127 | } | 177 | /* |
178 | * AUX_PLL Fraction = 0x12a0869 | ||
179 | * 28636363 * 0x8.9504348/0x1e = 32000 * 256 | ||
180 | * 246 MHz pre-postdivide | ||
181 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
182 | */ | ||
183 | cx25840_write4(client, 0x110, 0x012a0869); | ||
184 | |||
185 | /* | ||
186 | * SA_MCLK_SEL = 1 | ||
187 | * SA_MCLK_DIV = 0x14 = 256/384 * AUX_PLL post dvivider | ||
188 | */ | ||
189 | cx25840_write(client, 0x127, 0x54); | ||
128 | 190 | ||
129 | if (state->is_cx25836) | 191 | if (is_cx2583x(state)) |
130 | break; | 192 | break; |
131 | 193 | ||
132 | /* src1_ctl = 0x08010000 */ | 194 | /* src1_ctl */ |
195 | /* 0x1.0000 = 32000/32000 */ | ||
133 | cx25840_write4(client, 0x8f8, 0x08010000); | 196 | cx25840_write4(client, 0x8f8, 0x08010000); |
134 | 197 | ||
135 | /* src3/4/6_ctl = 0x08020000 */ | 198 | /* src3/4/6_ctl */ |
199 | /* 0x2.0000 = 2 * (32000/32000) */ | ||
136 | cx25840_write4(client, 0x900, 0x08020000); | 200 | cx25840_write4(client, 0x900, 0x08020000); |
137 | cx25840_write4(client, 0x904, 0x08020000); | 201 | cx25840_write4(client, 0x904, 0x08020000); |
138 | cx25840_write4(client, 0x90c, 0x08020000); | 202 | cx25840_write4(client, 0x90c, 0x08020000); |
139 | |||
140 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ | ||
141 | cx25840_write(client, 0x127, 0x54); | ||
142 | break; | 203 | break; |
143 | 204 | ||
144 | case 44100: | 205 | case 44100: |
145 | if (state->is_cx23885) { | 206 | /* |
146 | /* We don't have register values | 207 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
147 | * so avoid destroying registers. */ | 208 | * AUX_PLL Integer = 0x09, AUX PLL Post Divider = 0x18 |
148 | break; | 209 | */ |
149 | } | 210 | cx25840_write4(client, 0x108, 0x1809040f); |
150 | 211 | ||
151 | 212 | /* | |
152 | if (!state->is_cx231xx) { | 213 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe |
153 | /* VID_PLL and AUX_PLL */ | 214 | * 28636360 * 0xf.15f17f0/4 = 108 MHz |
154 | cx25840_write4(client, 0x108, 0x1809040f); | 215 | * 432 MHz pre-postdivide |
155 | 216 | */ | |
156 | /* AUX_PLL_FRAC */ | 217 | |
157 | cx25840_write4(client, 0x110, 0x00ec6bd6); | 218 | /* |
158 | } | 219 | * AUX_PLL Fraction = 0x0ec6bd6 |
159 | 220 | * 28636363 * 0x9.7635eb0/0x18 = 44100 * 256 | |
160 | if (state->is_cx25836) | 221 | * 271 MHz pre-postdivide |
222 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
223 | */ | ||
224 | cx25840_write4(client, 0x110, 0x00ec6bd6); | ||
225 | |||
226 | /* | ||
227 | * SA_MCLK_SEL = 1 | ||
228 | * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider | ||
229 | */ | ||
230 | cx25840_write(client, 0x127, 0x50); | ||
231 | |||
232 | if (is_cx2583x(state)) | ||
161 | break; | 233 | break; |
162 | 234 | ||
163 | /* src1_ctl = 0x08010000 */ | 235 | /* src1_ctl */ |
236 | /* 0x1.60cd = 44100/32000 */ | ||
164 | cx25840_write4(client, 0x8f8, 0x080160cd); | 237 | cx25840_write4(client, 0x8f8, 0x080160cd); |
165 | 238 | ||
166 | /* src3/4/6_ctl = 0x08020000 */ | 239 | /* src3/4/6_ctl */ |
240 | /* 0x1.7385 = 2 * (32000/44100) */ | ||
167 | cx25840_write4(client, 0x900, 0x08017385); | 241 | cx25840_write4(client, 0x900, 0x08017385); |
168 | cx25840_write4(client, 0x904, 0x08017385); | 242 | cx25840_write4(client, 0x904, 0x08017385); |
169 | cx25840_write4(client, 0x90c, 0x08017385); | 243 | cx25840_write4(client, 0x90c, 0x08017385); |
170 | break; | 244 | break; |
171 | 245 | ||
172 | case 48000: | 246 | case 48000: |
173 | if (!state->is_cx23885 && !state->is_cx231xx) { | 247 | /* |
174 | /* VID_PLL and AUX_PLL */ | 248 | * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 |
175 | cx25840_write4(client, 0x108, 0x180a040f); | 249 | * AUX_PLL Integer = 0x0a, AUX PLL Post Divider = 0x18 |
250 | */ | ||
251 | cx25840_write4(client, 0x108, 0x180a040f); | ||
252 | |||
253 | /* | ||
254 | * VID_PLL Fraction (register 0x10c) = 0x2be2fe | ||
255 | * 28636360 * 0xf.15f17f0/4 = 108 MHz | ||
256 | * 432 MHz pre-postdivide | ||
257 | */ | ||
258 | |||
259 | /* | ||
260 | * AUX_PLL Fraction = 0x098d6e5 | ||
261 | * 28636363 * 0xa.4c6b728/0x18 = 48000 * 256 | ||
262 | * 295 MHz pre-postdivide | ||
263 | * FIXME 28636363 ref_freq doesn't match VID PLL ref | ||
264 | */ | ||
265 | cx25840_write4(client, 0x110, 0x0098d6e5); | ||
266 | |||
267 | /* | ||
268 | * SA_MCLK_SEL = 1 | ||
269 | * SA_MCLK_DIV = 0x10 = 256/384 * AUX_PLL post dvivider | ||
270 | */ | ||
271 | cx25840_write(client, 0x127, 0x50); | ||
272 | |||
273 | if (is_cx2583x(state)) | ||
274 | break; | ||
176 | 275 | ||
177 | /* AUX_PLL_FRAC */ | 276 | /* src1_ctl */ |
178 | cx25840_write4(client, 0x110, 0x0098d6e5); | 277 | /* 0x1.8000 = 48000/32000 */ |
179 | } | 278 | cx25840_write4(client, 0x8f8, 0x08018000); |
180 | 279 | ||
181 | if (state->is_cx25836) | 280 | /* src3/4/6_ctl */ |
182 | break; | 281 | /* 0x1.5555 = 2 * (32000/48000) */ |
282 | cx25840_write4(client, 0x900, 0x08015555); | ||
283 | cx25840_write4(client, 0x904, 0x08015555); | ||
284 | cx25840_write4(client, 0x90c, 0x08015555); | ||
285 | break; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | state->audclk_freq = freq; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static inline int cx25836_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
295 | { | ||
296 | return cx25840_set_audclk_freq(client, freq); | ||
297 | } | ||
298 | |||
299 | static int cx23885_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
300 | { | ||
301 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
302 | |||
303 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
304 | switch (freq) { | ||
305 | case 32000: | ||
306 | case 44100: | ||
307 | case 48000: | ||
308 | /* We don't have register values | ||
309 | * so avoid destroying registers. */ | ||
310 | /* FIXME return -EINVAL; */ | ||
311 | break; | ||
312 | } | ||
313 | } else { | ||
314 | switch (freq) { | ||
315 | case 32000: | ||
316 | case 44100: | ||
317 | /* We don't have register values | ||
318 | * so avoid destroying registers. */ | ||
319 | /* FIXME return -EINVAL; */ | ||
320 | break; | ||
321 | |||
322 | case 48000: | ||
323 | /* src1_ctl */ | ||
324 | /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ | ||
325 | cx25840_write4(client, 0x8f8, 0x0801867c); | ||
326 | |||
327 | /* src3/4/6_ctl */ | ||
328 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
329 | cx25840_write4(client, 0x900, 0x08014faa); | ||
330 | cx25840_write4(client, 0x904, 0x08014faa); | ||
331 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
332 | break; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | state->audclk_freq = freq; | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int cx231xx_set_audclk_freq(struct i2c_client *client, u32 freq) | ||
342 | { | ||
343 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
344 | |||
345 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | ||
346 | switch (freq) { | ||
347 | case 32000: | ||
348 | /* src3/4/6_ctl */ | ||
349 | /* 0x1.f77f = (4 * 28636360/8 * 2/455) / 32000 */ | ||
350 | cx25840_write4(client, 0x900, 0x0801f77f); | ||
351 | cx25840_write4(client, 0x904, 0x0801f77f); | ||
352 | cx25840_write4(client, 0x90c, 0x0801f77f); | ||
353 | break; | ||
354 | |||
355 | case 44100: | ||
356 | /* src3/4/6_ctl */ | ||
357 | /* 0x1.6d59 = (4 * 28636360/8 * 2/455) / 44100 */ | ||
358 | cx25840_write4(client, 0x900, 0x08016d59); | ||
359 | cx25840_write4(client, 0x904, 0x08016d59); | ||
360 | cx25840_write4(client, 0x90c, 0x08016d59); | ||
361 | break; | ||
362 | |||
363 | case 48000: | ||
364 | /* src3/4/6_ctl */ | ||
365 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
366 | cx25840_write4(client, 0x900, 0x08014faa); | ||
367 | cx25840_write4(client, 0x904, 0x08014faa); | ||
368 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
369 | break; | ||
370 | } | ||
371 | } else { | ||
372 | switch (freq) { | ||
373 | /* FIXME These cases make different assumptions about audclk */ | ||
374 | case 32000: | ||
375 | /* src1_ctl */ | ||
376 | /* 0x1.0000 = 32000/32000 */ | ||
377 | cx25840_write4(client, 0x8f8, 0x08010000); | ||
183 | 378 | ||
184 | if (!state->is_cx23885 && !state->is_cx231xx) { | 379 | /* src3/4/6_ctl */ |
185 | /* src1_ctl */ | 380 | /* 0x2.0000 = 2 * (32000/32000) */ |
186 | cx25840_write4(client, 0x8f8, 0x08018000); | 381 | cx25840_write4(client, 0x900, 0x08020000); |
382 | cx25840_write4(client, 0x904, 0x08020000); | ||
383 | cx25840_write4(client, 0x90c, 0x08020000); | ||
384 | break; | ||
187 | 385 | ||
188 | /* src3/4/6_ctl */ | 386 | case 44100: |
189 | cx25840_write4(client, 0x900, 0x08015555); | 387 | /* src1_ctl */ |
190 | cx25840_write4(client, 0x904, 0x08015555); | 388 | /* 0x1.60cd = 44100/32000 */ |
191 | cx25840_write4(client, 0x90c, 0x08015555); | 389 | cx25840_write4(client, 0x8f8, 0x080160cd); |
192 | } else { | ||
193 | 390 | ||
194 | cx25840_write4(client, 0x8f8, 0x0801867c); | 391 | /* src3/4/6_ctl */ |
392 | /* 0x1.7385 = 2 * (32000/44100) */ | ||
393 | cx25840_write4(client, 0x900, 0x08017385); | ||
394 | cx25840_write4(client, 0x904, 0x08017385); | ||
395 | cx25840_write4(client, 0x90c, 0x08017385); | ||
396 | break; | ||
195 | 397 | ||
196 | cx25840_write4(client, 0x900, 0x08014faa); | 398 | case 48000: |
197 | cx25840_write4(client, 0x904, 0x08014faa); | 399 | /* src1_ctl */ |
198 | cx25840_write4(client, 0x90c, 0x08014faa); | 400 | /* 0x1.867c = 48000 / (2 * 28636360/8 * 2/455) */ |
199 | } | 401 | cx25840_write4(client, 0x8f8, 0x0801867c); |
402 | |||
403 | /* src3/4/6_ctl */ | ||
404 | /* 0x1.4faa = (4 * 28636360/8 * 2/455) / 48000 */ | ||
405 | cx25840_write4(client, 0x900, 0x08014faa); | ||
406 | cx25840_write4(client, 0x904, 0x08014faa); | ||
407 | cx25840_write4(client, 0x90c, 0x08014faa); | ||
200 | break; | 408 | break; |
201 | } | 409 | } |
202 | } | 410 | } |
@@ -206,6 +414,25 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq) | |||
206 | return 0; | 414 | return 0; |
207 | } | 415 | } |
208 | 416 | ||
417 | static int set_audclk_freq(struct i2c_client *client, u32 freq) | ||
418 | { | ||
419 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | ||
420 | |||
421 | if (freq != 32000 && freq != 44100 && freq != 48000) | ||
422 | return -EINVAL; | ||
423 | |||
424 | if (is_cx231xx(state)) | ||
425 | return cx231xx_set_audclk_freq(client, freq); | ||
426 | |||
427 | if (is_cx2388x(state)) | ||
428 | return cx23885_set_audclk_freq(client, freq); | ||
429 | |||
430 | if (is_cx2583x(state)) | ||
431 | return cx25836_set_audclk_freq(client, freq); | ||
432 | |||
433 | return cx25840_set_audclk_freq(client, freq); | ||
434 | } | ||
435 | |||
209 | void cx25840_audio_set_path(struct i2c_client *client) | 436 | void cx25840_audio_set_path(struct i2c_client *client) |
210 | { | 437 | { |
211 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 438 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
@@ -243,7 +470,7 @@ void cx25840_audio_set_path(struct i2c_client *client) | |||
243 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | 470 | cx25840_and_or(client, 0x810, ~0x1, 0x00); |
244 | 471 | ||
245 | /* Ensure the controller is running when we exit */ | 472 | /* Ensure the controller is running when we exit */ |
246 | if (state->is_cx23885 || state->is_cx231xx) | 473 | if (is_cx2388x(state) || is_cx231xx(state)) |
247 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 474 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
248 | } | 475 | } |
249 | 476 | ||
@@ -383,7 +610,7 @@ int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
383 | struct cx25840_state *state = to_state(sd); | 610 | struct cx25840_state *state = to_state(sd); |
384 | int retval; | 611 | int retval; |
385 | 612 | ||
386 | if (!state->is_cx25836) | 613 | if (!is_cx2583x(state)) |
387 | cx25840_and_or(client, 0x810, ~0x1, 1); | 614 | cx25840_and_or(client, 0x810, ~0x1, 1); |
388 | if (state->aud_input != CX25840_AUDIO_SERIAL) { | 615 | if (state->aud_input != CX25840_AUDIO_SERIAL) { |
389 | cx25840_and_or(client, 0x803, ~0x10, 0); | 616 | cx25840_and_or(client, 0x803, ~0x10, 0); |
@@ -392,7 +619,7 @@ int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq) | |||
392 | retval = set_audclk_freq(client, freq); | 619 | retval = set_audclk_freq(client, freq); |
393 | if (state->aud_input != CX25840_AUDIO_SERIAL) | 620 | if (state->aud_input != CX25840_AUDIO_SERIAL) |
394 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 621 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
395 | if (!state->is_cx25836) | 622 | if (!is_cx2583x(state)) |
396 | cx25840_and_or(client, 0x810, ~0x1, 0); | 623 | cx25840_and_or(client, 0x810, ~0x1, 0); |
397 | return retval; | 624 | return retval; |
398 | } | 625 | } |
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 1aeaf18a9bea..f2461cd3de5a 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -259,6 +259,13 @@ static void cx23885_initialize(struct i2c_client *client) | |||
259 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 259 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
260 | struct workqueue_struct *q; | 260 | struct workqueue_struct *q; |
261 | 261 | ||
262 | /* | ||
263 | * Come out of digital power down | ||
264 | * The CX23888, at least, needs this, otherwise registers aside from | ||
265 | * 0x0-0x2 can't be read or written. | ||
266 | */ | ||
267 | cx25840_write(client, 0x000, 0); | ||
268 | |||
262 | /* Internal Reset */ | 269 | /* Internal Reset */ |
263 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | 270 | cx25840_and_or(client, 0x102, ~0x01, 0x01); |
264 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | 271 | cx25840_and_or(client, 0x102, ~0x01, 0x00); |
@@ -269,18 +276,45 @@ static void cx23885_initialize(struct i2c_client *client) | |||
269 | /* DIF in reset? */ | 276 | /* DIF in reset? */ |
270 | cx25840_write(client, 0x398, 0); | 277 | cx25840_write(client, 0x398, 0); |
271 | 278 | ||
272 | /* Trust the default xtal, no division */ | 279 | /* |
273 | /* This changes for the cx23888 products */ | 280 | * Trust the default xtal, no division |
281 | * '885: 28.636363... MHz | ||
282 | * '887: 25.000000 MHz | ||
283 | * '888: 50.000000 MHz | ||
284 | */ | ||
274 | cx25840_write(client, 0x2, 0x76); | 285 | cx25840_write(client, 0x2, 0x76); |
275 | 286 | ||
276 | /* Bring down the regulator for AUX clk */ | 287 | /* Power up all the PLL's and DLL */ |
277 | cx25840_write(client, 0x1, 0x40); | 288 | cx25840_write(client, 0x1, 0x40); |
278 | 289 | ||
279 | /* Sys PLL frac */ | 290 | /* Sys PLL */ |
280 | cx25840_write4(client, 0x11c, 0x01d1744c); | 291 | switch (state->id) { |
281 | 292 | case V4L2_IDENT_CX23888_AV: | |
282 | /* Sys PLL int */ | 293 | /* |
283 | cx25840_write4(client, 0x118, 0x00000416); | 294 | * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz |
295 | * 572.73 MHz before post divide | ||
296 | */ | ||
297 | cx25840_write4(client, 0x11c, 0x00e8ba26); | ||
298 | cx25840_write4(client, 0x118, 0x0000040b); | ||
299 | break; | ||
300 | case V4L2_IDENT_CX23887_AV: | ||
301 | /* | ||
302 | * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz | ||
303 | * 572.73 MHz before post divide | ||
304 | */ | ||
305 | cx25840_write4(client, 0x11c, 0x01d1744c); | ||
306 | cx25840_write4(client, 0x118, 0x00000416); | ||
307 | break; | ||
308 | case V4L2_IDENT_CX23885_AV: | ||
309 | default: | ||
310 | /* | ||
311 | * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz | ||
312 | * 572.73 MHz before post divide | ||
313 | */ | ||
314 | cx25840_write4(client, 0x11c, 0x00000000); | ||
315 | cx25840_write4(client, 0x118, 0x00000414); | ||
316 | break; | ||
317 | } | ||
284 | 318 | ||
285 | /* Disable DIF bypass */ | 319 | /* Disable DIF bypass */ |
286 | cx25840_write4(client, 0x33c, 0x00000001); | 320 | cx25840_write4(client, 0x33c, 0x00000001); |
@@ -288,11 +322,15 @@ static void cx23885_initialize(struct i2c_client *client) | |||
288 | /* DIF Src phase inc */ | 322 | /* DIF Src phase inc */ |
289 | cx25840_write4(client, 0x340, 0x0df7df83); | 323 | cx25840_write4(client, 0x340, 0x0df7df83); |
290 | 324 | ||
291 | /* Vid PLL frac */ | 325 | /* |
292 | cx25840_write4(client, 0x10c, 0x01b6db7b); | 326 | * Vid PLL |
293 | 327 | * Setup for a BT.656 pixel clock of 13.5 Mpixels/second | |
294 | /* Vid PLL int */ | 328 | * |
295 | cx25840_write4(client, 0x108, 0x00000512); | 329 | * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz |
330 | * 432.0 MHz before post divide | ||
331 | */ | ||
332 | cx25840_write4(client, 0x10c, 0x002be2c9); | ||
333 | cx25840_write4(client, 0x108, 0x0000040f); | ||
296 | 334 | ||
297 | /* Luma */ | 335 | /* Luma */ |
298 | cx25840_write4(client, 0x414, 0x00107d12); | 336 | cx25840_write4(client, 0x414, 0x00107d12); |
@@ -300,11 +338,43 @@ static void cx23885_initialize(struct i2c_client *client) | |||
300 | /* Chroma */ | 338 | /* Chroma */ |
301 | cx25840_write4(client, 0x420, 0x3d008282); | 339 | cx25840_write4(client, 0x420, 0x3d008282); |
302 | 340 | ||
303 | /* Aux PLL frac */ | 341 | /* |
304 | cx25840_write4(client, 0x114, 0x017dbf48); | 342 | * Aux PLL |
305 | 343 | * Initial setup for audio sample clock: | |
306 | /* Aux PLL int */ | 344 | * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz |
307 | cx25840_write4(client, 0x110, 0x000a030e); | 345 | * Intial I2S output/master clock(?): |
346 | * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz | ||
347 | */ | ||
348 | switch (state->id) { | ||
349 | case V4L2_IDENT_CX23888_AV: | ||
350 | /* | ||
351 | * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz | ||
352 | * 368.64 MHz before post divide | ||
353 | * 122.88 MHz / 0xa = 12.288 MHz | ||
354 | */ | ||
355 | cx25840_write4(client, 0x114, 0x00bedfa4); | ||
356 | cx25840_write4(client, 0x110, 0x000a0307); | ||
357 | break; | ||
358 | case V4L2_IDENT_CX23887_AV: | ||
359 | /* | ||
360 | * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz | ||
361 | * 368.64 MHz before post divide | ||
362 | * 122.88 MHz / 0xa = 12.288 MHz | ||
363 | */ | ||
364 | cx25840_write4(client, 0x114, 0x017dbf48); | ||
365 | cx25840_write4(client, 0x110, 0x000a030e); | ||
366 | break; | ||
367 | case V4L2_IDENT_CX23885_AV: | ||
368 | default: | ||
369 | /* | ||
370 | * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz | ||
371 | * 368.64 MHz before post divide | ||
372 | * 122.88 MHz / 0xa = 12.288 MHz | ||
373 | */ | ||
374 | cx25840_write4(client, 0x114, 0x01bf0c9e); | ||
375 | cx25840_write4(client, 0x110, 0x000a030c); | ||
376 | break; | ||
377 | }; | ||
308 | 378 | ||
309 | /* ADC2 input select */ | 379 | /* ADC2 input select */ |
310 | cx25840_write(client, 0x102, 0x10); | 380 | cx25840_write(client, 0x102, 0x10); |
@@ -494,7 +564,7 @@ void cx25840_std_setup(struct i2c_client *client) | |||
494 | } | 564 | } |
495 | 565 | ||
496 | /* DEBUG: Displays configured PLL frequency */ | 566 | /* DEBUG: Displays configured PLL frequency */ |
497 | if (!state->is_cx231xx) { | 567 | if (!is_cx231xx(state)) { |
498 | pll_int = cx25840_read(client, 0x108); | 568 | pll_int = cx25840_read(client, 0x108); |
499 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; | 569 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; |
500 | pll_post = cx25840_read(client, 0x109); | 570 | pll_post = cx25840_read(client, 0x109); |
@@ -615,13 +685,30 @@ static void input_change(struct i2c_client *client) | |||
615 | } | 685 | } |
616 | cx25840_write(client, 0x80b, 0x00); | 686 | cx25840_write(client, 0x80b, 0x00); |
617 | } else if (std & V4L2_STD_PAL) { | 687 | } else if (std & V4L2_STD_PAL) { |
618 | /* Follow tuner change procedure for PAL */ | 688 | /* Autodetect audio standard and audio system */ |
619 | cx25840_write(client, 0x808, 0xff); | 689 | cx25840_write(client, 0x808, 0xff); |
620 | cx25840_write(client, 0x80b, 0x10); | 690 | /* Since system PAL-L is pretty much non-existant and |
691 | not used by any public broadcast network, force | ||
692 | 6.5 MHz carrier to be interpreted as System DK, | ||
693 | this avoids DK audio detection instability */ | ||
694 | cx25840_write(client, 0x80b, 0x00); | ||
621 | } else if (std & V4L2_STD_SECAM) { | 695 | } else if (std & V4L2_STD_SECAM) { |
622 | /* Select autodetect for SECAM */ | 696 | /* Autodetect audio standard and audio system */ |
623 | cx25840_write(client, 0x808, 0xff); | 697 | cx25840_write(client, 0x808, 0xff); |
624 | cx25840_write(client, 0x80b, 0x10); | 698 | /* If only one of SECAM-DK / SECAM-L is required, then force |
699 | 6.5MHz carrier, else autodetect it */ | ||
700 | if ((std & V4L2_STD_SECAM_DK) && | ||
701 | !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { | ||
702 | /* 6.5 MHz carrier to be interpreted as System DK */ | ||
703 | cx25840_write(client, 0x80b, 0x00); | ||
704 | } else if (!(std & V4L2_STD_SECAM_DK) && | ||
705 | (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { | ||
706 | /* 6.5 MHz carrier to be interpreted as System L */ | ||
707 | cx25840_write(client, 0x80b, 0x08); | ||
708 | } else { | ||
709 | /* 6.5 MHz carrier to be autodetected */ | ||
710 | cx25840_write(client, 0x80b, 0x10); | ||
711 | } | ||
625 | } | 712 | } |
626 | 713 | ||
627 | cx25840_and_or(client, 0x810, ~0x01, 0); | 714 | cx25840_and_or(client, 0x810, ~0x01, 0); |
@@ -633,6 +720,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
633 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 720 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
634 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && | 721 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && |
635 | vid_input <= CX25840_COMPOSITE8); | 722 | vid_input <= CX25840_COMPOSITE8); |
723 | u8 is_component = (vid_input & CX25840_COMPONENT_ON) == | ||
724 | CX25840_COMPONENT_ON; | ||
725 | int luma = vid_input & 0xf0; | ||
726 | int chroma = vid_input & 0xf00; | ||
636 | u8 reg; | 727 | u8 reg; |
637 | 728 | ||
638 | v4l_dbg(1, cx25840_debug, client, | 729 | v4l_dbg(1, cx25840_debug, client, |
@@ -643,20 +734,14 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
643 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", | 734 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", |
644 | vid_input); | 735 | vid_input); |
645 | reg = vid_input & 0xff; | 736 | reg = vid_input & 0xff; |
646 | if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) | 737 | is_composite = !is_component && |
647 | is_composite = 0; | 738 | ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); |
648 | else | ||
649 | is_composite = 1; | ||
650 | 739 | ||
651 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", | 740 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", |
652 | reg, is_composite); | 741 | reg, is_composite); |
653 | } else | 742 | } else if (is_composite) { |
654 | if (is_composite) { | ||
655 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); | 743 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); |
656 | } else { | 744 | } else { |
657 | int luma = vid_input & 0xf0; | ||
658 | int chroma = vid_input & 0xf00; | ||
659 | |||
660 | if ((vid_input & ~0xff0) || | 745 | if ((vid_input & ~0xff0) || |
661 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || | 746 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || |
662 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { | 747 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { |
@@ -678,7 +763,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
678 | * configuration in reg (for the cx23885) so we have no | 763 | * configuration in reg (for the cx23885) so we have no |
679 | * need to attempt to flip bits for earlier av decoders. | 764 | * need to attempt to flip bits for earlier av decoders. |
680 | */ | 765 | */ |
681 | if (!state->is_cx23885 && !state->is_cx231xx) { | 766 | if (!is_cx2388x(state) && !is_cx231xx(state)) { |
682 | switch (aud_input) { | 767 | switch (aud_input) { |
683 | case CX25840_AUDIO_SERIAL: | 768 | case CX25840_AUDIO_SERIAL: |
684 | /* do nothing, use serial audio input */ | 769 | /* do nothing, use serial audio input */ |
@@ -698,10 +783,13 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
698 | 783 | ||
699 | cx25840_write(client, 0x103, reg); | 784 | cx25840_write(client, 0x103, reg); |
700 | 785 | ||
701 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ | 786 | /* Set INPUT_MODE to Composite, S-Video or Component */ |
702 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | 787 | if (is_component) |
788 | cx25840_and_or(client, 0x401, ~0x6, 0x6); | ||
789 | else | ||
790 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | ||
703 | 791 | ||
704 | if (!state->is_cx23885 && !state->is_cx231xx) { | 792 | if (!is_cx2388x(state) && !is_cx231xx(state)) { |
705 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | 793 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ |
706 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | 794 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); |
707 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ | 795 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ |
@@ -710,22 +798,31 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
710 | else | 798 | else |
711 | cx25840_and_or(client, 0x102, ~0x4, 0); | 799 | cx25840_and_or(client, 0x102, ~0x4, 0); |
712 | } else { | 800 | } else { |
713 | if (is_composite) | 801 | /* Set DUAL_MODE_ADC2 to 1 if component*/ |
802 | cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0); | ||
803 | if (is_composite) { | ||
714 | /* ADC2 input select channel 2 */ | 804 | /* ADC2 input select channel 2 */ |
715 | cx25840_and_or(client, 0x102, ~0x2, 0); | 805 | cx25840_and_or(client, 0x102, ~0x2, 0); |
716 | else | 806 | } else if (!is_component) { |
717 | /* ADC2 input select channel 3 */ | 807 | /* S-Video */ |
718 | cx25840_and_or(client, 0x102, ~0x2, 2); | 808 | if (chroma >= CX25840_SVIDEO_CHROMA7) { |
809 | /* ADC2 input select channel 3 */ | ||
810 | cx25840_and_or(client, 0x102, ~0x2, 2); | ||
811 | } else { | ||
812 | /* ADC2 input select channel 2 */ | ||
813 | cx25840_and_or(client, 0x102, ~0x2, 0); | ||
814 | } | ||
815 | } | ||
719 | } | 816 | } |
720 | 817 | ||
721 | state->vid_input = vid_input; | 818 | state->vid_input = vid_input; |
722 | state->aud_input = aud_input; | 819 | state->aud_input = aud_input; |
723 | if (!state->is_cx25836) { | 820 | if (!is_cx2583x(state)) { |
724 | cx25840_audio_set_path(client); | 821 | cx25840_audio_set_path(client); |
725 | input_change(client); | 822 | input_change(client); |
726 | } | 823 | } |
727 | 824 | ||
728 | if (state->is_cx23885) { | 825 | if (is_cx2388x(state)) { |
729 | /* Audio channel 1 src : Parallel 1 */ | 826 | /* Audio channel 1 src : Parallel 1 */ |
730 | cx25840_write(client, 0x124, 0x03); | 827 | cx25840_write(client, 0x124, 0x03); |
731 | 828 | ||
@@ -741,7 +838,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp | |||
741 | */ | 838 | */ |
742 | cx25840_write(client, 0x918, 0xa0); | 839 | cx25840_write(client, 0x918, 0xa0); |
743 | cx25840_write(client, 0x919, 0x01); | 840 | cx25840_write(client, 0x919, 0x01); |
744 | } else if (state->is_cx231xx) { | 841 | } else if (is_cx231xx(state)) { |
745 | /* Audio channel 1 src : Parallel 1 */ | 842 | /* Audio channel 1 src : Parallel 1 */ |
746 | cx25840_write(client, 0x124, 0x03); | 843 | cx25840_write(client, 0x124, 0x03); |
747 | 844 | ||
@@ -805,7 +902,7 @@ static int set_v4lstd(struct i2c_client *client) | |||
805 | cx25840_and_or(client, 0x400, ~0xf, fmt); | 902 | cx25840_and_or(client, 0x400, ~0xf, fmt); |
806 | cx25840_and_or(client, 0x403, ~0x3, pal_m); | 903 | cx25840_and_or(client, 0x403, ~0x3, pal_m); |
807 | cx25840_std_setup(client); | 904 | cx25840_std_setup(client); |
808 | if (!state->is_cx25836) | 905 | if (!is_cx2583x(state)) |
809 | input_change(client); | 906 | input_change(client); |
810 | return 0; | 907 | return 0; |
811 | } | 908 | } |
@@ -868,7 +965,7 @@ static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
868 | case V4L2_CID_AUDIO_TREBLE: | 965 | case V4L2_CID_AUDIO_TREBLE: |
869 | case V4L2_CID_AUDIO_BALANCE: | 966 | case V4L2_CID_AUDIO_BALANCE: |
870 | case V4L2_CID_AUDIO_MUTE: | 967 | case V4L2_CID_AUDIO_MUTE: |
871 | if (state->is_cx25836) | 968 | if (is_cx2583x(state)) |
872 | return -EINVAL; | 969 | return -EINVAL; |
873 | return cx25840_audio_s_ctrl(sd, ctrl); | 970 | return cx25840_audio_s_ctrl(sd, ctrl); |
874 | 971 | ||
@@ -905,7 +1002,7 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | |||
905 | case V4L2_CID_AUDIO_TREBLE: | 1002 | case V4L2_CID_AUDIO_TREBLE: |
906 | case V4L2_CID_AUDIO_BALANCE: | 1003 | case V4L2_CID_AUDIO_BALANCE: |
907 | case V4L2_CID_AUDIO_MUTE: | 1004 | case V4L2_CID_AUDIO_MUTE: |
908 | if (state->is_cx25836) | 1005 | if (is_cx2583x(state)) |
909 | return -EINVAL; | 1006 | return -EINVAL; |
910 | return cx25840_audio_g_ctrl(sd, ctrl); | 1007 | return cx25840_audio_g_ctrl(sd, ctrl); |
911 | default: | 1008 | default: |
@@ -1209,11 +1306,11 @@ static int cx25840_load_fw(struct v4l2_subdev *sd) | |||
1209 | if (!state->is_initialized) { | 1306 | if (!state->is_initialized) { |
1210 | /* initialize and load firmware */ | 1307 | /* initialize and load firmware */ |
1211 | state->is_initialized = 1; | 1308 | state->is_initialized = 1; |
1212 | if (state->is_cx25836) | 1309 | if (is_cx2583x(state)) |
1213 | cx25836_initialize(client); | 1310 | cx25836_initialize(client); |
1214 | else if (state->is_cx23885) | 1311 | else if (is_cx2388x(state)) |
1215 | cx23885_initialize(client); | 1312 | cx23885_initialize(client); |
1216 | else if (state->is_cx231xx) | 1313 | else if (is_cx231xx(state)) |
1217 | cx231xx_initialize(client); | 1314 | cx231xx_initialize(client); |
1218 | else | 1315 | else |
1219 | cx25840_initialize(client); | 1316 | cx25840_initialize(client); |
@@ -1248,30 +1345,59 @@ static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * | |||
1248 | } | 1345 | } |
1249 | #endif | 1346 | #endif |
1250 | 1347 | ||
1348 | static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) | ||
1349 | { | ||
1350 | struct cx25840_state *state = to_state(sd); | ||
1351 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1352 | u8 v; | ||
1353 | |||
1354 | if (is_cx2583x(state) || is_cx2388x(state) || is_cx231xx(state)) | ||
1355 | return 0; | ||
1356 | |||
1357 | v4l_dbg(1, cx25840_debug, client, "%s audio output\n", | ||
1358 | enable ? "enable" : "disable"); | ||
1359 | |||
1360 | if (enable) { | ||
1361 | v = cx25840_read(client, 0x115) | 0x80; | ||
1362 | cx25840_write(client, 0x115, v); | ||
1363 | v = cx25840_read(client, 0x116) | 0x03; | ||
1364 | cx25840_write(client, 0x116, v); | ||
1365 | } else { | ||
1366 | v = cx25840_read(client, 0x115) & ~(0x80); | ||
1367 | cx25840_write(client, 0x115, v); | ||
1368 | v = cx25840_read(client, 0x116) & ~(0x03); | ||
1369 | cx25840_write(client, 0x116, v); | ||
1370 | } | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1251 | static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) | 1374 | static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) |
1252 | { | 1375 | { |
1253 | struct cx25840_state *state = to_state(sd); | 1376 | struct cx25840_state *state = to_state(sd); |
1254 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1377 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1378 | u8 v; | ||
1255 | 1379 | ||
1256 | v4l_dbg(1, cx25840_debug, client, "%s output\n", | 1380 | v4l_dbg(1, cx25840_debug, client, "%s video output\n", |
1257 | enable ? "enable" : "disable"); | 1381 | enable ? "enable" : "disable"); |
1258 | if (enable) { | 1382 | if (enable) { |
1259 | if (state->is_cx23885 || state->is_cx231xx) { | 1383 | if (is_cx2388x(state) || is_cx231xx(state)) { |
1260 | u8 v = (cx25840_read(client, 0x421) | 0x0b); | 1384 | v = cx25840_read(client, 0x421) | 0x0b; |
1261 | cx25840_write(client, 0x421, v); | 1385 | cx25840_write(client, 0x421, v); |
1262 | } else { | 1386 | } else { |
1263 | cx25840_write(client, 0x115, | 1387 | v = cx25840_read(client, 0x115) | 0x0c; |
1264 | state->is_cx25836 ? 0x0c : 0x8c); | 1388 | cx25840_write(client, 0x115, v); |
1265 | cx25840_write(client, 0x116, | 1389 | v = cx25840_read(client, 0x116) | 0x04; |
1266 | state->is_cx25836 ? 0x04 : 0x07); | 1390 | cx25840_write(client, 0x116, v); |
1267 | } | 1391 | } |
1268 | } else { | 1392 | } else { |
1269 | if (state->is_cx23885 || state->is_cx231xx) { | 1393 | if (is_cx2388x(state) || is_cx231xx(state)) { |
1270 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); | 1394 | v = cx25840_read(client, 0x421) & ~(0x0b); |
1271 | cx25840_write(client, 0x421, v); | 1395 | cx25840_write(client, 0x421, v); |
1272 | } else { | 1396 | } else { |
1273 | cx25840_write(client, 0x115, 0x00); | 1397 | v = cx25840_read(client, 0x115) & ~(0x0c); |
1274 | cx25840_write(client, 0x116, 0x00); | 1398 | cx25840_write(client, 0x115, v); |
1399 | v = cx25840_read(client, 0x116) & ~(0x04); | ||
1400 | cx25840_write(client, 0x116, v); | ||
1275 | } | 1401 | } |
1276 | } | 1402 | } |
1277 | return 0; | 1403 | return 0; |
@@ -1292,7 +1418,7 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | |||
1292 | default: | 1418 | default: |
1293 | break; | 1419 | break; |
1294 | } | 1420 | } |
1295 | if (state->is_cx25836) | 1421 | if (is_cx2583x(state)) |
1296 | return -EINVAL; | 1422 | return -EINVAL; |
1297 | 1423 | ||
1298 | switch (qc->id) { | 1424 | switch (qc->id) { |
@@ -1346,7 +1472,7 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, | |||
1346 | struct cx25840_state *state = to_state(sd); | 1472 | struct cx25840_state *state = to_state(sd); |
1347 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1473 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1348 | 1474 | ||
1349 | if (state->is_cx25836) | 1475 | if (is_cx2583x(state)) |
1350 | return -EINVAL; | 1476 | return -EINVAL; |
1351 | return set_input(client, state->vid_input, input); | 1477 | return set_input(client, state->vid_input, input); |
1352 | } | 1478 | } |
@@ -1356,7 +1482,7 @@ static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fr | |||
1356 | struct cx25840_state *state = to_state(sd); | 1482 | struct cx25840_state *state = to_state(sd); |
1357 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1483 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1358 | 1484 | ||
1359 | if (!state->is_cx25836) | 1485 | if (!is_cx2583x(state)) |
1360 | input_change(client); | 1486 | input_change(client); |
1361 | return 0; | 1487 | return 0; |
1362 | } | 1488 | } |
@@ -1373,7 +1499,7 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | |||
1373 | return 0; | 1499 | return 0; |
1374 | 1500 | ||
1375 | vt->signal = vpres ? 0xffff : 0x0; | 1501 | vt->signal = vpres ? 0xffff : 0x0; |
1376 | if (state->is_cx25836) | 1502 | if (is_cx2583x(state)) |
1377 | return 0; | 1503 | return 0; |
1378 | 1504 | ||
1379 | vt->capability |= | 1505 | vt->capability |= |
@@ -1404,7 +1530,7 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | |||
1404 | struct cx25840_state *state = to_state(sd); | 1530 | struct cx25840_state *state = to_state(sd); |
1405 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1531 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1406 | 1532 | ||
1407 | if (state->radio || state->is_cx25836) | 1533 | if (state->radio || is_cx2583x(state)) |
1408 | return 0; | 1534 | return 0; |
1409 | 1535 | ||
1410 | switch (vt->audmode) { | 1536 | switch (vt->audmode) { |
@@ -1445,11 +1571,11 @@ static int cx25840_reset(struct v4l2_subdev *sd, u32 val) | |||
1445 | struct cx25840_state *state = to_state(sd); | 1571 | struct cx25840_state *state = to_state(sd); |
1446 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1572 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1447 | 1573 | ||
1448 | if (state->is_cx25836) | 1574 | if (is_cx2583x(state)) |
1449 | cx25836_initialize(client); | 1575 | cx25836_initialize(client); |
1450 | else if (state->is_cx23885) | 1576 | else if (is_cx2388x(state)) |
1451 | cx23885_initialize(client); | 1577 | cx23885_initialize(client); |
1452 | else if (state->is_cx231xx) | 1578 | else if (is_cx231xx(state)) |
1453 | cx231xx_initialize(client); | 1579 | cx231xx_initialize(client); |
1454 | else | 1580 | else |
1455 | cx25840_initialize(client); | 1581 | cx25840_initialize(client); |
@@ -1470,7 +1596,7 @@ static int cx25840_log_status(struct v4l2_subdev *sd) | |||
1470 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1596 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1471 | 1597 | ||
1472 | log_video_status(client); | 1598 | log_video_status(client); |
1473 | if (!state->is_cx25836) | 1599 | if (!is_cx2583x(state)) |
1474 | log_audio_status(client); | 1600 | log_audio_status(client); |
1475 | return 0; | 1601 | return 0; |
1476 | } | 1602 | } |
@@ -1502,6 +1628,7 @@ static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { | |||
1502 | static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { | 1628 | static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { |
1503 | .s_clock_freq = cx25840_s_clock_freq, | 1629 | .s_clock_freq = cx25840_s_clock_freq, |
1504 | .s_routing = cx25840_s_audio_routing, | 1630 | .s_routing = cx25840_s_audio_routing, |
1631 | .s_stream = cx25840_s_audio_stream, | ||
1505 | }; | 1632 | }; |
1506 | 1633 | ||
1507 | static const struct v4l2_subdev_video_ops cx25840_video_ops = { | 1634 | static const struct v4l2_subdev_video_ops cx25840_video_ops = { |
@@ -1521,12 +1648,50 @@ static const struct v4l2_subdev_ops cx25840_ops = { | |||
1521 | 1648 | ||
1522 | /* ----------------------------------------------------------------------- */ | 1649 | /* ----------------------------------------------------------------------- */ |
1523 | 1650 | ||
1651 | static u32 get_cx2388x_ident(struct i2c_client *client) | ||
1652 | { | ||
1653 | u32 ret; | ||
1654 | |||
1655 | /* Come out of digital power down */ | ||
1656 | cx25840_write(client, 0x000, 0); | ||
1657 | |||
1658 | /* Detecting whether the part is cx23885/7/8 is more | ||
1659 | * difficult than it needs to be. No ID register. Instead we | ||
1660 | * probe certain registers indicated in the datasheets to look | ||
1661 | * for specific defaults that differ between the silicon designs. */ | ||
1662 | |||
1663 | /* It's either 885/7 if the IR Tx Clk Divider register exists */ | ||
1664 | if (cx25840_read4(client, 0x204) & 0xffff) { | ||
1665 | /* CX23885 returns bogus repetitive byte values for the DIF, | ||
1666 | * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ | ||
1667 | ret = cx25840_read4(client, 0x300); | ||
1668 | if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { | ||
1669 | /* No DIF */ | ||
1670 | ret = V4L2_IDENT_CX23885_AV; | ||
1671 | } else { | ||
1672 | /* CX23887 has a broken DIF, but the registers | ||
1673 | * appear valid (but unsed), good enough to detect. */ | ||
1674 | ret = V4L2_IDENT_CX23887_AV; | ||
1675 | } | ||
1676 | } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { | ||
1677 | /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ | ||
1678 | ret = V4L2_IDENT_CX23888_AV; | ||
1679 | } else { | ||
1680 | v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); | ||
1681 | ret = V4L2_IDENT_CX23887_AV; | ||
1682 | } | ||
1683 | |||
1684 | /* Back into digital power down */ | ||
1685 | cx25840_write(client, 0x000, 2); | ||
1686 | return ret; | ||
1687 | } | ||
1688 | |||
1524 | static int cx25840_probe(struct i2c_client *client, | 1689 | static int cx25840_probe(struct i2c_client *client, |
1525 | const struct i2c_device_id *did) | 1690 | const struct i2c_device_id *did) |
1526 | { | 1691 | { |
1527 | struct cx25840_state *state; | 1692 | struct cx25840_state *state; |
1528 | struct v4l2_subdev *sd; | 1693 | struct v4l2_subdev *sd; |
1529 | u32 id; | 1694 | u32 id = V4L2_IDENT_NONE; |
1530 | u16 device_id; | 1695 | u16 device_id; |
1531 | 1696 | ||
1532 | /* Check if the adapter supports the needed features */ | 1697 | /* Check if the adapter supports the needed features */ |
@@ -1543,17 +1708,22 @@ static int cx25840_probe(struct i2c_client *client, | |||
1543 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ | 1708 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ |
1544 | if ((device_id & 0xff00) == 0x8300) { | 1709 | if ((device_id & 0xff00) == 0x8300) { |
1545 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | 1710 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; |
1546 | } | 1711 | } else if ((device_id & 0xff00) == 0x8400) { |
1547 | else if ((device_id & 0xff00) == 0x8400) { | ||
1548 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | 1712 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); |
1549 | } else if (device_id == 0x0000) { | 1713 | } else if (device_id == 0x0000) { |
1550 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | 1714 | id = get_cx2388x_ident(client); |
1551 | } else if (device_id == 0x1313) { | ||
1552 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | ||
1553 | } else if ((device_id & 0xfff0) == 0x5A30) { | 1715 | } else if ((device_id & 0xfff0) == 0x5A30) { |
1554 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | 1716 | /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ |
1555 | } | 1717 | id = V4L2_IDENT_CX2310X_AV; |
1556 | else { | 1718 | } else if ((device_id & 0xff) == (device_id >> 8)) { |
1719 | v4l_err(client, | ||
1720 | "likely a confused/unresponsive cx2388[578] A/V decoder" | ||
1721 | " found @ 0x%x (%s)\n", | ||
1722 | client->addr << 1, client->adapter->name); | ||
1723 | v4l_err(client, "A method to reset it from the cx25840 driver" | ||
1724 | " software is not known at this time\n"); | ||
1725 | return -ENODEV; | ||
1726 | } else { | ||
1557 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | 1727 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); |
1558 | return -ENODEV; | 1728 | return -ENODEV; |
1559 | } | 1729 | } |
@@ -1564,17 +1734,45 @@ static int cx25840_probe(struct i2c_client *client, | |||
1564 | 1734 | ||
1565 | sd = &state->sd; | 1735 | sd = &state->sd; |
1566 | v4l2_i2c_subdev_init(sd, client, &cx25840_ops); | 1736 | v4l2_i2c_subdev_init(sd, client, &cx25840_ops); |
1567 | /* Note: revision '(device_id & 0x0f) == 2' was never built. The | 1737 | switch (id) { |
1568 | marking skips from 0x1 == 22 to 0x3 == 23. */ | 1738 | case V4L2_IDENT_CX23885_AV: |
1569 | v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", | 1739 | v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", |
1570 | (device_id & 0xfff0) >> 4, | 1740 | client->addr << 1, client->adapter->name); |
1571 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f), | 1741 | break; |
1572 | client->addr << 1, client->adapter->name); | 1742 | case V4L2_IDENT_CX23887_AV: |
1743 | v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", | ||
1744 | client->addr << 1, client->adapter->name); | ||
1745 | break; | ||
1746 | case V4L2_IDENT_CX23888_AV: | ||
1747 | v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", | ||
1748 | client->addr << 1, client->adapter->name); | ||
1749 | break; | ||
1750 | case V4L2_IDENT_CX2310X_AV: | ||
1751 | v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", | ||
1752 | device_id, client->addr << 1, client->adapter->name); | ||
1753 | break; | ||
1754 | case V4L2_IDENT_CX25840: | ||
1755 | case V4L2_IDENT_CX25841: | ||
1756 | case V4L2_IDENT_CX25842: | ||
1757 | case V4L2_IDENT_CX25843: | ||
1758 | /* Note: revision '(device_id & 0x0f) == 2' was never built. The | ||
1759 | marking skips from 0x1 == 22 to 0x3 == 23. */ | ||
1760 | v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", | ||
1761 | (device_id & 0xfff0) >> 4, | ||
1762 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 | ||
1763 | : (device_id & 0x0f), | ||
1764 | client->addr << 1, client->adapter->name); | ||
1765 | break; | ||
1766 | case V4L2_IDENT_CX25836: | ||
1767 | case V4L2_IDENT_CX25837: | ||
1768 | default: | ||
1769 | v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", | ||
1770 | (device_id & 0xfff0) >> 4, device_id & 0x0f, | ||
1771 | client->addr << 1, client->adapter->name); | ||
1772 | break; | ||
1773 | } | ||
1573 | 1774 | ||
1574 | state->c = client; | 1775 | state->c = client; |
1575 | state->is_cx25836 = ((device_id & 0xff00) == 0x8300); | ||
1576 | state->is_cx23885 = (device_id == 0x0000) || (device_id == 0x1313); | ||
1577 | state->is_cx231xx = (device_id == 0x5a3e); | ||
1578 | state->vid_input = CX25840_COMPOSITE7; | 1776 | state->vid_input = CX25840_COMPOSITE7; |
1579 | state->aud_input = CX25840_AUDIO8; | 1777 | state->aud_input = CX25840_AUDIO8; |
1580 | state->audclk_freq = 48000; | 1778 | state->audclk_freq = 48000; |
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h index 814b56536994..55345444417f 100644 --- a/drivers/media/video/cx25840/cx25840-core.h +++ b/drivers/media/video/cx25840/cx25840-core.h | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #include <linux/videodev2.h> | 24 | #include <linux/videodev2.h> |
25 | #include <media/v4l2-device.h> | 25 | #include <media/v4l2-device.h> |
26 | #include <media/v4l2-chip-ident.h> | ||
26 | #include <linux/i2c.h> | 27 | #include <linux/i2c.h> |
27 | 28 | ||
28 | /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is | 29 | /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is |
@@ -48,9 +49,6 @@ struct cx25840_state { | |||
48 | int vbi_line_offset; | 49 | int vbi_line_offset; |
49 | u32 id; | 50 | u32 id; |
50 | u32 rev; | 51 | u32 rev; |
51 | int is_cx25836; | ||
52 | int is_cx23885; | ||
53 | int is_cx231xx; | ||
54 | int is_initialized; | 52 | int is_initialized; |
55 | wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ | 53 | wait_queue_head_t fw_wait; /* wake up when the fw load is finished */ |
56 | struct work_struct fw_work; /* work entry for fw load */ | 54 | struct work_struct fw_work; /* work entry for fw load */ |
@@ -61,6 +59,24 @@ static inline struct cx25840_state *to_state(struct v4l2_subdev *sd) | |||
61 | return container_of(sd, struct cx25840_state, sd); | 59 | return container_of(sd, struct cx25840_state, sd); |
62 | } | 60 | } |
63 | 61 | ||
62 | static inline bool is_cx2583x(struct cx25840_state *state) | ||
63 | { | ||
64 | return state->id == V4L2_IDENT_CX25836 || | ||
65 | state->id == V4L2_IDENT_CX25837; | ||
66 | } | ||
67 | |||
68 | static inline bool is_cx231xx(struct cx25840_state *state) | ||
69 | { | ||
70 | return state->id == V4L2_IDENT_CX2310X_AV; | ||
71 | } | ||
72 | |||
73 | static inline bool is_cx2388x(struct cx25840_state *state) | ||
74 | { | ||
75 | return state->id == V4L2_IDENT_CX23885_AV || | ||
76 | state->id == V4L2_IDENT_CX23887_AV || | ||
77 | state->id == V4L2_IDENT_CX23888_AV; | ||
78 | } | ||
79 | |||
64 | /* ----------------------------------------------------------------------- */ | 80 | /* ----------------------------------------------------------------------- */ |
65 | /* cx25850-core.c */ | 81 | /* cx25850-core.c */ |
66 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value); | 82 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value); |
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 1f483c1d0dbe..8150200511da 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -67,9 +67,9 @@ static const char *get_fw_name(struct i2c_client *client) | |||
67 | 67 | ||
68 | if (firmware[0]) | 68 | if (firmware[0]) |
69 | return firmware; | 69 | return firmware; |
70 | if (state->is_cx23885) | 70 | if (is_cx2388x(state)) |
71 | return "v4l-cx23885-avcore-01.fw"; | 71 | return "v4l-cx23885-avcore-01.fw"; |
72 | if (state->is_cx231xx) | 72 | if (is_cx231xx(state)) |
73 | return "v4l-cx231xx-avcore-01.fw"; | 73 | return "v4l-cx231xx-avcore-01.fw"; |
74 | return "v4l-cx25840.fw"; | 74 | return "v4l-cx25840.fw"; |
75 | } | 75 | } |
@@ -112,13 +112,13 @@ int cx25840_loadfw(struct i2c_client *client) | |||
112 | int MAX_BUF_SIZE = FWSEND; | 112 | int MAX_BUF_SIZE = FWSEND; |
113 | u32 gpio_oe = 0, gpio_da = 0; | 113 | u32 gpio_oe = 0, gpio_da = 0; |
114 | 114 | ||
115 | if (state->is_cx23885) { | 115 | if (is_cx2388x(state)) { |
116 | /* Preserve the GPIO OE and output bits */ | 116 | /* Preserve the GPIO OE and output bits */ |
117 | gpio_oe = cx25840_read(client, 0x160); | 117 | gpio_oe = cx25840_read(client, 0x160); |
118 | gpio_da = cx25840_read(client, 0x164); | 118 | gpio_da = cx25840_read(client, 0x164); |
119 | } | 119 | } |
120 | 120 | ||
121 | if ((state->is_cx231xx) && MAX_BUF_SIZE > 16) { | 121 | if (is_cx231xx(state) && MAX_BUF_SIZE > 16) { |
122 | v4l_err(client, " Firmware download size changed to 16 bytes max length\n"); | 122 | v4l_err(client, " Firmware download size changed to 16 bytes max length\n"); |
123 | MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */ | 123 | MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */ |
124 | } | 124 | } |
@@ -156,7 +156,7 @@ int cx25840_loadfw(struct i2c_client *client) | |||
156 | size = fw->size; | 156 | size = fw->size; |
157 | release_firmware(fw); | 157 | release_firmware(fw); |
158 | 158 | ||
159 | if (state->is_cx23885) { | 159 | if (is_cx2388x(state)) { |
160 | /* Restore GPIO configuration after f/w load */ | 160 | /* Restore GPIO configuration after f/w load */ |
161 | cx25840_write(client, 0x160, gpio_oe); | 161 | cx25840_write(client, 0x160, gpio_oe); |
162 | cx25840_write(client, 0x164, gpio_da); | 162 | cx25840_write(client, 0x164, gpio_da); |