Commit fb29ab96982baba57b03636e2a894c0d0acd197e
Committed by
Mauro Carvalho Chehab
1 parent
184e769f93
Exists in
master
and in
7 other branches
V4L/DVB (13206): cx25840: add component support
Signed-off-by: David T.L. Wong <davidtlwong@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Showing 2 changed files with 25 additions and 12 deletions Inline Diff
drivers/media/video/cx25840/cx25840-core.c
1 | /* cx25840 - Conexant CX25840 audio/video decoder driver | 1 | /* cx25840 - Conexant CX25840 audio/video decoder driver |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Ulf Eklund | 3 | * Copyright (C) 2004 Ulf Eklund |
4 | * | 4 | * |
5 | * Based on the saa7115 driver and on the first verison of Chris Kennedy's | 5 | * Based on the saa7115 driver and on the first verison of Chris Kennedy's |
6 | * cx25840 driver. | 6 | * cx25840 driver. |
7 | * | 7 | * |
8 | * Changes by Tyler Trafford <tatrafford@comcast.net> | 8 | * Changes by Tyler Trafford <tatrafford@comcast.net> |
9 | * - cleanup/rewrite for V4L2 API (2005) | 9 | * - cleanup/rewrite for V4L2 API (2005) |
10 | * | 10 | * |
11 | * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. | 11 | * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. |
12 | * | 12 | * |
13 | * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> | 13 | * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> |
14 | * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. | 14 | * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. |
15 | * | 15 | * |
16 | * CX23885 support by Steven Toth <stoth@linuxtv.org>. | 16 | * CX23885 support by Steven Toth <stoth@linuxtv.org>. |
17 | * | 17 | * |
18 | * This program is free software; you can redistribute it and/or | 18 | * This program is free software; you can redistribute it and/or |
19 | * modify it under the terms of the GNU General Public License | 19 | * modify it under the terms of the GNU General Public License |
20 | * as published by the Free Software Foundation; either version 2 | 20 | * as published by the Free Software Foundation; either version 2 |
21 | * of the License, or (at your option) any later version. | 21 | * of the License, or (at your option) any later version. |
22 | * | 22 | * |
23 | * This program is distributed in the hope that it will be useful, | 23 | * This program is distributed in the hope that it will be useful, |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
26 | * GNU General Public License for more details. | 26 | * GNU General Public License for more details. |
27 | * | 27 | * |
28 | * You should have received a copy of the GNU General Public License | 28 | * You should have received a copy of the GNU General Public License |
29 | * along with this program; if not, write to the Free Software | 29 | * along with this program; if not, write to the Free Software |
30 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 30 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | 33 | ||
34 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | #include <linux/videodev2.h> | 37 | #include <linux/videodev2.h> |
38 | #include <linux/i2c.h> | 38 | #include <linux/i2c.h> |
39 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
40 | #include <media/v4l2-common.h> | 40 | #include <media/v4l2-common.h> |
41 | #include <media/v4l2-chip-ident.h> | 41 | #include <media/v4l2-chip-ident.h> |
42 | #include <media/v4l2-i2c-drv.h> | 42 | #include <media/v4l2-i2c-drv.h> |
43 | #include <media/cx25840.h> | 43 | #include <media/cx25840.h> |
44 | 44 | ||
45 | #include "cx25840-core.h" | 45 | #include "cx25840-core.h" |
46 | 46 | ||
47 | MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); | 47 | MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); |
48 | MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); | 48 | MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); |
49 | MODULE_LICENSE("GPL"); | 49 | MODULE_LICENSE("GPL"); |
50 | 50 | ||
51 | static int cx25840_debug; | 51 | static int cx25840_debug; |
52 | 52 | ||
53 | module_param_named(debug,cx25840_debug, int, 0644); | 53 | module_param_named(debug,cx25840_debug, int, 0644); |
54 | 54 | ||
55 | MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); | 55 | MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); |
56 | 56 | ||
57 | 57 | ||
58 | /* ----------------------------------------------------------------------- */ | 58 | /* ----------------------------------------------------------------------- */ |
59 | 59 | ||
60 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value) | 60 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value) |
61 | { | 61 | { |
62 | u8 buffer[3]; | 62 | u8 buffer[3]; |
63 | buffer[0] = addr >> 8; | 63 | buffer[0] = addr >> 8; |
64 | buffer[1] = addr & 0xff; | 64 | buffer[1] = addr & 0xff; |
65 | buffer[2] = value; | 65 | buffer[2] = value; |
66 | return i2c_master_send(client, buffer, 3); | 66 | return i2c_master_send(client, buffer, 3); |
67 | } | 67 | } |
68 | 68 | ||
69 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) | 69 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) |
70 | { | 70 | { |
71 | u8 buffer[6]; | 71 | u8 buffer[6]; |
72 | buffer[0] = addr >> 8; | 72 | buffer[0] = addr >> 8; |
73 | buffer[1] = addr & 0xff; | 73 | buffer[1] = addr & 0xff; |
74 | buffer[2] = value & 0xff; | 74 | buffer[2] = value & 0xff; |
75 | buffer[3] = (value >> 8) & 0xff; | 75 | buffer[3] = (value >> 8) & 0xff; |
76 | buffer[4] = (value >> 16) & 0xff; | 76 | buffer[4] = (value >> 16) & 0xff; |
77 | buffer[5] = value >> 24; | 77 | buffer[5] = value >> 24; |
78 | return i2c_master_send(client, buffer, 6); | 78 | return i2c_master_send(client, buffer, 6); |
79 | } | 79 | } |
80 | 80 | ||
81 | u8 cx25840_read(struct i2c_client * client, u16 addr) | 81 | u8 cx25840_read(struct i2c_client * client, u16 addr) |
82 | { | 82 | { |
83 | u8 buffer[2]; | 83 | u8 buffer[2]; |
84 | buffer[0] = addr >> 8; | 84 | buffer[0] = addr >> 8; |
85 | buffer[1] = addr & 0xff; | 85 | buffer[1] = addr & 0xff; |
86 | 86 | ||
87 | if (i2c_master_send(client, buffer, 2) < 2) | 87 | if (i2c_master_send(client, buffer, 2) < 2) |
88 | return 0; | 88 | return 0; |
89 | 89 | ||
90 | if (i2c_master_recv(client, buffer, 1) < 1) | 90 | if (i2c_master_recv(client, buffer, 1) < 1) |
91 | return 0; | 91 | return 0; |
92 | 92 | ||
93 | return buffer[0]; | 93 | return buffer[0]; |
94 | } | 94 | } |
95 | 95 | ||
96 | u32 cx25840_read4(struct i2c_client * client, u16 addr) | 96 | u32 cx25840_read4(struct i2c_client * client, u16 addr) |
97 | { | 97 | { |
98 | u8 buffer[4]; | 98 | u8 buffer[4]; |
99 | buffer[0] = addr >> 8; | 99 | buffer[0] = addr >> 8; |
100 | buffer[1] = addr & 0xff; | 100 | buffer[1] = addr & 0xff; |
101 | 101 | ||
102 | if (i2c_master_send(client, buffer, 2) < 2) | 102 | if (i2c_master_send(client, buffer, 2) < 2) |
103 | return 0; | 103 | return 0; |
104 | 104 | ||
105 | if (i2c_master_recv(client, buffer, 4) < 4) | 105 | if (i2c_master_recv(client, buffer, 4) < 4) |
106 | return 0; | 106 | return 0; |
107 | 107 | ||
108 | return (buffer[3] << 24) | (buffer[2] << 16) | | 108 | return (buffer[3] << 24) | (buffer[2] << 16) | |
109 | (buffer[1] << 8) | buffer[0]; | 109 | (buffer[1] << 8) | buffer[0]; |
110 | } | 110 | } |
111 | 111 | ||
112 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, | 112 | int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, |
113 | u8 or_value) | 113 | u8 or_value) |
114 | { | 114 | { |
115 | return cx25840_write(client, addr, | 115 | return cx25840_write(client, addr, |
116 | (cx25840_read(client, addr) & and_mask) | | 116 | (cx25840_read(client, addr) & and_mask) | |
117 | or_value); | 117 | or_value); |
118 | } | 118 | } |
119 | 119 | ||
120 | /* ----------------------------------------------------------------------- */ | 120 | /* ----------------------------------------------------------------------- */ |
121 | 121 | ||
122 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, | 122 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, |
123 | enum cx25840_audio_input aud_input); | 123 | enum cx25840_audio_input aud_input); |
124 | 124 | ||
125 | /* ----------------------------------------------------------------------- */ | 125 | /* ----------------------------------------------------------------------- */ |
126 | 126 | ||
127 | static void init_dll1(struct i2c_client *client) | 127 | static void init_dll1(struct i2c_client *client) |
128 | { | 128 | { |
129 | /* This is the Hauppauge sequence used to | 129 | /* This is the Hauppauge sequence used to |
130 | * initialize the Delay Lock Loop 1 (ADC DLL). */ | 130 | * initialize the Delay Lock Loop 1 (ADC DLL). */ |
131 | cx25840_write(client, 0x159, 0x23); | 131 | cx25840_write(client, 0x159, 0x23); |
132 | cx25840_write(client, 0x15a, 0x87); | 132 | cx25840_write(client, 0x15a, 0x87); |
133 | cx25840_write(client, 0x15b, 0x06); | 133 | cx25840_write(client, 0x15b, 0x06); |
134 | udelay(10); | 134 | udelay(10); |
135 | cx25840_write(client, 0x159, 0xe1); | 135 | cx25840_write(client, 0x159, 0xe1); |
136 | udelay(10); | 136 | udelay(10); |
137 | cx25840_write(client, 0x15a, 0x86); | 137 | cx25840_write(client, 0x15a, 0x86); |
138 | cx25840_write(client, 0x159, 0xe0); | 138 | cx25840_write(client, 0x159, 0xe0); |
139 | cx25840_write(client, 0x159, 0xe1); | 139 | cx25840_write(client, 0x159, 0xe1); |
140 | cx25840_write(client, 0x15b, 0x10); | 140 | cx25840_write(client, 0x15b, 0x10); |
141 | } | 141 | } |
142 | 142 | ||
143 | static void init_dll2(struct i2c_client *client) | 143 | static void init_dll2(struct i2c_client *client) |
144 | { | 144 | { |
145 | /* This is the Hauppauge sequence used to | 145 | /* This is the Hauppauge sequence used to |
146 | * initialize the Delay Lock Loop 2 (ADC DLL). */ | 146 | * initialize the Delay Lock Loop 2 (ADC DLL). */ |
147 | cx25840_write(client, 0x15d, 0xe3); | 147 | cx25840_write(client, 0x15d, 0xe3); |
148 | cx25840_write(client, 0x15e, 0x86); | 148 | cx25840_write(client, 0x15e, 0x86); |
149 | cx25840_write(client, 0x15f, 0x06); | 149 | cx25840_write(client, 0x15f, 0x06); |
150 | udelay(10); | 150 | udelay(10); |
151 | cx25840_write(client, 0x15d, 0xe1); | 151 | cx25840_write(client, 0x15d, 0xe1); |
152 | cx25840_write(client, 0x15d, 0xe0); | 152 | cx25840_write(client, 0x15d, 0xe0); |
153 | cx25840_write(client, 0x15d, 0xe1); | 153 | cx25840_write(client, 0x15d, 0xe1); |
154 | } | 154 | } |
155 | 155 | ||
156 | static void cx25836_initialize(struct i2c_client *client) | 156 | static void cx25836_initialize(struct i2c_client *client) |
157 | { | 157 | { |
158 | /* reset configuration is described on page 3-77 of the CX25836 datasheet */ | 158 | /* reset configuration is described on page 3-77 of the CX25836 datasheet */ |
159 | /* 2. */ | 159 | /* 2. */ |
160 | cx25840_and_or(client, 0x000, ~0x01, 0x01); | 160 | cx25840_and_or(client, 0x000, ~0x01, 0x01); |
161 | cx25840_and_or(client, 0x000, ~0x01, 0x00); | 161 | cx25840_and_or(client, 0x000, ~0x01, 0x00); |
162 | /* 3a. */ | 162 | /* 3a. */ |
163 | cx25840_and_or(client, 0x15a, ~0x70, 0x00); | 163 | cx25840_and_or(client, 0x15a, ~0x70, 0x00); |
164 | /* 3b. */ | 164 | /* 3b. */ |
165 | cx25840_and_or(client, 0x15b, ~0x1e, 0x06); | 165 | cx25840_and_or(client, 0x15b, ~0x1e, 0x06); |
166 | /* 3c. */ | 166 | /* 3c. */ |
167 | cx25840_and_or(client, 0x159, ~0x02, 0x02); | 167 | cx25840_and_or(client, 0x159, ~0x02, 0x02); |
168 | /* 3d. */ | 168 | /* 3d. */ |
169 | udelay(10); | 169 | udelay(10); |
170 | /* 3e. */ | 170 | /* 3e. */ |
171 | cx25840_and_or(client, 0x159, ~0x02, 0x00); | 171 | cx25840_and_or(client, 0x159, ~0x02, 0x00); |
172 | /* 3f. */ | 172 | /* 3f. */ |
173 | cx25840_and_or(client, 0x159, ~0xc0, 0xc0); | 173 | cx25840_and_or(client, 0x159, ~0xc0, 0xc0); |
174 | /* 3g. */ | 174 | /* 3g. */ |
175 | cx25840_and_or(client, 0x159, ~0x01, 0x00); | 175 | cx25840_and_or(client, 0x159, ~0x01, 0x00); |
176 | cx25840_and_or(client, 0x159, ~0x01, 0x01); | 176 | cx25840_and_or(client, 0x159, ~0x01, 0x01); |
177 | /* 3h. */ | 177 | /* 3h. */ |
178 | cx25840_and_or(client, 0x15b, ~0x1e, 0x10); | 178 | cx25840_and_or(client, 0x15b, ~0x1e, 0x10); |
179 | } | 179 | } |
180 | 180 | ||
181 | static void cx25840_work_handler(struct work_struct *work) | 181 | static void cx25840_work_handler(struct work_struct *work) |
182 | { | 182 | { |
183 | struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); | 183 | struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); |
184 | cx25840_loadfw(state->c); | 184 | cx25840_loadfw(state->c); |
185 | wake_up(&state->fw_wait); | 185 | wake_up(&state->fw_wait); |
186 | } | 186 | } |
187 | 187 | ||
188 | static void cx25840_initialize(struct i2c_client *client) | 188 | static void cx25840_initialize(struct i2c_client *client) |
189 | { | 189 | { |
190 | DEFINE_WAIT(wait); | 190 | DEFINE_WAIT(wait); |
191 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 191 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
192 | struct workqueue_struct *q; | 192 | struct workqueue_struct *q; |
193 | 193 | ||
194 | /* datasheet startup in numbered steps, refer to page 3-77 */ | 194 | /* datasheet startup in numbered steps, refer to page 3-77 */ |
195 | /* 2. */ | 195 | /* 2. */ |
196 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | 196 | cx25840_and_or(client, 0x803, ~0x10, 0x00); |
197 | /* The default of this register should be 4, but I get 0 instead. | 197 | /* The default of this register should be 4, but I get 0 instead. |
198 | * Set this register to 4 manually. */ | 198 | * Set this register to 4 manually. */ |
199 | cx25840_write(client, 0x000, 0x04); | 199 | cx25840_write(client, 0x000, 0x04); |
200 | /* 3. */ | 200 | /* 3. */ |
201 | init_dll1(client); | 201 | init_dll1(client); |
202 | init_dll2(client); | 202 | init_dll2(client); |
203 | cx25840_write(client, 0x136, 0x0a); | 203 | cx25840_write(client, 0x136, 0x0a); |
204 | /* 4. */ | 204 | /* 4. */ |
205 | cx25840_write(client, 0x13c, 0x01); | 205 | cx25840_write(client, 0x13c, 0x01); |
206 | cx25840_write(client, 0x13c, 0x00); | 206 | cx25840_write(client, 0x13c, 0x00); |
207 | /* 5. */ | 207 | /* 5. */ |
208 | /* Do the firmware load in a work handler to prevent. | 208 | /* Do the firmware load in a work handler to prevent. |
209 | Otherwise the kernel is blocked waiting for the | 209 | Otherwise the kernel is blocked waiting for the |
210 | bit-banging i2c interface to finish uploading the | 210 | bit-banging i2c interface to finish uploading the |
211 | firmware. */ | 211 | firmware. */ |
212 | INIT_WORK(&state->fw_work, cx25840_work_handler); | 212 | INIT_WORK(&state->fw_work, cx25840_work_handler); |
213 | init_waitqueue_head(&state->fw_wait); | 213 | init_waitqueue_head(&state->fw_wait); |
214 | q = create_singlethread_workqueue("cx25840_fw"); | 214 | q = create_singlethread_workqueue("cx25840_fw"); |
215 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | 215 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); |
216 | queue_work(q, &state->fw_work); | 216 | queue_work(q, &state->fw_work); |
217 | schedule(); | 217 | schedule(); |
218 | finish_wait(&state->fw_wait, &wait); | 218 | finish_wait(&state->fw_wait, &wait); |
219 | destroy_workqueue(q); | 219 | destroy_workqueue(q); |
220 | 220 | ||
221 | /* 6. */ | 221 | /* 6. */ |
222 | cx25840_write(client, 0x115, 0x8c); | 222 | cx25840_write(client, 0x115, 0x8c); |
223 | cx25840_write(client, 0x116, 0x07); | 223 | cx25840_write(client, 0x116, 0x07); |
224 | cx25840_write(client, 0x118, 0x02); | 224 | cx25840_write(client, 0x118, 0x02); |
225 | /* 7. */ | 225 | /* 7. */ |
226 | cx25840_write(client, 0x4a5, 0x80); | 226 | cx25840_write(client, 0x4a5, 0x80); |
227 | cx25840_write(client, 0x4a5, 0x00); | 227 | cx25840_write(client, 0x4a5, 0x00); |
228 | cx25840_write(client, 0x402, 0x00); | 228 | cx25840_write(client, 0x402, 0x00); |
229 | /* 8. */ | 229 | /* 8. */ |
230 | cx25840_and_or(client, 0x401, ~0x18, 0); | 230 | cx25840_and_or(client, 0x401, ~0x18, 0); |
231 | cx25840_and_or(client, 0x4a2, ~0x10, 0x10); | 231 | cx25840_and_or(client, 0x4a2, ~0x10, 0x10); |
232 | /* steps 8c and 8d are done in change_input() */ | 232 | /* steps 8c and 8d are done in change_input() */ |
233 | /* 10. */ | 233 | /* 10. */ |
234 | cx25840_write(client, 0x8d3, 0x1f); | 234 | cx25840_write(client, 0x8d3, 0x1f); |
235 | cx25840_write(client, 0x8e3, 0x03); | 235 | cx25840_write(client, 0x8e3, 0x03); |
236 | 236 | ||
237 | cx25840_std_setup(client); | 237 | cx25840_std_setup(client); |
238 | 238 | ||
239 | /* trial and error says these are needed to get audio */ | 239 | /* trial and error says these are needed to get audio */ |
240 | cx25840_write(client, 0x914, 0xa0); | 240 | cx25840_write(client, 0x914, 0xa0); |
241 | cx25840_write(client, 0x918, 0xa0); | 241 | cx25840_write(client, 0x918, 0xa0); |
242 | cx25840_write(client, 0x919, 0x01); | 242 | cx25840_write(client, 0x919, 0x01); |
243 | 243 | ||
244 | /* stereo prefered */ | 244 | /* stereo prefered */ |
245 | cx25840_write(client, 0x809, 0x04); | 245 | cx25840_write(client, 0x809, 0x04); |
246 | /* AC97 shift */ | 246 | /* AC97 shift */ |
247 | cx25840_write(client, 0x8cf, 0x0f); | 247 | cx25840_write(client, 0x8cf, 0x0f); |
248 | 248 | ||
249 | /* (re)set input */ | 249 | /* (re)set input */ |
250 | set_input(client, state->vid_input, state->aud_input); | 250 | set_input(client, state->vid_input, state->aud_input); |
251 | 251 | ||
252 | /* start microcontroller */ | 252 | /* start microcontroller */ |
253 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 253 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
254 | } | 254 | } |
255 | 255 | ||
256 | static void cx23885_initialize(struct i2c_client *client) | 256 | static void cx23885_initialize(struct i2c_client *client) |
257 | { | 257 | { |
258 | DEFINE_WAIT(wait); | 258 | DEFINE_WAIT(wait); |
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 | /* | 262 | /* |
263 | * Come out of digital power down | 263 | * Come out of digital power down |
264 | * The CX23888, at least, needs this, otherwise registers aside from | 264 | * The CX23888, at least, needs this, otherwise registers aside from |
265 | * 0x0-0x2 can't be read or written. | 265 | * 0x0-0x2 can't be read or written. |
266 | */ | 266 | */ |
267 | cx25840_write(client, 0x000, 0); | 267 | cx25840_write(client, 0x000, 0); |
268 | 268 | ||
269 | /* Internal Reset */ | 269 | /* Internal Reset */ |
270 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | 270 | cx25840_and_or(client, 0x102, ~0x01, 0x01); |
271 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | 271 | cx25840_and_or(client, 0x102, ~0x01, 0x00); |
272 | 272 | ||
273 | /* Stop microcontroller */ | 273 | /* Stop microcontroller */ |
274 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | 274 | cx25840_and_or(client, 0x803, ~0x10, 0x00); |
275 | 275 | ||
276 | /* DIF in reset? */ | 276 | /* DIF in reset? */ |
277 | cx25840_write(client, 0x398, 0); | 277 | cx25840_write(client, 0x398, 0); |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * Trust the default xtal, no division | 280 | * Trust the default xtal, no division |
281 | * '885: 28.636363... MHz | 281 | * '885: 28.636363... MHz |
282 | * '887: 25.000000 MHz | 282 | * '887: 25.000000 MHz |
283 | * '888: 50.000000 MHz | 283 | * '888: 50.000000 MHz |
284 | */ | 284 | */ |
285 | cx25840_write(client, 0x2, 0x76); | 285 | cx25840_write(client, 0x2, 0x76); |
286 | 286 | ||
287 | /* Power up all the PLL's and DLL */ | 287 | /* Power up all the PLL's and DLL */ |
288 | cx25840_write(client, 0x1, 0x40); | 288 | cx25840_write(client, 0x1, 0x40); |
289 | 289 | ||
290 | /* Sys PLL */ | 290 | /* Sys PLL */ |
291 | switch (state->id) { | 291 | switch (state->id) { |
292 | case V4L2_IDENT_CX23888_AV: | 292 | case V4L2_IDENT_CX23888_AV: |
293 | /* | 293 | /* |
294 | * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz | 294 | * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz |
295 | * 572.73 MHz before post divide | 295 | * 572.73 MHz before post divide |
296 | */ | 296 | */ |
297 | cx25840_write4(client, 0x11c, 0x00e8ba26); | 297 | cx25840_write4(client, 0x11c, 0x00e8ba26); |
298 | cx25840_write4(client, 0x118, 0x0000040b); | 298 | cx25840_write4(client, 0x118, 0x0000040b); |
299 | break; | 299 | break; |
300 | case V4L2_IDENT_CX23887_AV: | 300 | case V4L2_IDENT_CX23887_AV: |
301 | /* | 301 | /* |
302 | * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz | 302 | * 25.0 MHz * (0x16 + 0x1d1744c/0x2000000)/4 = 5 * 28.636363 MHz |
303 | * 572.73 MHz before post divide | 303 | * 572.73 MHz before post divide |
304 | */ | 304 | */ |
305 | cx25840_write4(client, 0x11c, 0x01d1744c); | 305 | cx25840_write4(client, 0x11c, 0x01d1744c); |
306 | cx25840_write4(client, 0x118, 0x00000416); | 306 | cx25840_write4(client, 0x118, 0x00000416); |
307 | break; | 307 | break; |
308 | case V4L2_IDENT_CX23885_AV: | 308 | case V4L2_IDENT_CX23885_AV: |
309 | default: | 309 | default: |
310 | /* | 310 | /* |
311 | * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz | 311 | * 28.636363 MHz * (0x14 + 0x0/0x2000000)/4 = 5 * 28.636363 MHz |
312 | * 572.73 MHz before post divide | 312 | * 572.73 MHz before post divide |
313 | */ | 313 | */ |
314 | cx25840_write4(client, 0x11c, 0x00000000); | 314 | cx25840_write4(client, 0x11c, 0x00000000); |
315 | cx25840_write4(client, 0x118, 0x00000414); | 315 | cx25840_write4(client, 0x118, 0x00000414); |
316 | break; | 316 | break; |
317 | } | 317 | } |
318 | 318 | ||
319 | /* Disable DIF bypass */ | 319 | /* Disable DIF bypass */ |
320 | cx25840_write4(client, 0x33c, 0x00000001); | 320 | cx25840_write4(client, 0x33c, 0x00000001); |
321 | 321 | ||
322 | /* DIF Src phase inc */ | 322 | /* DIF Src phase inc */ |
323 | cx25840_write4(client, 0x340, 0x0df7df83); | 323 | cx25840_write4(client, 0x340, 0x0df7df83); |
324 | 324 | ||
325 | /* | 325 | /* |
326 | * Vid PLL | 326 | * Vid PLL |
327 | * Setup for a BT.656 pixel clock of 13.5 Mpixels/second | 327 | * Setup for a BT.656 pixel clock of 13.5 Mpixels/second |
328 | * | 328 | * |
329 | * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz | 329 | * 28.636363 MHz * (0xf + 0x02be2c9/0x2000000)/4 = 8 * 13.5 MHz |
330 | * 432.0 MHz before post divide | 330 | * 432.0 MHz before post divide |
331 | */ | 331 | */ |
332 | cx25840_write4(client, 0x10c, 0x002be2c9); | 332 | cx25840_write4(client, 0x10c, 0x002be2c9); |
333 | cx25840_write4(client, 0x108, 0x0000040f); | 333 | cx25840_write4(client, 0x108, 0x0000040f); |
334 | 334 | ||
335 | /* Luma */ | 335 | /* Luma */ |
336 | cx25840_write4(client, 0x414, 0x00107d12); | 336 | cx25840_write4(client, 0x414, 0x00107d12); |
337 | 337 | ||
338 | /* Chroma */ | 338 | /* Chroma */ |
339 | cx25840_write4(client, 0x420, 0x3d008282); | 339 | cx25840_write4(client, 0x420, 0x3d008282); |
340 | 340 | ||
341 | /* | 341 | /* |
342 | * Aux PLL | 342 | * Aux PLL |
343 | * Initial setup for audio sample clock: | 343 | * Initial setup for audio sample clock: |
344 | * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz | 344 | * 48 ksps, 16 bits/sample, x160 multiplier = 122.88 MHz |
345 | * Intial I2S output/master clock(?): | 345 | * Intial I2S output/master clock(?): |
346 | * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz | 346 | * 48 ksps, 16 bits/sample, x16 multiplier = 12.288 MHz |
347 | */ | 347 | */ |
348 | switch (state->id) { | 348 | switch (state->id) { |
349 | case V4L2_IDENT_CX23888_AV: | 349 | case V4L2_IDENT_CX23888_AV: |
350 | /* | 350 | /* |
351 | * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz | 351 | * 50.0 MHz * (0x7 + 0x0bedfa4/0x2000000)/3 = 122.88 MHz |
352 | * 368.64 MHz before post divide | 352 | * 368.64 MHz before post divide |
353 | * 122.88 MHz / 0xa = 12.288 MHz | 353 | * 122.88 MHz / 0xa = 12.288 MHz |
354 | */ | 354 | */ |
355 | cx25840_write4(client, 0x114, 0x00bedfa4); | 355 | cx25840_write4(client, 0x114, 0x00bedfa4); |
356 | cx25840_write4(client, 0x110, 0x000a0307); | 356 | cx25840_write4(client, 0x110, 0x000a0307); |
357 | break; | 357 | break; |
358 | case V4L2_IDENT_CX23887_AV: | 358 | case V4L2_IDENT_CX23887_AV: |
359 | /* | 359 | /* |
360 | * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz | 360 | * 25.0 MHz * (0xe + 0x17dbf48/0x2000000)/3 = 122.88 MHz |
361 | * 368.64 MHz before post divide | 361 | * 368.64 MHz before post divide |
362 | * 122.88 MHz / 0xa = 12.288 MHz | 362 | * 122.88 MHz / 0xa = 12.288 MHz |
363 | */ | 363 | */ |
364 | cx25840_write4(client, 0x114, 0x017dbf48); | 364 | cx25840_write4(client, 0x114, 0x017dbf48); |
365 | cx25840_write4(client, 0x110, 0x000a030e); | 365 | cx25840_write4(client, 0x110, 0x000a030e); |
366 | break; | 366 | break; |
367 | case V4L2_IDENT_CX23885_AV: | 367 | case V4L2_IDENT_CX23885_AV: |
368 | default: | 368 | default: |
369 | /* | 369 | /* |
370 | * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz | 370 | * 28.636363 MHz * (0xc + 0x1bf0c9e/0x2000000)/3 = 122.88 MHz |
371 | * 368.64 MHz before post divide | 371 | * 368.64 MHz before post divide |
372 | * 122.88 MHz / 0xa = 12.288 MHz | 372 | * 122.88 MHz / 0xa = 12.288 MHz |
373 | */ | 373 | */ |
374 | cx25840_write4(client, 0x114, 0x01bf0c9e); | 374 | cx25840_write4(client, 0x114, 0x01bf0c9e); |
375 | cx25840_write4(client, 0x110, 0x000a030c); | 375 | cx25840_write4(client, 0x110, 0x000a030c); |
376 | break; | 376 | break; |
377 | }; | 377 | }; |
378 | 378 | ||
379 | /* ADC2 input select */ | 379 | /* ADC2 input select */ |
380 | cx25840_write(client, 0x102, 0x10); | 380 | cx25840_write(client, 0x102, 0x10); |
381 | 381 | ||
382 | /* VIN1 & VIN5 */ | 382 | /* VIN1 & VIN5 */ |
383 | cx25840_write(client, 0x103, 0x11); | 383 | cx25840_write(client, 0x103, 0x11); |
384 | 384 | ||
385 | /* Enable format auto detect */ | 385 | /* Enable format auto detect */ |
386 | cx25840_write(client, 0x400, 0); | 386 | cx25840_write(client, 0x400, 0); |
387 | /* Fast subchroma lock */ | 387 | /* Fast subchroma lock */ |
388 | /* White crush, Chroma AGC & Chroma Killer enabled */ | 388 | /* White crush, Chroma AGC & Chroma Killer enabled */ |
389 | cx25840_write(client, 0x401, 0xe8); | 389 | cx25840_write(client, 0x401, 0xe8); |
390 | 390 | ||
391 | /* Select AFE clock pad output source */ | 391 | /* Select AFE clock pad output source */ |
392 | cx25840_write(client, 0x144, 0x05); | 392 | cx25840_write(client, 0x144, 0x05); |
393 | 393 | ||
394 | /* Drive GPIO2 direction and values for HVR1700 | 394 | /* Drive GPIO2 direction and values for HVR1700 |
395 | * where an onboard mux selects the output of demodulator | 395 | * where an onboard mux selects the output of demodulator |
396 | * vs the 417. Failure to set this results in no DTV. | 396 | * vs the 417. Failure to set this results in no DTV. |
397 | * It's safe to set this across all Hauppauge boards | 397 | * It's safe to set this across all Hauppauge boards |
398 | * currently, regardless of the board type. | 398 | * currently, regardless of the board type. |
399 | */ | 399 | */ |
400 | cx25840_write(client, 0x160, 0x1d); | 400 | cx25840_write(client, 0x160, 0x1d); |
401 | cx25840_write(client, 0x164, 0x00); | 401 | cx25840_write(client, 0x164, 0x00); |
402 | 402 | ||
403 | /* Do the firmware load in a work handler to prevent. | 403 | /* Do the firmware load in a work handler to prevent. |
404 | Otherwise the kernel is blocked waiting for the | 404 | Otherwise the kernel is blocked waiting for the |
405 | bit-banging i2c interface to finish uploading the | 405 | bit-banging i2c interface to finish uploading the |
406 | firmware. */ | 406 | firmware. */ |
407 | INIT_WORK(&state->fw_work, cx25840_work_handler); | 407 | INIT_WORK(&state->fw_work, cx25840_work_handler); |
408 | init_waitqueue_head(&state->fw_wait); | 408 | init_waitqueue_head(&state->fw_wait); |
409 | q = create_singlethread_workqueue("cx25840_fw"); | 409 | q = create_singlethread_workqueue("cx25840_fw"); |
410 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | 410 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); |
411 | queue_work(q, &state->fw_work); | 411 | queue_work(q, &state->fw_work); |
412 | schedule(); | 412 | schedule(); |
413 | finish_wait(&state->fw_wait, &wait); | 413 | finish_wait(&state->fw_wait, &wait); |
414 | destroy_workqueue(q); | 414 | destroy_workqueue(q); |
415 | 415 | ||
416 | cx25840_std_setup(client); | 416 | cx25840_std_setup(client); |
417 | 417 | ||
418 | /* (re)set input */ | 418 | /* (re)set input */ |
419 | set_input(client, state->vid_input, state->aud_input); | 419 | set_input(client, state->vid_input, state->aud_input); |
420 | 420 | ||
421 | /* start microcontroller */ | 421 | /* start microcontroller */ |
422 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 422 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
423 | } | 423 | } |
424 | 424 | ||
425 | /* ----------------------------------------------------------------------- */ | 425 | /* ----------------------------------------------------------------------- */ |
426 | 426 | ||
427 | static void cx231xx_initialize(struct i2c_client *client) | 427 | static void cx231xx_initialize(struct i2c_client *client) |
428 | { | 428 | { |
429 | DEFINE_WAIT(wait); | 429 | DEFINE_WAIT(wait); |
430 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 430 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
431 | struct workqueue_struct *q; | 431 | struct workqueue_struct *q; |
432 | 432 | ||
433 | /* Internal Reset */ | 433 | /* Internal Reset */ |
434 | cx25840_and_or(client, 0x102, ~0x01, 0x01); | 434 | cx25840_and_or(client, 0x102, ~0x01, 0x01); |
435 | cx25840_and_or(client, 0x102, ~0x01, 0x00); | 435 | cx25840_and_or(client, 0x102, ~0x01, 0x00); |
436 | 436 | ||
437 | /* Stop microcontroller */ | 437 | /* Stop microcontroller */ |
438 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | 438 | cx25840_and_or(client, 0x803, ~0x10, 0x00); |
439 | 439 | ||
440 | /* DIF in reset? */ | 440 | /* DIF in reset? */ |
441 | cx25840_write(client, 0x398, 0); | 441 | cx25840_write(client, 0x398, 0); |
442 | 442 | ||
443 | /* Trust the default xtal, no division */ | 443 | /* Trust the default xtal, no division */ |
444 | /* This changes for the cx23888 products */ | 444 | /* This changes for the cx23888 products */ |
445 | cx25840_write(client, 0x2, 0x76); | 445 | cx25840_write(client, 0x2, 0x76); |
446 | 446 | ||
447 | /* Bring down the regulator for AUX clk */ | 447 | /* Bring down the regulator for AUX clk */ |
448 | cx25840_write(client, 0x1, 0x40); | 448 | cx25840_write(client, 0x1, 0x40); |
449 | 449 | ||
450 | /* Disable DIF bypass */ | 450 | /* Disable DIF bypass */ |
451 | cx25840_write4(client, 0x33c, 0x00000001); | 451 | cx25840_write4(client, 0x33c, 0x00000001); |
452 | 452 | ||
453 | /* DIF Src phase inc */ | 453 | /* DIF Src phase inc */ |
454 | cx25840_write4(client, 0x340, 0x0df7df83); | 454 | cx25840_write4(client, 0x340, 0x0df7df83); |
455 | 455 | ||
456 | /* Luma */ | 456 | /* Luma */ |
457 | cx25840_write4(client, 0x414, 0x00107d12); | 457 | cx25840_write4(client, 0x414, 0x00107d12); |
458 | 458 | ||
459 | /* Chroma */ | 459 | /* Chroma */ |
460 | cx25840_write4(client, 0x420, 0x3d008282); | 460 | cx25840_write4(client, 0x420, 0x3d008282); |
461 | 461 | ||
462 | /* ADC2 input select */ | 462 | /* ADC2 input select */ |
463 | cx25840_write(client, 0x102, 0x10); | 463 | cx25840_write(client, 0x102, 0x10); |
464 | 464 | ||
465 | /* VIN1 & VIN5 */ | 465 | /* VIN1 & VIN5 */ |
466 | cx25840_write(client, 0x103, 0x11); | 466 | cx25840_write(client, 0x103, 0x11); |
467 | 467 | ||
468 | /* Enable format auto detect */ | 468 | /* Enable format auto detect */ |
469 | cx25840_write(client, 0x400, 0); | 469 | cx25840_write(client, 0x400, 0); |
470 | /* Fast subchroma lock */ | 470 | /* Fast subchroma lock */ |
471 | /* White crush, Chroma AGC & Chroma Killer enabled */ | 471 | /* White crush, Chroma AGC & Chroma Killer enabled */ |
472 | cx25840_write(client, 0x401, 0xe8); | 472 | cx25840_write(client, 0x401, 0xe8); |
473 | 473 | ||
474 | /* Do the firmware load in a work handler to prevent. | 474 | /* Do the firmware load in a work handler to prevent. |
475 | Otherwise the kernel is blocked waiting for the | 475 | Otherwise the kernel is blocked waiting for the |
476 | bit-banging i2c interface to finish uploading the | 476 | bit-banging i2c interface to finish uploading the |
477 | firmware. */ | 477 | firmware. */ |
478 | INIT_WORK(&state->fw_work, cx25840_work_handler); | 478 | INIT_WORK(&state->fw_work, cx25840_work_handler); |
479 | init_waitqueue_head(&state->fw_wait); | 479 | init_waitqueue_head(&state->fw_wait); |
480 | q = create_singlethread_workqueue("cx25840_fw"); | 480 | q = create_singlethread_workqueue("cx25840_fw"); |
481 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); | 481 | prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); |
482 | queue_work(q, &state->fw_work); | 482 | queue_work(q, &state->fw_work); |
483 | schedule(); | 483 | schedule(); |
484 | finish_wait(&state->fw_wait, &wait); | 484 | finish_wait(&state->fw_wait, &wait); |
485 | destroy_workqueue(q); | 485 | destroy_workqueue(q); |
486 | 486 | ||
487 | cx25840_std_setup(client); | 487 | cx25840_std_setup(client); |
488 | 488 | ||
489 | /* (re)set input */ | 489 | /* (re)set input */ |
490 | set_input(client, state->vid_input, state->aud_input); | 490 | set_input(client, state->vid_input, state->aud_input); |
491 | 491 | ||
492 | /* start microcontroller */ | 492 | /* start microcontroller */ |
493 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | 493 | cx25840_and_or(client, 0x803, ~0x10, 0x10); |
494 | } | 494 | } |
495 | 495 | ||
496 | /* ----------------------------------------------------------------------- */ | 496 | /* ----------------------------------------------------------------------- */ |
497 | 497 | ||
498 | void cx25840_std_setup(struct i2c_client *client) | 498 | void cx25840_std_setup(struct i2c_client *client) |
499 | { | 499 | { |
500 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 500 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
501 | v4l2_std_id std = state->std; | 501 | v4l2_std_id std = state->std; |
502 | int hblank, hactive, burst, vblank, vactive, sc; | 502 | int hblank, hactive, burst, vblank, vactive, sc; |
503 | int vblank656, src_decimation; | 503 | int vblank656, src_decimation; |
504 | int luma_lpf, uv_lpf, comb; | 504 | int luma_lpf, uv_lpf, comb; |
505 | u32 pll_int, pll_frac, pll_post; | 505 | u32 pll_int, pll_frac, pll_post; |
506 | 506 | ||
507 | /* datasheet startup, step 8d */ | 507 | /* datasheet startup, step 8d */ |
508 | if (std & ~V4L2_STD_NTSC) | 508 | if (std & ~V4L2_STD_NTSC) |
509 | cx25840_write(client, 0x49f, 0x11); | 509 | cx25840_write(client, 0x49f, 0x11); |
510 | else | 510 | else |
511 | cx25840_write(client, 0x49f, 0x14); | 511 | cx25840_write(client, 0x49f, 0x14); |
512 | 512 | ||
513 | if (std & V4L2_STD_625_50) { | 513 | if (std & V4L2_STD_625_50) { |
514 | hblank = 132; | 514 | hblank = 132; |
515 | hactive = 720; | 515 | hactive = 720; |
516 | burst = 93; | 516 | burst = 93; |
517 | vblank = 36; | 517 | vblank = 36; |
518 | vactive = 580; | 518 | vactive = 580; |
519 | vblank656 = 40; | 519 | vblank656 = 40; |
520 | src_decimation = 0x21f; | 520 | src_decimation = 0x21f; |
521 | luma_lpf = 2; | 521 | luma_lpf = 2; |
522 | 522 | ||
523 | if (std & V4L2_STD_SECAM) { | 523 | if (std & V4L2_STD_SECAM) { |
524 | uv_lpf = 0; | 524 | uv_lpf = 0; |
525 | comb = 0; | 525 | comb = 0; |
526 | sc = 0x0a425f; | 526 | sc = 0x0a425f; |
527 | } else if (std == V4L2_STD_PAL_Nc) { | 527 | } else if (std == V4L2_STD_PAL_Nc) { |
528 | uv_lpf = 1; | 528 | uv_lpf = 1; |
529 | comb = 0x20; | 529 | comb = 0x20; |
530 | sc = 556453; | 530 | sc = 556453; |
531 | } else { | 531 | } else { |
532 | uv_lpf = 1; | 532 | uv_lpf = 1; |
533 | comb = 0x20; | 533 | comb = 0x20; |
534 | sc = 688739; | 534 | sc = 688739; |
535 | } | 535 | } |
536 | } else { | 536 | } else { |
537 | hactive = 720; | 537 | hactive = 720; |
538 | hblank = 122; | 538 | hblank = 122; |
539 | vactive = 487; | 539 | vactive = 487; |
540 | luma_lpf = 1; | 540 | luma_lpf = 1; |
541 | uv_lpf = 1; | 541 | uv_lpf = 1; |
542 | 542 | ||
543 | src_decimation = 0x21f; | 543 | src_decimation = 0x21f; |
544 | if (std == V4L2_STD_PAL_60) { | 544 | if (std == V4L2_STD_PAL_60) { |
545 | vblank = 26; | 545 | vblank = 26; |
546 | vblank656 = 26; | 546 | vblank656 = 26; |
547 | burst = 0x5b; | 547 | burst = 0x5b; |
548 | luma_lpf = 2; | 548 | luma_lpf = 2; |
549 | comb = 0x20; | 549 | comb = 0x20; |
550 | sc = 688739; | 550 | sc = 688739; |
551 | } else if (std == V4L2_STD_PAL_M) { | 551 | } else if (std == V4L2_STD_PAL_M) { |
552 | vblank = 20; | 552 | vblank = 20; |
553 | vblank656 = 24; | 553 | vblank656 = 24; |
554 | burst = 0x61; | 554 | burst = 0x61; |
555 | comb = 0x20; | 555 | comb = 0x20; |
556 | sc = 555452; | 556 | sc = 555452; |
557 | } else { | 557 | } else { |
558 | vblank = 26; | 558 | vblank = 26; |
559 | vblank656 = 26; | 559 | vblank656 = 26; |
560 | burst = 0x5b; | 560 | burst = 0x5b; |
561 | comb = 0x66; | 561 | comb = 0x66; |
562 | sc = 556063; | 562 | sc = 556063; |
563 | } | 563 | } |
564 | } | 564 | } |
565 | 565 | ||
566 | /* DEBUG: Displays configured PLL frequency */ | 566 | /* DEBUG: Displays configured PLL frequency */ |
567 | if (!is_cx231xx(state)) { | 567 | if (!is_cx231xx(state)) { |
568 | pll_int = cx25840_read(client, 0x108); | 568 | pll_int = cx25840_read(client, 0x108); |
569 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; | 569 | pll_frac = cx25840_read4(client, 0x10c) & 0x1ffffff; |
570 | pll_post = cx25840_read(client, 0x109); | 570 | pll_post = cx25840_read(client, 0x109); |
571 | v4l_dbg(1, cx25840_debug, client, | 571 | v4l_dbg(1, cx25840_debug, client, |
572 | "PLL regs = int: %u, frac: %u, post: %u\n", | 572 | "PLL regs = int: %u, frac: %u, post: %u\n", |
573 | pll_int, pll_frac, pll_post); | 573 | pll_int, pll_frac, pll_post); |
574 | 574 | ||
575 | if (pll_post) { | 575 | if (pll_post) { |
576 | int fin, fsc; | 576 | int fin, fsc; |
577 | int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; | 577 | int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; |
578 | 578 | ||
579 | pll /= pll_post; | 579 | pll /= pll_post; |
580 | v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", | 580 | v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", |
581 | pll / 1000000, pll % 1000000); | 581 | pll / 1000000, pll % 1000000); |
582 | v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", | 582 | v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", |
583 | pll / 8000000, (pll / 8) % 1000000); | 583 | pll / 8000000, (pll / 8) % 1000000); |
584 | 584 | ||
585 | fin = ((u64)src_decimation * pll) >> 12; | 585 | fin = ((u64)src_decimation * pll) >> 12; |
586 | v4l_dbg(1, cx25840_debug, client, | 586 | v4l_dbg(1, cx25840_debug, client, |
587 | "ADC Sampling freq = %d.%06d MHz\n", | 587 | "ADC Sampling freq = %d.%06d MHz\n", |
588 | fin / 1000000, fin % 1000000); | 588 | fin / 1000000, fin % 1000000); |
589 | 589 | ||
590 | fsc = (((u64)sc) * pll) >> 24L; | 590 | fsc = (((u64)sc) * pll) >> 24L; |
591 | v4l_dbg(1, cx25840_debug, client, | 591 | v4l_dbg(1, cx25840_debug, client, |
592 | "Chroma sub-carrier freq = %d.%06d MHz\n", | 592 | "Chroma sub-carrier freq = %d.%06d MHz\n", |
593 | fsc / 1000000, fsc % 1000000); | 593 | fsc / 1000000, fsc % 1000000); |
594 | 594 | ||
595 | v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " | 595 | v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " |
596 | "vblank %i, vactive %i, vblank656 %i, src_dec %i, " | 596 | "vblank %i, vactive %i, vblank656 %i, src_dec %i, " |
597 | "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " | 597 | "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " |
598 | "sc 0x%06x\n", | 598 | "sc 0x%06x\n", |
599 | hblank, hactive, vblank, vactive, vblank656, | 599 | hblank, hactive, vblank, vactive, vblank656, |
600 | src_decimation, burst, luma_lpf, uv_lpf, comb, sc); | 600 | src_decimation, burst, luma_lpf, uv_lpf, comb, sc); |
601 | } | 601 | } |
602 | } | 602 | } |
603 | 603 | ||
604 | /* Sets horizontal blanking delay and active lines */ | 604 | /* Sets horizontal blanking delay and active lines */ |
605 | cx25840_write(client, 0x470, hblank); | 605 | cx25840_write(client, 0x470, hblank); |
606 | cx25840_write(client, 0x471, | 606 | cx25840_write(client, 0x471, |
607 | 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); | 607 | 0xff & (((hblank >> 8) & 0x3) | (hactive << 4))); |
608 | cx25840_write(client, 0x472, hactive >> 4); | 608 | cx25840_write(client, 0x472, hactive >> 4); |
609 | 609 | ||
610 | /* Sets burst gate delay */ | 610 | /* Sets burst gate delay */ |
611 | cx25840_write(client, 0x473, burst); | 611 | cx25840_write(client, 0x473, burst); |
612 | 612 | ||
613 | /* Sets vertical blanking delay and active duration */ | 613 | /* Sets vertical blanking delay and active duration */ |
614 | cx25840_write(client, 0x474, vblank); | 614 | cx25840_write(client, 0x474, vblank); |
615 | cx25840_write(client, 0x475, | 615 | cx25840_write(client, 0x475, |
616 | 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); | 616 | 0xff & (((vblank >> 8) & 0x3) | (vactive << 4))); |
617 | cx25840_write(client, 0x476, vactive >> 4); | 617 | cx25840_write(client, 0x476, vactive >> 4); |
618 | cx25840_write(client, 0x477, vblank656); | 618 | cx25840_write(client, 0x477, vblank656); |
619 | 619 | ||
620 | /* Sets src decimation rate */ | 620 | /* Sets src decimation rate */ |
621 | cx25840_write(client, 0x478, 0xff & src_decimation); | 621 | cx25840_write(client, 0x478, 0xff & src_decimation); |
622 | cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); | 622 | cx25840_write(client, 0x479, 0xff & (src_decimation >> 8)); |
623 | 623 | ||
624 | /* Sets Luma and UV Low pass filters */ | 624 | /* Sets Luma and UV Low pass filters */ |
625 | cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); | 625 | cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); |
626 | 626 | ||
627 | /* Enables comb filters */ | 627 | /* Enables comb filters */ |
628 | cx25840_write(client, 0x47b, comb); | 628 | cx25840_write(client, 0x47b, comb); |
629 | 629 | ||
630 | /* Sets SC Step*/ | 630 | /* Sets SC Step*/ |
631 | cx25840_write(client, 0x47c, sc); | 631 | cx25840_write(client, 0x47c, sc); |
632 | cx25840_write(client, 0x47d, 0xff & sc >> 8); | 632 | cx25840_write(client, 0x47d, 0xff & sc >> 8); |
633 | cx25840_write(client, 0x47e, 0xff & sc >> 16); | 633 | cx25840_write(client, 0x47e, 0xff & sc >> 16); |
634 | 634 | ||
635 | /* Sets VBI parameters */ | 635 | /* Sets VBI parameters */ |
636 | if (std & V4L2_STD_625_50) { | 636 | if (std & V4L2_STD_625_50) { |
637 | cx25840_write(client, 0x47f, 0x01); | 637 | cx25840_write(client, 0x47f, 0x01); |
638 | state->vbi_line_offset = 5; | 638 | state->vbi_line_offset = 5; |
639 | } else { | 639 | } else { |
640 | cx25840_write(client, 0x47f, 0x00); | 640 | cx25840_write(client, 0x47f, 0x00); |
641 | state->vbi_line_offset = 8; | 641 | state->vbi_line_offset = 8; |
642 | } | 642 | } |
643 | } | 643 | } |
644 | 644 | ||
645 | /* ----------------------------------------------------------------------- */ | 645 | /* ----------------------------------------------------------------------- */ |
646 | 646 | ||
647 | static void input_change(struct i2c_client *client) | 647 | static void input_change(struct i2c_client *client) |
648 | { | 648 | { |
649 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 649 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
650 | v4l2_std_id std = state->std; | 650 | v4l2_std_id std = state->std; |
651 | 651 | ||
652 | /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ | 652 | /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ |
653 | if (std & V4L2_STD_SECAM) { | 653 | if (std & V4L2_STD_SECAM) { |
654 | cx25840_write(client, 0x402, 0); | 654 | cx25840_write(client, 0x402, 0); |
655 | } | 655 | } |
656 | else { | 656 | else { |
657 | cx25840_write(client, 0x402, 0x04); | 657 | cx25840_write(client, 0x402, 0x04); |
658 | cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); | 658 | cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); |
659 | } | 659 | } |
660 | cx25840_and_or(client, 0x401, ~0x60, 0); | 660 | cx25840_and_or(client, 0x401, ~0x60, 0); |
661 | cx25840_and_or(client, 0x401, ~0x60, 0x60); | 661 | cx25840_and_or(client, 0x401, ~0x60, 0x60); |
662 | cx25840_and_or(client, 0x810, ~0x01, 1); | 662 | cx25840_and_or(client, 0x810, ~0x01, 1); |
663 | 663 | ||
664 | if (state->radio) { | 664 | if (state->radio) { |
665 | cx25840_write(client, 0x808, 0xf9); | 665 | cx25840_write(client, 0x808, 0xf9); |
666 | cx25840_write(client, 0x80b, 0x00); | 666 | cx25840_write(client, 0x80b, 0x00); |
667 | } | 667 | } |
668 | else if (std & V4L2_STD_525_60) { | 668 | else if (std & V4L2_STD_525_60) { |
669 | /* Certain Hauppauge PVR150 models have a hardware bug | 669 | /* Certain Hauppauge PVR150 models have a hardware bug |
670 | that causes audio to drop out. For these models the | 670 | that causes audio to drop out. For these models the |
671 | audio standard must be set explicitly. | 671 | audio standard must be set explicitly. |
672 | To be precise: it affects cards with tuner models | 672 | To be precise: it affects cards with tuner models |
673 | 85, 99 and 112 (model numbers from tveeprom). */ | 673 | 85, 99 and 112 (model numbers from tveeprom). */ |
674 | int hw_fix = state->pvr150_workaround; | 674 | int hw_fix = state->pvr150_workaround; |
675 | 675 | ||
676 | if (std == V4L2_STD_NTSC_M_JP) { | 676 | if (std == V4L2_STD_NTSC_M_JP) { |
677 | /* Japan uses EIAJ audio standard */ | 677 | /* Japan uses EIAJ audio standard */ |
678 | cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7); | 678 | cx25840_write(client, 0x808, hw_fix ? 0x2f : 0xf7); |
679 | } else if (std == V4L2_STD_NTSC_M_KR) { | 679 | } else if (std == V4L2_STD_NTSC_M_KR) { |
680 | /* South Korea uses A2 audio standard */ | 680 | /* South Korea uses A2 audio standard */ |
681 | cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8); | 681 | cx25840_write(client, 0x808, hw_fix ? 0x3f : 0xf8); |
682 | } else { | 682 | } else { |
683 | /* Others use the BTSC audio standard */ | 683 | /* Others use the BTSC audio standard */ |
684 | cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6); | 684 | cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6); |
685 | } | 685 | } |
686 | cx25840_write(client, 0x80b, 0x00); | 686 | cx25840_write(client, 0x80b, 0x00); |
687 | } else if (std & V4L2_STD_PAL) { | 687 | } else if (std & V4L2_STD_PAL) { |
688 | /* Follow tuner change procedure for PAL */ | 688 | /* Follow tuner change procedure for PAL */ |
689 | cx25840_write(client, 0x808, 0xff); | 689 | cx25840_write(client, 0x808, 0xff); |
690 | cx25840_write(client, 0x80b, 0x10); | 690 | cx25840_write(client, 0x80b, 0x10); |
691 | } else if (std & V4L2_STD_SECAM) { | 691 | } else if (std & V4L2_STD_SECAM) { |
692 | /* Select autodetect for SECAM */ | 692 | /* Select autodetect for SECAM */ |
693 | cx25840_write(client, 0x808, 0xff); | 693 | cx25840_write(client, 0x808, 0xff); |
694 | cx25840_write(client, 0x80b, 0x10); | 694 | cx25840_write(client, 0x80b, 0x10); |
695 | } | 695 | } |
696 | 696 | ||
697 | cx25840_and_or(client, 0x810, ~0x01, 0); | 697 | cx25840_and_or(client, 0x810, ~0x01, 0); |
698 | } | 698 | } |
699 | 699 | ||
700 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, | 700 | static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, |
701 | enum cx25840_audio_input aud_input) | 701 | enum cx25840_audio_input aud_input) |
702 | { | 702 | { |
703 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 703 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
704 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && | 704 | u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && |
705 | vid_input <= CX25840_COMPOSITE8); | 705 | vid_input <= CX25840_COMPOSITE8); |
706 | u8 is_component = (vid_input & CX25840_COMPONENT_ON) == | ||
707 | CX25840_COMPONENT_ON; | ||
708 | int luma = vid_input & 0xf0; | ||
709 | int chroma = vid_input & 0xf00; | ||
706 | u8 reg; | 710 | u8 reg; |
707 | 711 | ||
708 | v4l_dbg(1, cx25840_debug, client, | 712 | v4l_dbg(1, cx25840_debug, client, |
709 | "decoder set video input %d, audio input %d\n", | 713 | "decoder set video input %d, audio input %d\n", |
710 | vid_input, aud_input); | 714 | vid_input, aud_input); |
711 | 715 | ||
712 | if (vid_input >= CX25840_VIN1_CH1) { | 716 | if (vid_input >= CX25840_VIN1_CH1) { |
713 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", | 717 | v4l_dbg(1, cx25840_debug, client, "vid_input 0x%x\n", |
714 | vid_input); | 718 | vid_input); |
715 | reg = vid_input & 0xff; | 719 | reg = vid_input & 0xff; |
716 | if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) | 720 | if ((vid_input & CX25840_SVIDEO_ON) == CX25840_SVIDEO_ON) |
717 | is_composite = 0; | 721 | is_composite = 0; |
718 | else | 722 | else if ((vid_input & CX25840_COMPONENT_ON) == 0) |
719 | is_composite = 1; | 723 | is_composite = 1; |
720 | 724 | ||
721 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", | 725 | v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", |
722 | reg, is_composite); | 726 | reg, is_composite); |
723 | } else | 727 | } else if (is_composite) { |
724 | if (is_composite) { | ||
725 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); | 728 | reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); |
726 | } else { | 729 | } else { |
727 | int luma = vid_input & 0xf0; | ||
728 | int chroma = vid_input & 0xf00; | ||
729 | |||
730 | if ((vid_input & ~0xff0) || | 730 | if ((vid_input & ~0xff0) || |
731 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || | 731 | luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || |
732 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { | 732 | chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { |
733 | v4l_err(client, "0x%04x is not a valid video input!\n", | 733 | v4l_err(client, "0x%04x is not a valid video input!\n", |
734 | vid_input); | 734 | vid_input); |
735 | return -EINVAL; | 735 | return -EINVAL; |
736 | } | 736 | } |
737 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); | 737 | reg = 0xf0 + ((luma - CX25840_SVIDEO_LUMA1) >> 4); |
738 | if (chroma >= CX25840_SVIDEO_CHROMA7) { | 738 | if (chroma >= CX25840_SVIDEO_CHROMA7) { |
739 | reg &= 0x3f; | 739 | reg &= 0x3f; |
740 | reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; | 740 | reg |= (chroma - CX25840_SVIDEO_CHROMA7) >> 2; |
741 | } else { | 741 | } else { |
742 | reg &= 0xcf; | 742 | reg &= 0xcf; |
743 | reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; | 743 | reg |= (chroma - CX25840_SVIDEO_CHROMA4) >> 4; |
744 | } | 744 | } |
745 | } | 745 | } |
746 | 746 | ||
747 | /* The caller has previously prepared the correct routing | 747 | /* The caller has previously prepared the correct routing |
748 | * configuration in reg (for the cx23885) so we have no | 748 | * configuration in reg (for the cx23885) so we have no |
749 | * need to attempt to flip bits for earlier av decoders. | 749 | * need to attempt to flip bits for earlier av decoders. |
750 | */ | 750 | */ |
751 | if (!is_cx2388x(state) && !is_cx231xx(state)) { | 751 | if (!is_cx2388x(state) && !is_cx231xx(state)) { |
752 | switch (aud_input) { | 752 | switch (aud_input) { |
753 | case CX25840_AUDIO_SERIAL: | 753 | case CX25840_AUDIO_SERIAL: |
754 | /* do nothing, use serial audio input */ | 754 | /* do nothing, use serial audio input */ |
755 | break; | 755 | break; |
756 | case CX25840_AUDIO4: reg &= ~0x30; break; | 756 | case CX25840_AUDIO4: reg &= ~0x30; break; |
757 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; | 757 | case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; |
758 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; | 758 | case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; |
759 | case CX25840_AUDIO7: reg &= ~0xc0; break; | 759 | case CX25840_AUDIO7: reg &= ~0xc0; break; |
760 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; | 760 | case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; |
761 | 761 | ||
762 | default: | 762 | default: |
763 | v4l_err(client, "0x%04x is not a valid audio input!\n", | 763 | v4l_err(client, "0x%04x is not a valid audio input!\n", |
764 | aud_input); | 764 | aud_input); |
765 | return -EINVAL; | 765 | return -EINVAL; |
766 | } | 766 | } |
767 | } | 767 | } |
768 | 768 | ||
769 | cx25840_write(client, 0x103, reg); | 769 | cx25840_write(client, 0x103, reg); |
770 | 770 | ||
771 | /* Set INPUT_MODE to Composite (0) or S-Video (1) */ | 771 | /* Set INPUT_MODE to Composite, S-Video or Component */ |
772 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | 772 | if (is_component) |
773 | cx25840_and_or(client, 0x401, ~0x6, 0x6); | ||
774 | else | ||
775 | cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); | ||
773 | 776 | ||
774 | if (!is_cx2388x(state) && !is_cx231xx(state)) { | 777 | if (!is_cx2388x(state) && !is_cx231xx(state)) { |
775 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ | 778 | /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ |
776 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); | 779 | cx25840_and_or(client, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); |
777 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ | 780 | /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2&CH3 */ |
778 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) | 781 | if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) |
779 | cx25840_and_or(client, 0x102, ~0x4, 4); | 782 | cx25840_and_or(client, 0x102, ~0x4, 4); |
780 | else | 783 | else |
781 | cx25840_and_or(client, 0x102, ~0x4, 0); | 784 | cx25840_and_or(client, 0x102, ~0x4, 0); |
782 | } else { | 785 | } else { |
783 | if (is_composite) | 786 | /* Set DUAL_MODE_ADC2 to 1 if component*/ |
787 | cx25840_and_or(client, 0x102, ~0x4, is_component ? 0x4 : 0x0); | ||
788 | if (is_composite) { | ||
784 | /* ADC2 input select channel 2 */ | 789 | /* ADC2 input select channel 2 */ |
785 | cx25840_and_or(client, 0x102, ~0x2, 0); | 790 | cx25840_and_or(client, 0x102, ~0x2, 0); |
786 | else | 791 | } else if (!is_component) { |
787 | /* ADC2 input select channel 3 */ | 792 | /* S-Video */ |
788 | cx25840_and_or(client, 0x102, ~0x2, 2); | 793 | if (chroma >= CX25840_SVIDEO_CHROMA7) { |
794 | /* ADC2 input select channel 3 */ | ||
795 | cx25840_and_or(client, 0x102, ~0x2, 2); | ||
796 | } else { | ||
797 | /* ADC2 input select channel 2 */ | ||
798 | cx25840_and_or(client, 0x102, ~0x2, 0); | ||
799 | } | ||
800 | } | ||
789 | } | 801 | } |
790 | 802 | ||
791 | state->vid_input = vid_input; | 803 | state->vid_input = vid_input; |
792 | state->aud_input = aud_input; | 804 | state->aud_input = aud_input; |
793 | if (!is_cx2583x(state)) { | 805 | if (!is_cx2583x(state)) { |
794 | cx25840_audio_set_path(client); | 806 | cx25840_audio_set_path(client); |
795 | input_change(client); | 807 | input_change(client); |
796 | } | 808 | } |
797 | 809 | ||
798 | if (is_cx2388x(state)) { | 810 | if (is_cx2388x(state)) { |
799 | /* Audio channel 1 src : Parallel 1 */ | 811 | /* Audio channel 1 src : Parallel 1 */ |
800 | cx25840_write(client, 0x124, 0x03); | 812 | cx25840_write(client, 0x124, 0x03); |
801 | 813 | ||
802 | /* Select AFE clock pad output source */ | 814 | /* Select AFE clock pad output source */ |
803 | cx25840_write(client, 0x144, 0x05); | 815 | cx25840_write(client, 0x144, 0x05); |
804 | 816 | ||
805 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | 817 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ |
806 | cx25840_write(client, 0x914, 0xa0); | 818 | cx25840_write(client, 0x914, 0xa0); |
807 | 819 | ||
808 | /* I2S_OUT_CTL: | 820 | /* I2S_OUT_CTL: |
809 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | 821 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 |
810 | * I2S_OUT_MASTER_MODE = Master | 822 | * I2S_OUT_MASTER_MODE = Master |
811 | */ | 823 | */ |
812 | cx25840_write(client, 0x918, 0xa0); | 824 | cx25840_write(client, 0x918, 0xa0); |
813 | cx25840_write(client, 0x919, 0x01); | 825 | cx25840_write(client, 0x919, 0x01); |
814 | } else if (is_cx231xx(state)) { | 826 | } else if (is_cx231xx(state)) { |
815 | /* Audio channel 1 src : Parallel 1 */ | 827 | /* Audio channel 1 src : Parallel 1 */ |
816 | cx25840_write(client, 0x124, 0x03); | 828 | cx25840_write(client, 0x124, 0x03); |
817 | 829 | ||
818 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ | 830 | /* I2S_IN_CTL: I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 */ |
819 | cx25840_write(client, 0x914, 0xa0); | 831 | cx25840_write(client, 0x914, 0xa0); |
820 | 832 | ||
821 | /* I2S_OUT_CTL: | 833 | /* I2S_OUT_CTL: |
822 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 | 834 | * I2S_IN_SONY_MODE, LEFT SAMPLE on WS=1 |
823 | * I2S_OUT_MASTER_MODE = Master | 835 | * I2S_OUT_MASTER_MODE = Master |
824 | */ | 836 | */ |
825 | cx25840_write(client, 0x918, 0xa0); | 837 | cx25840_write(client, 0x918, 0xa0); |
826 | cx25840_write(client, 0x919, 0x01); | 838 | cx25840_write(client, 0x919, 0x01); |
827 | } | 839 | } |
828 | 840 | ||
829 | return 0; | 841 | return 0; |
830 | } | 842 | } |
831 | 843 | ||
832 | /* ----------------------------------------------------------------------- */ | 844 | /* ----------------------------------------------------------------------- */ |
833 | 845 | ||
834 | static int set_v4lstd(struct i2c_client *client) | 846 | static int set_v4lstd(struct i2c_client *client) |
835 | { | 847 | { |
836 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 848 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
837 | u8 fmt = 0; /* zero is autodetect */ | 849 | u8 fmt = 0; /* zero is autodetect */ |
838 | u8 pal_m = 0; | 850 | u8 pal_m = 0; |
839 | 851 | ||
840 | /* First tests should be against specific std */ | 852 | /* First tests should be against specific std */ |
841 | if (state->std == V4L2_STD_NTSC_M_JP) { | 853 | if (state->std == V4L2_STD_NTSC_M_JP) { |
842 | fmt = 0x2; | 854 | fmt = 0x2; |
843 | } else if (state->std == V4L2_STD_NTSC_443) { | 855 | } else if (state->std == V4L2_STD_NTSC_443) { |
844 | fmt = 0x3; | 856 | fmt = 0x3; |
845 | } else if (state->std == V4L2_STD_PAL_M) { | 857 | } else if (state->std == V4L2_STD_PAL_M) { |
846 | pal_m = 1; | 858 | pal_m = 1; |
847 | fmt = 0x5; | 859 | fmt = 0x5; |
848 | } else if (state->std == V4L2_STD_PAL_N) { | 860 | } else if (state->std == V4L2_STD_PAL_N) { |
849 | fmt = 0x6; | 861 | fmt = 0x6; |
850 | } else if (state->std == V4L2_STD_PAL_Nc) { | 862 | } else if (state->std == V4L2_STD_PAL_Nc) { |
851 | fmt = 0x7; | 863 | fmt = 0x7; |
852 | } else if (state->std == V4L2_STD_PAL_60) { | 864 | } else if (state->std == V4L2_STD_PAL_60) { |
853 | fmt = 0x8; | 865 | fmt = 0x8; |
854 | } else { | 866 | } else { |
855 | /* Then, test against generic ones */ | 867 | /* Then, test against generic ones */ |
856 | if (state->std & V4L2_STD_NTSC) | 868 | if (state->std & V4L2_STD_NTSC) |
857 | fmt = 0x1; | 869 | fmt = 0x1; |
858 | else if (state->std & V4L2_STD_PAL) | 870 | else if (state->std & V4L2_STD_PAL) |
859 | fmt = 0x4; | 871 | fmt = 0x4; |
860 | else if (state->std & V4L2_STD_SECAM) | 872 | else if (state->std & V4L2_STD_SECAM) |
861 | fmt = 0xc; | 873 | fmt = 0xc; |
862 | } | 874 | } |
863 | 875 | ||
864 | v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); | 876 | v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); |
865 | 877 | ||
866 | /* Follow step 9 of section 3.16 in the cx25840 datasheet. | 878 | /* Follow step 9 of section 3.16 in the cx25840 datasheet. |
867 | Without this PAL may display a vertical ghosting effect. | 879 | Without this PAL may display a vertical ghosting effect. |
868 | This happens for example with the Yuan MPC622. */ | 880 | This happens for example with the Yuan MPC622. */ |
869 | if (fmt >= 4 && fmt < 8) { | 881 | if (fmt >= 4 && fmt < 8) { |
870 | /* Set format to NTSC-M */ | 882 | /* Set format to NTSC-M */ |
871 | cx25840_and_or(client, 0x400, ~0xf, 1); | 883 | cx25840_and_or(client, 0x400, ~0xf, 1); |
872 | /* Turn off LCOMB */ | 884 | /* Turn off LCOMB */ |
873 | cx25840_and_or(client, 0x47b, ~6, 0); | 885 | cx25840_and_or(client, 0x47b, ~6, 0); |
874 | } | 886 | } |
875 | cx25840_and_or(client, 0x400, ~0xf, fmt); | 887 | cx25840_and_or(client, 0x400, ~0xf, fmt); |
876 | cx25840_and_or(client, 0x403, ~0x3, pal_m); | 888 | cx25840_and_or(client, 0x403, ~0x3, pal_m); |
877 | cx25840_std_setup(client); | 889 | cx25840_std_setup(client); |
878 | if (!is_cx2583x(state)) | 890 | if (!is_cx2583x(state)) |
879 | input_change(client); | 891 | input_change(client); |
880 | return 0; | 892 | return 0; |
881 | } | 893 | } |
882 | 894 | ||
883 | /* ----------------------------------------------------------------------- */ | 895 | /* ----------------------------------------------------------------------- */ |
884 | 896 | ||
885 | static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 897 | static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
886 | { | 898 | { |
887 | struct cx25840_state *state = to_state(sd); | 899 | struct cx25840_state *state = to_state(sd); |
888 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 900 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
889 | 901 | ||
890 | switch (ctrl->id) { | 902 | switch (ctrl->id) { |
891 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: | 903 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: |
892 | state->pvr150_workaround = ctrl->value; | 904 | state->pvr150_workaround = ctrl->value; |
893 | set_input(client, state->vid_input, state->aud_input); | 905 | set_input(client, state->vid_input, state->aud_input); |
894 | break; | 906 | break; |
895 | 907 | ||
896 | case V4L2_CID_BRIGHTNESS: | 908 | case V4L2_CID_BRIGHTNESS: |
897 | if (ctrl->value < 0 || ctrl->value > 255) { | 909 | if (ctrl->value < 0 || ctrl->value > 255) { |
898 | v4l_err(client, "invalid brightness setting %d\n", | 910 | v4l_err(client, "invalid brightness setting %d\n", |
899 | ctrl->value); | 911 | ctrl->value); |
900 | return -ERANGE; | 912 | return -ERANGE; |
901 | } | 913 | } |
902 | 914 | ||
903 | cx25840_write(client, 0x414, ctrl->value - 128); | 915 | cx25840_write(client, 0x414, ctrl->value - 128); |
904 | break; | 916 | break; |
905 | 917 | ||
906 | case V4L2_CID_CONTRAST: | 918 | case V4L2_CID_CONTRAST: |
907 | if (ctrl->value < 0 || ctrl->value > 127) { | 919 | if (ctrl->value < 0 || ctrl->value > 127) { |
908 | v4l_err(client, "invalid contrast setting %d\n", | 920 | v4l_err(client, "invalid contrast setting %d\n", |
909 | ctrl->value); | 921 | ctrl->value); |
910 | return -ERANGE; | 922 | return -ERANGE; |
911 | } | 923 | } |
912 | 924 | ||
913 | cx25840_write(client, 0x415, ctrl->value << 1); | 925 | cx25840_write(client, 0x415, ctrl->value << 1); |
914 | break; | 926 | break; |
915 | 927 | ||
916 | case V4L2_CID_SATURATION: | 928 | case V4L2_CID_SATURATION: |
917 | if (ctrl->value < 0 || ctrl->value > 127) { | 929 | if (ctrl->value < 0 || ctrl->value > 127) { |
918 | v4l_err(client, "invalid saturation setting %d\n", | 930 | v4l_err(client, "invalid saturation setting %d\n", |
919 | ctrl->value); | 931 | ctrl->value); |
920 | return -ERANGE; | 932 | return -ERANGE; |
921 | } | 933 | } |
922 | 934 | ||
923 | cx25840_write(client, 0x420, ctrl->value << 1); | 935 | cx25840_write(client, 0x420, ctrl->value << 1); |
924 | cx25840_write(client, 0x421, ctrl->value << 1); | 936 | cx25840_write(client, 0x421, ctrl->value << 1); |
925 | break; | 937 | break; |
926 | 938 | ||
927 | case V4L2_CID_HUE: | 939 | case V4L2_CID_HUE: |
928 | if (ctrl->value < -128 || ctrl->value > 127) { | 940 | if (ctrl->value < -128 || ctrl->value > 127) { |
929 | v4l_err(client, "invalid hue setting %d\n", ctrl->value); | 941 | v4l_err(client, "invalid hue setting %d\n", ctrl->value); |
930 | return -ERANGE; | 942 | return -ERANGE; |
931 | } | 943 | } |
932 | 944 | ||
933 | cx25840_write(client, 0x422, ctrl->value); | 945 | cx25840_write(client, 0x422, ctrl->value); |
934 | break; | 946 | break; |
935 | 947 | ||
936 | case V4L2_CID_AUDIO_VOLUME: | 948 | case V4L2_CID_AUDIO_VOLUME: |
937 | case V4L2_CID_AUDIO_BASS: | 949 | case V4L2_CID_AUDIO_BASS: |
938 | case V4L2_CID_AUDIO_TREBLE: | 950 | case V4L2_CID_AUDIO_TREBLE: |
939 | case V4L2_CID_AUDIO_BALANCE: | 951 | case V4L2_CID_AUDIO_BALANCE: |
940 | case V4L2_CID_AUDIO_MUTE: | 952 | case V4L2_CID_AUDIO_MUTE: |
941 | if (is_cx2583x(state)) | 953 | if (is_cx2583x(state)) |
942 | return -EINVAL; | 954 | return -EINVAL; |
943 | return cx25840_audio_s_ctrl(sd, ctrl); | 955 | return cx25840_audio_s_ctrl(sd, ctrl); |
944 | 956 | ||
945 | default: | 957 | default: |
946 | return -EINVAL; | 958 | return -EINVAL; |
947 | } | 959 | } |
948 | 960 | ||
949 | return 0; | 961 | return 0; |
950 | } | 962 | } |
951 | 963 | ||
952 | static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 964 | static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
953 | { | 965 | { |
954 | struct cx25840_state *state = to_state(sd); | 966 | struct cx25840_state *state = to_state(sd); |
955 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 967 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
956 | 968 | ||
957 | switch (ctrl->id) { | 969 | switch (ctrl->id) { |
958 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: | 970 | case CX25840_CID_ENABLE_PVR150_WORKAROUND: |
959 | ctrl->value = state->pvr150_workaround; | 971 | ctrl->value = state->pvr150_workaround; |
960 | break; | 972 | break; |
961 | case V4L2_CID_BRIGHTNESS: | 973 | case V4L2_CID_BRIGHTNESS: |
962 | ctrl->value = (s8)cx25840_read(client, 0x414) + 128; | 974 | ctrl->value = (s8)cx25840_read(client, 0x414) + 128; |
963 | break; | 975 | break; |
964 | case V4L2_CID_CONTRAST: | 976 | case V4L2_CID_CONTRAST: |
965 | ctrl->value = cx25840_read(client, 0x415) >> 1; | 977 | ctrl->value = cx25840_read(client, 0x415) >> 1; |
966 | break; | 978 | break; |
967 | case V4L2_CID_SATURATION: | 979 | case V4L2_CID_SATURATION: |
968 | ctrl->value = cx25840_read(client, 0x420) >> 1; | 980 | ctrl->value = cx25840_read(client, 0x420) >> 1; |
969 | break; | 981 | break; |
970 | case V4L2_CID_HUE: | 982 | case V4L2_CID_HUE: |
971 | ctrl->value = (s8)cx25840_read(client, 0x422); | 983 | ctrl->value = (s8)cx25840_read(client, 0x422); |
972 | break; | 984 | break; |
973 | case V4L2_CID_AUDIO_VOLUME: | 985 | case V4L2_CID_AUDIO_VOLUME: |
974 | case V4L2_CID_AUDIO_BASS: | 986 | case V4L2_CID_AUDIO_BASS: |
975 | case V4L2_CID_AUDIO_TREBLE: | 987 | case V4L2_CID_AUDIO_TREBLE: |
976 | case V4L2_CID_AUDIO_BALANCE: | 988 | case V4L2_CID_AUDIO_BALANCE: |
977 | case V4L2_CID_AUDIO_MUTE: | 989 | case V4L2_CID_AUDIO_MUTE: |
978 | if (is_cx2583x(state)) | 990 | if (is_cx2583x(state)) |
979 | return -EINVAL; | 991 | return -EINVAL; |
980 | return cx25840_audio_g_ctrl(sd, ctrl); | 992 | return cx25840_audio_g_ctrl(sd, ctrl); |
981 | default: | 993 | default: |
982 | return -EINVAL; | 994 | return -EINVAL; |
983 | } | 995 | } |
984 | 996 | ||
985 | return 0; | 997 | return 0; |
986 | } | 998 | } |
987 | 999 | ||
988 | /* ----------------------------------------------------------------------- */ | 1000 | /* ----------------------------------------------------------------------- */ |
989 | 1001 | ||
990 | static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | 1002 | static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) |
991 | { | 1003 | { |
992 | switch (fmt->type) { | 1004 | switch (fmt->type) { |
993 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 1005 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
994 | return cx25840_vbi_g_fmt(sd, fmt); | 1006 | return cx25840_vbi_g_fmt(sd, fmt); |
995 | default: | 1007 | default: |
996 | return -EINVAL; | 1008 | return -EINVAL; |
997 | } | 1009 | } |
998 | return 0; | 1010 | return 0; |
999 | } | 1011 | } |
1000 | 1012 | ||
1001 | static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | 1013 | static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) |
1002 | { | 1014 | { |
1003 | struct cx25840_state *state = to_state(sd); | 1015 | struct cx25840_state *state = to_state(sd); |
1004 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1016 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1005 | struct v4l2_pix_format *pix; | 1017 | struct v4l2_pix_format *pix; |
1006 | int HSC, VSC, Vsrc, Hsrc, filter, Vlines; | 1018 | int HSC, VSC, Vsrc, Hsrc, filter, Vlines; |
1007 | int is_50Hz = !(state->std & V4L2_STD_525_60); | 1019 | int is_50Hz = !(state->std & V4L2_STD_525_60); |
1008 | 1020 | ||
1009 | switch (fmt->type) { | 1021 | switch (fmt->type) { |
1010 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1022 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: |
1011 | pix = &(fmt->fmt.pix); | 1023 | pix = &(fmt->fmt.pix); |
1012 | 1024 | ||
1013 | Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; | 1025 | Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; |
1014 | Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; | 1026 | Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; |
1015 | 1027 | ||
1016 | Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; | 1028 | Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; |
1017 | Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; | 1029 | Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; |
1018 | 1030 | ||
1019 | Vlines = pix->height + (is_50Hz ? 4 : 7); | 1031 | Vlines = pix->height + (is_50Hz ? 4 : 7); |
1020 | 1032 | ||
1021 | if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || | 1033 | if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || |
1022 | (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { | 1034 | (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { |
1023 | v4l_err(client, "%dx%d is not a valid size!\n", | 1035 | v4l_err(client, "%dx%d is not a valid size!\n", |
1024 | pix->width, pix->height); | 1036 | pix->width, pix->height); |
1025 | return -ERANGE; | 1037 | return -ERANGE; |
1026 | } | 1038 | } |
1027 | 1039 | ||
1028 | HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); | 1040 | HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); |
1029 | VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); | 1041 | VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); |
1030 | VSC &= 0x1fff; | 1042 | VSC &= 0x1fff; |
1031 | 1043 | ||
1032 | if (pix->width >= 385) | 1044 | if (pix->width >= 385) |
1033 | filter = 0; | 1045 | filter = 0; |
1034 | else if (pix->width > 192) | 1046 | else if (pix->width > 192) |
1035 | filter = 1; | 1047 | filter = 1; |
1036 | else if (pix->width > 96) | 1048 | else if (pix->width > 96) |
1037 | filter = 2; | 1049 | filter = 2; |
1038 | else | 1050 | else |
1039 | filter = 3; | 1051 | filter = 3; |
1040 | 1052 | ||
1041 | v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", | 1053 | v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", |
1042 | pix->width, pix->height, HSC, VSC); | 1054 | pix->width, pix->height, HSC, VSC); |
1043 | 1055 | ||
1044 | /* HSCALE=HSC */ | 1056 | /* HSCALE=HSC */ |
1045 | cx25840_write(client, 0x418, HSC & 0xff); | 1057 | cx25840_write(client, 0x418, HSC & 0xff); |
1046 | cx25840_write(client, 0x419, (HSC >> 8) & 0xff); | 1058 | cx25840_write(client, 0x419, (HSC >> 8) & 0xff); |
1047 | cx25840_write(client, 0x41a, HSC >> 16); | 1059 | cx25840_write(client, 0x41a, HSC >> 16); |
1048 | /* VSCALE=VSC */ | 1060 | /* VSCALE=VSC */ |
1049 | cx25840_write(client, 0x41c, VSC & 0xff); | 1061 | cx25840_write(client, 0x41c, VSC & 0xff); |
1050 | cx25840_write(client, 0x41d, VSC >> 8); | 1062 | cx25840_write(client, 0x41d, VSC >> 8); |
1051 | /* VS_INTRLACE=1 VFILT=filter */ | 1063 | /* VS_INTRLACE=1 VFILT=filter */ |
1052 | cx25840_write(client, 0x41e, 0x8 | filter); | 1064 | cx25840_write(client, 0x41e, 0x8 | filter); |
1053 | break; | 1065 | break; |
1054 | 1066 | ||
1055 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 1067 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: |
1056 | return cx25840_vbi_s_fmt(sd, fmt); | 1068 | return cx25840_vbi_s_fmt(sd, fmt); |
1057 | 1069 | ||
1058 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1070 | case V4L2_BUF_TYPE_VBI_CAPTURE: |
1059 | return cx25840_vbi_s_fmt(sd, fmt); | 1071 | return cx25840_vbi_s_fmt(sd, fmt); |
1060 | 1072 | ||
1061 | default: | 1073 | default: |
1062 | return -EINVAL; | 1074 | return -EINVAL; |
1063 | } | 1075 | } |
1064 | 1076 | ||
1065 | return 0; | 1077 | return 0; |
1066 | } | 1078 | } |
1067 | 1079 | ||
1068 | /* ----------------------------------------------------------------------- */ | 1080 | /* ----------------------------------------------------------------------- */ |
1069 | 1081 | ||
1070 | static void log_video_status(struct i2c_client *client) | 1082 | static void log_video_status(struct i2c_client *client) |
1071 | { | 1083 | { |
1072 | static const char *const fmt_strs[] = { | 1084 | static const char *const fmt_strs[] = { |
1073 | "0x0", | 1085 | "0x0", |
1074 | "NTSC-M", "NTSC-J", "NTSC-4.43", | 1086 | "NTSC-M", "NTSC-J", "NTSC-4.43", |
1075 | "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", | 1087 | "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", |
1076 | "0x9", "0xA", "0xB", | 1088 | "0x9", "0xA", "0xB", |
1077 | "SECAM", | 1089 | "SECAM", |
1078 | "0xD", "0xE", "0xF" | 1090 | "0xD", "0xE", "0xF" |
1079 | }; | 1091 | }; |
1080 | 1092 | ||
1081 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 1093 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
1082 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; | 1094 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; |
1083 | u8 gen_stat1 = cx25840_read(client, 0x40d); | 1095 | u8 gen_stat1 = cx25840_read(client, 0x40d); |
1084 | u8 gen_stat2 = cx25840_read(client, 0x40e); | 1096 | u8 gen_stat2 = cx25840_read(client, 0x40e); |
1085 | int vid_input = state->vid_input; | 1097 | int vid_input = state->vid_input; |
1086 | 1098 | ||
1087 | v4l_info(client, "Video signal: %spresent\n", | 1099 | v4l_info(client, "Video signal: %spresent\n", |
1088 | (gen_stat2 & 0x20) ? "" : "not "); | 1100 | (gen_stat2 & 0x20) ? "" : "not "); |
1089 | v4l_info(client, "Detected format: %s\n", | 1101 | v4l_info(client, "Detected format: %s\n", |
1090 | fmt_strs[gen_stat1 & 0xf]); | 1102 | fmt_strs[gen_stat1 & 0xf]); |
1091 | 1103 | ||
1092 | v4l_info(client, "Specified standard: %s\n", | 1104 | v4l_info(client, "Specified standard: %s\n", |
1093 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | 1105 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); |
1094 | 1106 | ||
1095 | if (vid_input >= CX25840_COMPOSITE1 && | 1107 | if (vid_input >= CX25840_COMPOSITE1 && |
1096 | vid_input <= CX25840_COMPOSITE8) { | 1108 | vid_input <= CX25840_COMPOSITE8) { |
1097 | v4l_info(client, "Specified video input: Composite %d\n", | 1109 | v4l_info(client, "Specified video input: Composite %d\n", |
1098 | vid_input - CX25840_COMPOSITE1 + 1); | 1110 | vid_input - CX25840_COMPOSITE1 + 1); |
1099 | } else { | 1111 | } else { |
1100 | v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", | 1112 | v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", |
1101 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); | 1113 | (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); |
1102 | } | 1114 | } |
1103 | 1115 | ||
1104 | v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); | 1116 | v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); |
1105 | } | 1117 | } |
1106 | 1118 | ||
1107 | /* ----------------------------------------------------------------------- */ | 1119 | /* ----------------------------------------------------------------------- */ |
1108 | 1120 | ||
1109 | static void log_audio_status(struct i2c_client *client) | 1121 | static void log_audio_status(struct i2c_client *client) |
1110 | { | 1122 | { |
1111 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); | 1123 | struct cx25840_state *state = to_state(i2c_get_clientdata(client)); |
1112 | u8 download_ctl = cx25840_read(client, 0x803); | 1124 | u8 download_ctl = cx25840_read(client, 0x803); |
1113 | u8 mod_det_stat0 = cx25840_read(client, 0x804); | 1125 | u8 mod_det_stat0 = cx25840_read(client, 0x804); |
1114 | u8 mod_det_stat1 = cx25840_read(client, 0x805); | 1126 | u8 mod_det_stat1 = cx25840_read(client, 0x805); |
1115 | u8 audio_config = cx25840_read(client, 0x808); | 1127 | u8 audio_config = cx25840_read(client, 0x808); |
1116 | u8 pref_mode = cx25840_read(client, 0x809); | 1128 | u8 pref_mode = cx25840_read(client, 0x809); |
1117 | u8 afc0 = cx25840_read(client, 0x80b); | 1129 | u8 afc0 = cx25840_read(client, 0x80b); |
1118 | u8 mute_ctl = cx25840_read(client, 0x8d3); | 1130 | u8 mute_ctl = cx25840_read(client, 0x8d3); |
1119 | int aud_input = state->aud_input; | 1131 | int aud_input = state->aud_input; |
1120 | char *p; | 1132 | char *p; |
1121 | 1133 | ||
1122 | switch (mod_det_stat0) { | 1134 | switch (mod_det_stat0) { |
1123 | case 0x00: p = "mono"; break; | 1135 | case 0x00: p = "mono"; break; |
1124 | case 0x01: p = "stereo"; break; | 1136 | case 0x01: p = "stereo"; break; |
1125 | case 0x02: p = "dual"; break; | 1137 | case 0x02: p = "dual"; break; |
1126 | case 0x04: p = "tri"; break; | 1138 | case 0x04: p = "tri"; break; |
1127 | case 0x10: p = "mono with SAP"; break; | 1139 | case 0x10: p = "mono with SAP"; break; |
1128 | case 0x11: p = "stereo with SAP"; break; | 1140 | case 0x11: p = "stereo with SAP"; break; |
1129 | case 0x12: p = "dual with SAP"; break; | 1141 | case 0x12: p = "dual with SAP"; break; |
1130 | case 0x14: p = "tri with SAP"; break; | 1142 | case 0x14: p = "tri with SAP"; break; |
1131 | case 0xfe: p = "forced mode"; break; | 1143 | case 0xfe: p = "forced mode"; break; |
1132 | default: p = "not defined"; | 1144 | default: p = "not defined"; |
1133 | } | 1145 | } |
1134 | v4l_info(client, "Detected audio mode: %s\n", p); | 1146 | v4l_info(client, "Detected audio mode: %s\n", p); |
1135 | 1147 | ||
1136 | switch (mod_det_stat1) { | 1148 | switch (mod_det_stat1) { |
1137 | case 0x00: p = "not defined"; break; | 1149 | case 0x00: p = "not defined"; break; |
1138 | case 0x01: p = "EIAJ"; break; | 1150 | case 0x01: p = "EIAJ"; break; |
1139 | case 0x02: p = "A2-M"; break; | 1151 | case 0x02: p = "A2-M"; break; |
1140 | case 0x03: p = "A2-BG"; break; | 1152 | case 0x03: p = "A2-BG"; break; |
1141 | case 0x04: p = "A2-DK1"; break; | 1153 | case 0x04: p = "A2-DK1"; break; |
1142 | case 0x05: p = "A2-DK2"; break; | 1154 | case 0x05: p = "A2-DK2"; break; |
1143 | case 0x06: p = "A2-DK3"; break; | 1155 | case 0x06: p = "A2-DK3"; break; |
1144 | case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; | 1156 | case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; |
1145 | case 0x08: p = "AM-L"; break; | 1157 | case 0x08: p = "AM-L"; break; |
1146 | case 0x09: p = "NICAM-BG"; break; | 1158 | case 0x09: p = "NICAM-BG"; break; |
1147 | case 0x0a: p = "NICAM-DK"; break; | 1159 | case 0x0a: p = "NICAM-DK"; break; |
1148 | case 0x0b: p = "NICAM-I"; break; | 1160 | case 0x0b: p = "NICAM-I"; break; |
1149 | case 0x0c: p = "NICAM-L"; break; | 1161 | case 0x0c: p = "NICAM-L"; break; |
1150 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; | 1162 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; |
1151 | case 0x0e: p = "IF FM Radio"; break; | 1163 | case 0x0e: p = "IF FM Radio"; break; |
1152 | case 0x0f: p = "BTSC"; break; | 1164 | case 0x0f: p = "BTSC"; break; |
1153 | case 0x10: p = "high-deviation FM"; break; | 1165 | case 0x10: p = "high-deviation FM"; break; |
1154 | case 0x11: p = "very high-deviation FM"; break; | 1166 | case 0x11: p = "very high-deviation FM"; break; |
1155 | case 0xfd: p = "unknown audio standard"; break; | 1167 | case 0xfd: p = "unknown audio standard"; break; |
1156 | case 0xfe: p = "forced audio standard"; break; | 1168 | case 0xfe: p = "forced audio standard"; break; |
1157 | case 0xff: p = "no detected audio standard"; break; | 1169 | case 0xff: p = "no detected audio standard"; break; |
1158 | default: p = "not defined"; | 1170 | default: p = "not defined"; |
1159 | } | 1171 | } |
1160 | v4l_info(client, "Detected audio standard: %s\n", p); | 1172 | v4l_info(client, "Detected audio standard: %s\n", p); |
1161 | v4l_info(client, "Audio muted: %s\n", | 1173 | v4l_info(client, "Audio muted: %s\n", |
1162 | (state->unmute_volume >= 0) ? "yes" : "no"); | 1174 | (state->unmute_volume >= 0) ? "yes" : "no"); |
1163 | v4l_info(client, "Audio microcontroller: %s\n", | 1175 | v4l_info(client, "Audio microcontroller: %s\n", |
1164 | (download_ctl & 0x10) ? | 1176 | (download_ctl & 0x10) ? |
1165 | ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); | 1177 | ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); |
1166 | 1178 | ||
1167 | switch (audio_config >> 4) { | 1179 | switch (audio_config >> 4) { |
1168 | case 0x00: p = "undefined"; break; | 1180 | case 0x00: p = "undefined"; break; |
1169 | case 0x01: p = "BTSC"; break; | 1181 | case 0x01: p = "BTSC"; break; |
1170 | case 0x02: p = "EIAJ"; break; | 1182 | case 0x02: p = "EIAJ"; break; |
1171 | case 0x03: p = "A2-M"; break; | 1183 | case 0x03: p = "A2-M"; break; |
1172 | case 0x04: p = "A2-BG"; break; | 1184 | case 0x04: p = "A2-BG"; break; |
1173 | case 0x05: p = "A2-DK1"; break; | 1185 | case 0x05: p = "A2-DK1"; break; |
1174 | case 0x06: p = "A2-DK2"; break; | 1186 | case 0x06: p = "A2-DK2"; break; |
1175 | case 0x07: p = "A2-DK3"; break; | 1187 | case 0x07: p = "A2-DK3"; break; |
1176 | case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; | 1188 | case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; |
1177 | case 0x09: p = "AM-L"; break; | 1189 | case 0x09: p = "AM-L"; break; |
1178 | case 0x0a: p = "NICAM-BG"; break; | 1190 | case 0x0a: p = "NICAM-BG"; break; |
1179 | case 0x0b: p = "NICAM-DK"; break; | 1191 | case 0x0b: p = "NICAM-DK"; break; |
1180 | case 0x0c: p = "NICAM-I"; break; | 1192 | case 0x0c: p = "NICAM-I"; break; |
1181 | case 0x0d: p = "NICAM-L"; break; | 1193 | case 0x0d: p = "NICAM-L"; break; |
1182 | case 0x0e: p = "FM radio"; break; | 1194 | case 0x0e: p = "FM radio"; break; |
1183 | case 0x0f: p = "automatic detection"; break; | 1195 | case 0x0f: p = "automatic detection"; break; |
1184 | default: p = "undefined"; | 1196 | default: p = "undefined"; |
1185 | } | 1197 | } |
1186 | v4l_info(client, "Configured audio standard: %s\n", p); | 1198 | v4l_info(client, "Configured audio standard: %s\n", p); |
1187 | 1199 | ||
1188 | if ((audio_config >> 4) < 0xF) { | 1200 | if ((audio_config >> 4) < 0xF) { |
1189 | switch (audio_config & 0xF) { | 1201 | switch (audio_config & 0xF) { |
1190 | case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; | 1202 | case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; |
1191 | case 0x01: p = "MONO2 (LANGUAGE B)"; break; | 1203 | case 0x01: p = "MONO2 (LANGUAGE B)"; break; |
1192 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; | 1204 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; |
1193 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; | 1205 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; |
1194 | case 0x04: p = "STEREO"; break; | 1206 | case 0x04: p = "STEREO"; break; |
1195 | case 0x05: p = "DUAL1 (AB)"; break; | 1207 | case 0x05: p = "DUAL1 (AB)"; break; |
1196 | case 0x06: p = "DUAL2 (AC) (FM)"; break; | 1208 | case 0x06: p = "DUAL2 (AC) (FM)"; break; |
1197 | case 0x07: p = "DUAL3 (BC) (FM)"; break; | 1209 | case 0x07: p = "DUAL3 (BC) (FM)"; break; |
1198 | case 0x08: p = "DUAL4 (AC) (AM)"; break; | 1210 | case 0x08: p = "DUAL4 (AC) (AM)"; break; |
1199 | case 0x09: p = "DUAL5 (BC) (AM)"; break; | 1211 | case 0x09: p = "DUAL5 (BC) (AM)"; break; |
1200 | case 0x0a: p = "SAP"; break; | 1212 | case 0x0a: p = "SAP"; break; |
1201 | default: p = "undefined"; | 1213 | default: p = "undefined"; |
1202 | } | 1214 | } |
1203 | v4l_info(client, "Configured audio mode: %s\n", p); | 1215 | v4l_info(client, "Configured audio mode: %s\n", p); |
1204 | } else { | 1216 | } else { |
1205 | switch (audio_config & 0xF) { | 1217 | switch (audio_config & 0xF) { |
1206 | case 0x00: p = "BG"; break; | 1218 | case 0x00: p = "BG"; break; |
1207 | case 0x01: p = "DK1"; break; | 1219 | case 0x01: p = "DK1"; break; |
1208 | case 0x02: p = "DK2"; break; | 1220 | case 0x02: p = "DK2"; break; |
1209 | case 0x03: p = "DK3"; break; | 1221 | case 0x03: p = "DK3"; break; |
1210 | case 0x04: p = "I"; break; | 1222 | case 0x04: p = "I"; break; |
1211 | case 0x05: p = "L"; break; | 1223 | case 0x05: p = "L"; break; |
1212 | case 0x06: p = "BTSC"; break; | 1224 | case 0x06: p = "BTSC"; break; |
1213 | case 0x07: p = "EIAJ"; break; | 1225 | case 0x07: p = "EIAJ"; break; |
1214 | case 0x08: p = "A2-M"; break; | 1226 | case 0x08: p = "A2-M"; break; |
1215 | case 0x09: p = "FM Radio"; break; | 1227 | case 0x09: p = "FM Radio"; break; |
1216 | case 0x0f: p = "automatic standard and mode detection"; break; | 1228 | case 0x0f: p = "automatic standard and mode detection"; break; |
1217 | default: p = "undefined"; | 1229 | default: p = "undefined"; |
1218 | } | 1230 | } |
1219 | v4l_info(client, "Configured audio system: %s\n", p); | 1231 | v4l_info(client, "Configured audio system: %s\n", p); |
1220 | } | 1232 | } |
1221 | 1233 | ||
1222 | if (aud_input) { | 1234 | if (aud_input) { |
1223 | v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); | 1235 | v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); |
1224 | } else { | 1236 | } else { |
1225 | v4l_info(client, "Specified audio input: External\n"); | 1237 | v4l_info(client, "Specified audio input: External\n"); |
1226 | } | 1238 | } |
1227 | 1239 | ||
1228 | switch (pref_mode & 0xf) { | 1240 | switch (pref_mode & 0xf) { |
1229 | case 0: p = "mono/language A"; break; | 1241 | case 0: p = "mono/language A"; break; |
1230 | case 1: p = "language B"; break; | 1242 | case 1: p = "language B"; break; |
1231 | case 2: p = "language C"; break; | 1243 | case 2: p = "language C"; break; |
1232 | case 3: p = "analog fallback"; break; | 1244 | case 3: p = "analog fallback"; break; |
1233 | case 4: p = "stereo"; break; | 1245 | case 4: p = "stereo"; break; |
1234 | case 5: p = "language AC"; break; | 1246 | case 5: p = "language AC"; break; |
1235 | case 6: p = "language BC"; break; | 1247 | case 6: p = "language BC"; break; |
1236 | case 7: p = "language AB"; break; | 1248 | case 7: p = "language AB"; break; |
1237 | default: p = "undefined"; | 1249 | default: p = "undefined"; |
1238 | } | 1250 | } |
1239 | v4l_info(client, "Preferred audio mode: %s\n", p); | 1251 | v4l_info(client, "Preferred audio mode: %s\n", p); |
1240 | 1252 | ||
1241 | if ((audio_config & 0xf) == 0xf) { | 1253 | if ((audio_config & 0xf) == 0xf) { |
1242 | switch ((afc0 >> 3) & 0x3) { | 1254 | switch ((afc0 >> 3) & 0x3) { |
1243 | case 0: p = "system DK"; break; | 1255 | case 0: p = "system DK"; break; |
1244 | case 1: p = "system L"; break; | 1256 | case 1: p = "system L"; break; |
1245 | case 2: p = "autodetect"; break; | 1257 | case 2: p = "autodetect"; break; |
1246 | default: p = "undefined"; | 1258 | default: p = "undefined"; |
1247 | } | 1259 | } |
1248 | v4l_info(client, "Selected 65 MHz format: %s\n", p); | 1260 | v4l_info(client, "Selected 65 MHz format: %s\n", p); |
1249 | 1261 | ||
1250 | switch (afc0 & 0x7) { | 1262 | switch (afc0 & 0x7) { |
1251 | case 0: p = "chroma"; break; | 1263 | case 0: p = "chroma"; break; |
1252 | case 1: p = "BTSC"; break; | 1264 | case 1: p = "BTSC"; break; |
1253 | case 2: p = "EIAJ"; break; | 1265 | case 2: p = "EIAJ"; break; |
1254 | case 3: p = "A2-M"; break; | 1266 | case 3: p = "A2-M"; break; |
1255 | case 4: p = "autodetect"; break; | 1267 | case 4: p = "autodetect"; break; |
1256 | default: p = "undefined"; | 1268 | default: p = "undefined"; |
1257 | } | 1269 | } |
1258 | v4l_info(client, "Selected 45 MHz format: %s\n", p); | 1270 | v4l_info(client, "Selected 45 MHz format: %s\n", p); |
1259 | } | 1271 | } |
1260 | } | 1272 | } |
1261 | 1273 | ||
1262 | /* ----------------------------------------------------------------------- */ | 1274 | /* ----------------------------------------------------------------------- */ |
1263 | 1275 | ||
1264 | /* This load_fw operation must be called to load the driver's firmware. | 1276 | /* This load_fw operation must be called to load the driver's firmware. |
1265 | Without this the audio standard detection will fail and you will | 1277 | Without this the audio standard detection will fail and you will |
1266 | only get mono. | 1278 | only get mono. |
1267 | 1279 | ||
1268 | Since loading the firmware is often problematic when the driver is | 1280 | Since loading the firmware is often problematic when the driver is |
1269 | compiled into the kernel I recommend postponing calling this function | 1281 | compiled into the kernel I recommend postponing calling this function |
1270 | until the first open of the video device. Another reason for | 1282 | until the first open of the video device. Another reason for |
1271 | postponing it is that loading this firmware takes a long time (seconds) | 1283 | postponing it is that loading this firmware takes a long time (seconds) |
1272 | due to the slow i2c bus speed. So it will speed up the boot process if | 1284 | due to the slow i2c bus speed. So it will speed up the boot process if |
1273 | you can avoid loading the fw as long as the video device isn't used. */ | 1285 | you can avoid loading the fw as long as the video device isn't used. */ |
1274 | static int cx25840_load_fw(struct v4l2_subdev *sd) | 1286 | static int cx25840_load_fw(struct v4l2_subdev *sd) |
1275 | { | 1287 | { |
1276 | struct cx25840_state *state = to_state(sd); | 1288 | struct cx25840_state *state = to_state(sd); |
1277 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1289 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1278 | 1290 | ||
1279 | if (!state->is_initialized) { | 1291 | if (!state->is_initialized) { |
1280 | /* initialize and load firmware */ | 1292 | /* initialize and load firmware */ |
1281 | state->is_initialized = 1; | 1293 | state->is_initialized = 1; |
1282 | if (is_cx2583x(state)) | 1294 | if (is_cx2583x(state)) |
1283 | cx25836_initialize(client); | 1295 | cx25836_initialize(client); |
1284 | else if (is_cx2388x(state)) | 1296 | else if (is_cx2388x(state)) |
1285 | cx23885_initialize(client); | 1297 | cx23885_initialize(client); |
1286 | else if (is_cx231xx(state)) | 1298 | else if (is_cx231xx(state)) |
1287 | cx231xx_initialize(client); | 1299 | cx231xx_initialize(client); |
1288 | else | 1300 | else |
1289 | cx25840_initialize(client); | 1301 | cx25840_initialize(client); |
1290 | } | 1302 | } |
1291 | return 0; | 1303 | return 0; |
1292 | } | 1304 | } |
1293 | 1305 | ||
1294 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1306 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1295 | static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 1307 | static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
1296 | { | 1308 | { |
1297 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1309 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1298 | 1310 | ||
1299 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | 1311 | if (!v4l2_chip_match_i2c_client(client, ®->match)) |
1300 | return -EINVAL; | 1312 | return -EINVAL; |
1301 | if (!capable(CAP_SYS_ADMIN)) | 1313 | if (!capable(CAP_SYS_ADMIN)) |
1302 | return -EPERM; | 1314 | return -EPERM; |
1303 | reg->size = 1; | 1315 | reg->size = 1; |
1304 | reg->val = cx25840_read(client, reg->reg & 0x0fff); | 1316 | reg->val = cx25840_read(client, reg->reg & 0x0fff); |
1305 | return 0; | 1317 | return 0; |
1306 | } | 1318 | } |
1307 | 1319 | ||
1308 | static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 1320 | static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
1309 | { | 1321 | { |
1310 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1322 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1311 | 1323 | ||
1312 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | 1324 | if (!v4l2_chip_match_i2c_client(client, ®->match)) |
1313 | return -EINVAL; | 1325 | return -EINVAL; |
1314 | if (!capable(CAP_SYS_ADMIN)) | 1326 | if (!capable(CAP_SYS_ADMIN)) |
1315 | return -EPERM; | 1327 | return -EPERM; |
1316 | cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); | 1328 | cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); |
1317 | return 0; | 1329 | return 0; |
1318 | } | 1330 | } |
1319 | #endif | 1331 | #endif |
1320 | 1332 | ||
1321 | static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) | 1333 | static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) |
1322 | { | 1334 | { |
1323 | struct cx25840_state *state = to_state(sd); | 1335 | struct cx25840_state *state = to_state(sd); |
1324 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1336 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1325 | 1337 | ||
1326 | v4l_dbg(1, cx25840_debug, client, "%s output\n", | 1338 | v4l_dbg(1, cx25840_debug, client, "%s output\n", |
1327 | enable ? "enable" : "disable"); | 1339 | enable ? "enable" : "disable"); |
1328 | if (enable) { | 1340 | if (enable) { |
1329 | if (is_cx2388x(state) || is_cx231xx(state)) { | 1341 | if (is_cx2388x(state) || is_cx231xx(state)) { |
1330 | u8 v = (cx25840_read(client, 0x421) | 0x0b); | 1342 | u8 v = (cx25840_read(client, 0x421) | 0x0b); |
1331 | cx25840_write(client, 0x421, v); | 1343 | cx25840_write(client, 0x421, v); |
1332 | } else { | 1344 | } else { |
1333 | cx25840_write(client, 0x115, | 1345 | cx25840_write(client, 0x115, |
1334 | is_cx2583x(state) ? 0x0c : 0x8c); | 1346 | is_cx2583x(state) ? 0x0c : 0x8c); |
1335 | cx25840_write(client, 0x116, | 1347 | cx25840_write(client, 0x116, |
1336 | is_cx2583x(state) ? 0x04 : 0x07); | 1348 | is_cx2583x(state) ? 0x04 : 0x07); |
1337 | } | 1349 | } |
1338 | } else { | 1350 | } else { |
1339 | if (is_cx2388x(state) || is_cx231xx(state)) { | 1351 | if (is_cx2388x(state) || is_cx231xx(state)) { |
1340 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); | 1352 | u8 v = cx25840_read(client, 0x421) & ~(0x0b); |
1341 | cx25840_write(client, 0x421, v); | 1353 | cx25840_write(client, 0x421, v); |
1342 | } else { | 1354 | } else { |
1343 | cx25840_write(client, 0x115, 0x00); | 1355 | cx25840_write(client, 0x115, 0x00); |
1344 | cx25840_write(client, 0x116, 0x00); | 1356 | cx25840_write(client, 0x116, 0x00); |
1345 | } | 1357 | } |
1346 | } | 1358 | } |
1347 | return 0; | 1359 | return 0; |
1348 | } | 1360 | } |
1349 | 1361 | ||
1350 | static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) | 1362 | static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) |
1351 | { | 1363 | { |
1352 | struct cx25840_state *state = to_state(sd); | 1364 | struct cx25840_state *state = to_state(sd); |
1353 | 1365 | ||
1354 | switch (qc->id) { | 1366 | switch (qc->id) { |
1355 | case V4L2_CID_BRIGHTNESS: | 1367 | case V4L2_CID_BRIGHTNESS: |
1356 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); | 1368 | return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); |
1357 | case V4L2_CID_CONTRAST: | 1369 | case V4L2_CID_CONTRAST: |
1358 | case V4L2_CID_SATURATION: | 1370 | case V4L2_CID_SATURATION: |
1359 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); | 1371 | return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64); |
1360 | case V4L2_CID_HUE: | 1372 | case V4L2_CID_HUE: |
1361 | return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); | 1373 | return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0); |
1362 | default: | 1374 | default: |
1363 | break; | 1375 | break; |
1364 | } | 1376 | } |
1365 | if (is_cx2583x(state)) | 1377 | if (is_cx2583x(state)) |
1366 | return -EINVAL; | 1378 | return -EINVAL; |
1367 | 1379 | ||
1368 | switch (qc->id) { | 1380 | switch (qc->id) { |
1369 | case V4L2_CID_AUDIO_VOLUME: | 1381 | case V4L2_CID_AUDIO_VOLUME: |
1370 | return v4l2_ctrl_query_fill(qc, 0, 65535, | 1382 | return v4l2_ctrl_query_fill(qc, 0, 65535, |
1371 | 65535 / 100, state->default_volume); | 1383 | 65535 / 100, state->default_volume); |
1372 | case V4L2_CID_AUDIO_MUTE: | 1384 | case V4L2_CID_AUDIO_MUTE: |
1373 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); | 1385 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); |
1374 | case V4L2_CID_AUDIO_BALANCE: | 1386 | case V4L2_CID_AUDIO_BALANCE: |
1375 | case V4L2_CID_AUDIO_BASS: | 1387 | case V4L2_CID_AUDIO_BASS: |
1376 | case V4L2_CID_AUDIO_TREBLE: | 1388 | case V4L2_CID_AUDIO_TREBLE: |
1377 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); | 1389 | return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); |
1378 | default: | 1390 | default: |
1379 | return -EINVAL; | 1391 | return -EINVAL; |
1380 | } | 1392 | } |
1381 | return -EINVAL; | 1393 | return -EINVAL; |
1382 | } | 1394 | } |
1383 | 1395 | ||
1384 | static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) | 1396 | static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
1385 | { | 1397 | { |
1386 | struct cx25840_state *state = to_state(sd); | 1398 | struct cx25840_state *state = to_state(sd); |
1387 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1399 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1388 | 1400 | ||
1389 | if (state->radio == 0 && state->std == std) | 1401 | if (state->radio == 0 && state->std == std) |
1390 | return 0; | 1402 | return 0; |
1391 | state->radio = 0; | 1403 | state->radio = 0; |
1392 | state->std = std; | 1404 | state->std = std; |
1393 | return set_v4lstd(client); | 1405 | return set_v4lstd(client); |
1394 | } | 1406 | } |
1395 | 1407 | ||
1396 | static int cx25840_s_radio(struct v4l2_subdev *sd) | 1408 | static int cx25840_s_radio(struct v4l2_subdev *sd) |
1397 | { | 1409 | { |
1398 | struct cx25840_state *state = to_state(sd); | 1410 | struct cx25840_state *state = to_state(sd); |
1399 | 1411 | ||
1400 | state->radio = 1; | 1412 | state->radio = 1; |
1401 | return 0; | 1413 | return 0; |
1402 | } | 1414 | } |
1403 | 1415 | ||
1404 | static int cx25840_s_video_routing(struct v4l2_subdev *sd, | 1416 | static int cx25840_s_video_routing(struct v4l2_subdev *sd, |
1405 | u32 input, u32 output, u32 config) | 1417 | u32 input, u32 output, u32 config) |
1406 | { | 1418 | { |
1407 | struct cx25840_state *state = to_state(sd); | 1419 | struct cx25840_state *state = to_state(sd); |
1408 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1420 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1409 | 1421 | ||
1410 | return set_input(client, input, state->aud_input); | 1422 | return set_input(client, input, state->aud_input); |
1411 | } | 1423 | } |
1412 | 1424 | ||
1413 | static int cx25840_s_audio_routing(struct v4l2_subdev *sd, | 1425 | static int cx25840_s_audio_routing(struct v4l2_subdev *sd, |
1414 | u32 input, u32 output, u32 config) | 1426 | u32 input, u32 output, u32 config) |
1415 | { | 1427 | { |
1416 | struct cx25840_state *state = to_state(sd); | 1428 | struct cx25840_state *state = to_state(sd); |
1417 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1429 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1418 | 1430 | ||
1419 | if (is_cx2583x(state)) | 1431 | if (is_cx2583x(state)) |
1420 | return -EINVAL; | 1432 | return -EINVAL; |
1421 | return set_input(client, state->vid_input, input); | 1433 | return set_input(client, state->vid_input, input); |
1422 | } | 1434 | } |
1423 | 1435 | ||
1424 | static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) | 1436 | static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) |
1425 | { | 1437 | { |
1426 | struct cx25840_state *state = to_state(sd); | 1438 | struct cx25840_state *state = to_state(sd); |
1427 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1439 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1428 | 1440 | ||
1429 | if (!is_cx2583x(state)) | 1441 | if (!is_cx2583x(state)) |
1430 | input_change(client); | 1442 | input_change(client); |
1431 | return 0; | 1443 | return 0; |
1432 | } | 1444 | } |
1433 | 1445 | ||
1434 | static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | 1446 | static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
1435 | { | 1447 | { |
1436 | struct cx25840_state *state = to_state(sd); | 1448 | struct cx25840_state *state = to_state(sd); |
1437 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1449 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1438 | u8 vpres = cx25840_read(client, 0x40e) & 0x20; | 1450 | u8 vpres = cx25840_read(client, 0x40e) & 0x20; |
1439 | u8 mode; | 1451 | u8 mode; |
1440 | int val = 0; | 1452 | int val = 0; |
1441 | 1453 | ||
1442 | if (state->radio) | 1454 | if (state->radio) |
1443 | return 0; | 1455 | return 0; |
1444 | 1456 | ||
1445 | vt->signal = vpres ? 0xffff : 0x0; | 1457 | vt->signal = vpres ? 0xffff : 0x0; |
1446 | if (is_cx2583x(state)) | 1458 | if (is_cx2583x(state)) |
1447 | return 0; | 1459 | return 0; |
1448 | 1460 | ||
1449 | vt->capability |= | 1461 | vt->capability |= |
1450 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | 1462 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | |
1451 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | 1463 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; |
1452 | 1464 | ||
1453 | mode = cx25840_read(client, 0x804); | 1465 | mode = cx25840_read(client, 0x804); |
1454 | 1466 | ||
1455 | /* get rxsubchans and audmode */ | 1467 | /* get rxsubchans and audmode */ |
1456 | if ((mode & 0xf) == 1) | 1468 | if ((mode & 0xf) == 1) |
1457 | val |= V4L2_TUNER_SUB_STEREO; | 1469 | val |= V4L2_TUNER_SUB_STEREO; |
1458 | else | 1470 | else |
1459 | val |= V4L2_TUNER_SUB_MONO; | 1471 | val |= V4L2_TUNER_SUB_MONO; |
1460 | 1472 | ||
1461 | if (mode == 2 || mode == 4) | 1473 | if (mode == 2 || mode == 4) |
1462 | val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | 1474 | val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; |
1463 | 1475 | ||
1464 | if (mode & 0x10) | 1476 | if (mode & 0x10) |
1465 | val |= V4L2_TUNER_SUB_SAP; | 1477 | val |= V4L2_TUNER_SUB_SAP; |
1466 | 1478 | ||
1467 | vt->rxsubchans = val; | 1479 | vt->rxsubchans = val; |
1468 | vt->audmode = state->audmode; | 1480 | vt->audmode = state->audmode; |
1469 | return 0; | 1481 | return 0; |
1470 | } | 1482 | } |
1471 | 1483 | ||
1472 | static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) | 1484 | static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
1473 | { | 1485 | { |
1474 | struct cx25840_state *state = to_state(sd); | 1486 | struct cx25840_state *state = to_state(sd); |
1475 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1487 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1476 | 1488 | ||
1477 | if (state->radio || is_cx2583x(state)) | 1489 | if (state->radio || is_cx2583x(state)) |
1478 | return 0; | 1490 | return 0; |
1479 | 1491 | ||
1480 | switch (vt->audmode) { | 1492 | switch (vt->audmode) { |
1481 | case V4L2_TUNER_MODE_MONO: | 1493 | case V4L2_TUNER_MODE_MONO: |
1482 | /* mono -> mono | 1494 | /* mono -> mono |
1483 | stereo -> mono | 1495 | stereo -> mono |
1484 | bilingual -> lang1 */ | 1496 | bilingual -> lang1 */ |
1485 | cx25840_and_or(client, 0x809, ~0xf, 0x00); | 1497 | cx25840_and_or(client, 0x809, ~0xf, 0x00); |
1486 | break; | 1498 | break; |
1487 | case V4L2_TUNER_MODE_STEREO: | 1499 | case V4L2_TUNER_MODE_STEREO: |
1488 | case V4L2_TUNER_MODE_LANG1: | 1500 | case V4L2_TUNER_MODE_LANG1: |
1489 | /* mono -> mono | 1501 | /* mono -> mono |
1490 | stereo -> stereo | 1502 | stereo -> stereo |
1491 | bilingual -> lang1 */ | 1503 | bilingual -> lang1 */ |
1492 | cx25840_and_or(client, 0x809, ~0xf, 0x04); | 1504 | cx25840_and_or(client, 0x809, ~0xf, 0x04); |
1493 | break; | 1505 | break; |
1494 | case V4L2_TUNER_MODE_LANG1_LANG2: | 1506 | case V4L2_TUNER_MODE_LANG1_LANG2: |
1495 | /* mono -> mono | 1507 | /* mono -> mono |
1496 | stereo -> stereo | 1508 | stereo -> stereo |
1497 | bilingual -> lang1/lang2 */ | 1509 | bilingual -> lang1/lang2 */ |
1498 | cx25840_and_or(client, 0x809, ~0xf, 0x07); | 1510 | cx25840_and_or(client, 0x809, ~0xf, 0x07); |
1499 | break; | 1511 | break; |
1500 | case V4L2_TUNER_MODE_LANG2: | 1512 | case V4L2_TUNER_MODE_LANG2: |
1501 | /* mono -> mono | 1513 | /* mono -> mono |
1502 | stereo -> stereo | 1514 | stereo -> stereo |
1503 | bilingual -> lang2 */ | 1515 | bilingual -> lang2 */ |
1504 | cx25840_and_or(client, 0x809, ~0xf, 0x01); | 1516 | cx25840_and_or(client, 0x809, ~0xf, 0x01); |
1505 | break; | 1517 | break; |
1506 | default: | 1518 | default: |
1507 | return -EINVAL; | 1519 | return -EINVAL; |
1508 | } | 1520 | } |
1509 | state->audmode = vt->audmode; | 1521 | state->audmode = vt->audmode; |
1510 | return 0; | 1522 | return 0; |
1511 | } | 1523 | } |
1512 | 1524 | ||
1513 | static int cx25840_reset(struct v4l2_subdev *sd, u32 val) | 1525 | static int cx25840_reset(struct v4l2_subdev *sd, u32 val) |
1514 | { | 1526 | { |
1515 | struct cx25840_state *state = to_state(sd); | 1527 | struct cx25840_state *state = to_state(sd); |
1516 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1528 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1517 | 1529 | ||
1518 | if (is_cx2583x(state)) | 1530 | if (is_cx2583x(state)) |
1519 | cx25836_initialize(client); | 1531 | cx25836_initialize(client); |
1520 | else if (is_cx2388x(state)) | 1532 | else if (is_cx2388x(state)) |
1521 | cx23885_initialize(client); | 1533 | cx23885_initialize(client); |
1522 | else if (is_cx231xx(state)) | 1534 | else if (is_cx231xx(state)) |
1523 | cx231xx_initialize(client); | 1535 | cx231xx_initialize(client); |
1524 | else | 1536 | else |
1525 | cx25840_initialize(client); | 1537 | cx25840_initialize(client); |
1526 | return 0; | 1538 | return 0; |
1527 | } | 1539 | } |
1528 | 1540 | ||
1529 | static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) | 1541 | static int cx25840_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) |
1530 | { | 1542 | { |
1531 | struct cx25840_state *state = to_state(sd); | 1543 | struct cx25840_state *state = to_state(sd); |
1532 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1544 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1533 | 1545 | ||
1534 | return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); | 1546 | return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); |
1535 | } | 1547 | } |
1536 | 1548 | ||
1537 | static int cx25840_log_status(struct v4l2_subdev *sd) | 1549 | static int cx25840_log_status(struct v4l2_subdev *sd) |
1538 | { | 1550 | { |
1539 | struct cx25840_state *state = to_state(sd); | 1551 | struct cx25840_state *state = to_state(sd); |
1540 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 1552 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
1541 | 1553 | ||
1542 | log_video_status(client); | 1554 | log_video_status(client); |
1543 | if (!is_cx2583x(state)) | 1555 | if (!is_cx2583x(state)) |
1544 | log_audio_status(client); | 1556 | log_audio_status(client); |
1545 | return 0; | 1557 | return 0; |
1546 | } | 1558 | } |
1547 | 1559 | ||
1548 | /* ----------------------------------------------------------------------- */ | 1560 | /* ----------------------------------------------------------------------- */ |
1549 | 1561 | ||
1550 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { | 1562 | static const struct v4l2_subdev_core_ops cx25840_core_ops = { |
1551 | .log_status = cx25840_log_status, | 1563 | .log_status = cx25840_log_status, |
1552 | .g_chip_ident = cx25840_g_chip_ident, | 1564 | .g_chip_ident = cx25840_g_chip_ident, |
1553 | .g_ctrl = cx25840_g_ctrl, | 1565 | .g_ctrl = cx25840_g_ctrl, |
1554 | .s_ctrl = cx25840_s_ctrl, | 1566 | .s_ctrl = cx25840_s_ctrl, |
1555 | .queryctrl = cx25840_queryctrl, | 1567 | .queryctrl = cx25840_queryctrl, |
1556 | .s_std = cx25840_s_std, | 1568 | .s_std = cx25840_s_std, |
1557 | .reset = cx25840_reset, | 1569 | .reset = cx25840_reset, |
1558 | .load_fw = cx25840_load_fw, | 1570 | .load_fw = cx25840_load_fw, |
1559 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1571 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1560 | .g_register = cx25840_g_register, | 1572 | .g_register = cx25840_g_register, |
1561 | .s_register = cx25840_s_register, | 1573 | .s_register = cx25840_s_register, |
1562 | #endif | 1574 | #endif |
1563 | }; | 1575 | }; |
1564 | 1576 | ||
1565 | static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { | 1577 | static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = { |
1566 | .s_frequency = cx25840_s_frequency, | 1578 | .s_frequency = cx25840_s_frequency, |
1567 | .s_radio = cx25840_s_radio, | 1579 | .s_radio = cx25840_s_radio, |
1568 | .g_tuner = cx25840_g_tuner, | 1580 | .g_tuner = cx25840_g_tuner, |
1569 | .s_tuner = cx25840_s_tuner, | 1581 | .s_tuner = cx25840_s_tuner, |
1570 | }; | 1582 | }; |
1571 | 1583 | ||
1572 | static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { | 1584 | static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { |
1573 | .s_clock_freq = cx25840_s_clock_freq, | 1585 | .s_clock_freq = cx25840_s_clock_freq, |
1574 | .s_routing = cx25840_s_audio_routing, | 1586 | .s_routing = cx25840_s_audio_routing, |
1575 | }; | 1587 | }; |
1576 | 1588 | ||
1577 | static const struct v4l2_subdev_video_ops cx25840_video_ops = { | 1589 | static const struct v4l2_subdev_video_ops cx25840_video_ops = { |
1578 | .s_routing = cx25840_s_video_routing, | 1590 | .s_routing = cx25840_s_video_routing, |
1579 | .g_fmt = cx25840_g_fmt, | 1591 | .g_fmt = cx25840_g_fmt, |
1580 | .s_fmt = cx25840_s_fmt, | 1592 | .s_fmt = cx25840_s_fmt, |
1581 | .decode_vbi_line = cx25840_decode_vbi_line, | 1593 | .decode_vbi_line = cx25840_decode_vbi_line, |
1582 | .s_stream = cx25840_s_stream, | 1594 | .s_stream = cx25840_s_stream, |
1583 | }; | 1595 | }; |
1584 | 1596 | ||
1585 | static const struct v4l2_subdev_ops cx25840_ops = { | 1597 | static const struct v4l2_subdev_ops cx25840_ops = { |
1586 | .core = &cx25840_core_ops, | 1598 | .core = &cx25840_core_ops, |
1587 | .tuner = &cx25840_tuner_ops, | 1599 | .tuner = &cx25840_tuner_ops, |
1588 | .audio = &cx25840_audio_ops, | 1600 | .audio = &cx25840_audio_ops, |
1589 | .video = &cx25840_video_ops, | 1601 | .video = &cx25840_video_ops, |
1590 | }; | 1602 | }; |
1591 | 1603 | ||
1592 | /* ----------------------------------------------------------------------- */ | 1604 | /* ----------------------------------------------------------------------- */ |
1593 | 1605 | ||
1594 | static u32 get_cx2388x_ident(struct i2c_client *client) | 1606 | static u32 get_cx2388x_ident(struct i2c_client *client) |
1595 | { | 1607 | { |
1596 | u32 ret; | 1608 | u32 ret; |
1597 | 1609 | ||
1598 | /* Come out of digital power down */ | 1610 | /* Come out of digital power down */ |
1599 | cx25840_write(client, 0x000, 0); | 1611 | cx25840_write(client, 0x000, 0); |
1600 | 1612 | ||
1601 | /* Detecting whether the part is cx23885/7/8 is more | 1613 | /* Detecting whether the part is cx23885/7/8 is more |
1602 | * difficult than it needs to be. No ID register. Instead we | 1614 | * difficult than it needs to be. No ID register. Instead we |
1603 | * probe certain registers indicated in the datasheets to look | 1615 | * probe certain registers indicated in the datasheets to look |
1604 | * for specific defaults that differ between the silicon designs. */ | 1616 | * for specific defaults that differ between the silicon designs. */ |
1605 | 1617 | ||
1606 | /* It's either 885/7 if the IR Tx Clk Divider register exists */ | 1618 | /* It's either 885/7 if the IR Tx Clk Divider register exists */ |
1607 | if (cx25840_read4(client, 0x204) & 0xffff) { | 1619 | if (cx25840_read4(client, 0x204) & 0xffff) { |
1608 | /* CX23885 returns bogus repetitive byte values for the DIF, | 1620 | /* CX23885 returns bogus repetitive byte values for the DIF, |
1609 | * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ | 1621 | * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ |
1610 | ret = cx25840_read4(client, 0x300); | 1622 | ret = cx25840_read4(client, 0x300); |
1611 | if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { | 1623 | if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { |
1612 | /* No DIF */ | 1624 | /* No DIF */ |
1613 | ret = V4L2_IDENT_CX23885_AV; | 1625 | ret = V4L2_IDENT_CX23885_AV; |
1614 | } else { | 1626 | } else { |
1615 | /* CX23887 has a broken DIF, but the registers | 1627 | /* CX23887 has a broken DIF, but the registers |
1616 | * appear valid (but unsed), good enough to detect. */ | 1628 | * appear valid (but unsed), good enough to detect. */ |
1617 | ret = V4L2_IDENT_CX23887_AV; | 1629 | ret = V4L2_IDENT_CX23887_AV; |
1618 | } | 1630 | } |
1619 | } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { | 1631 | } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { |
1620 | /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ | 1632 | /* DIF PLL Freq Word reg exists; chip must be a CX23888 */ |
1621 | ret = V4L2_IDENT_CX23888_AV; | 1633 | ret = V4L2_IDENT_CX23888_AV; |
1622 | } else { | 1634 | } else { |
1623 | v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); | 1635 | v4l_err(client, "Unable to detect h/w, assuming cx23887\n"); |
1624 | ret = V4L2_IDENT_CX23887_AV; | 1636 | ret = V4L2_IDENT_CX23887_AV; |
1625 | } | 1637 | } |
1626 | 1638 | ||
1627 | /* Back into digital power down */ | 1639 | /* Back into digital power down */ |
1628 | cx25840_write(client, 0x000, 2); | 1640 | cx25840_write(client, 0x000, 2); |
1629 | return ret; | 1641 | return ret; |
1630 | } | 1642 | } |
1631 | 1643 | ||
1632 | static int cx25840_probe(struct i2c_client *client, | 1644 | static int cx25840_probe(struct i2c_client *client, |
1633 | const struct i2c_device_id *did) | 1645 | const struct i2c_device_id *did) |
1634 | { | 1646 | { |
1635 | struct cx25840_state *state; | 1647 | struct cx25840_state *state; |
1636 | struct v4l2_subdev *sd; | 1648 | struct v4l2_subdev *sd; |
1637 | u32 id = V4L2_IDENT_NONE; | 1649 | u32 id = V4L2_IDENT_NONE; |
1638 | u16 device_id; | 1650 | u16 device_id; |
1639 | 1651 | ||
1640 | /* Check if the adapter supports the needed features */ | 1652 | /* Check if the adapter supports the needed features */ |
1641 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 1653 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
1642 | return -EIO; | 1654 | return -EIO; |
1643 | 1655 | ||
1644 | v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); | 1656 | v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); |
1645 | 1657 | ||
1646 | device_id = cx25840_read(client, 0x101) << 8; | 1658 | device_id = cx25840_read(client, 0x101) << 8; |
1647 | device_id |= cx25840_read(client, 0x100); | 1659 | device_id |= cx25840_read(client, 0x100); |
1648 | v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); | 1660 | v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); |
1649 | 1661 | ||
1650 | /* The high byte of the device ID should be | 1662 | /* The high byte of the device ID should be |
1651 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ | 1663 | * 0x83 for the cx2583x and 0x84 for the cx2584x */ |
1652 | if ((device_id & 0xff00) == 0x8300) { | 1664 | if ((device_id & 0xff00) == 0x8300) { |
1653 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; | 1665 | id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6; |
1654 | } else if ((device_id & 0xff00) == 0x8400) { | 1666 | } else if ((device_id & 0xff00) == 0x8400) { |
1655 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); | 1667 | id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf); |
1656 | } else if (device_id == 0x0000) { | 1668 | } else if (device_id == 0x0000) { |
1657 | id = get_cx2388x_ident(client); | 1669 | id = get_cx2388x_ident(client); |
1658 | } else if ((device_id & 0xfff0) == 0x5A30) { | 1670 | } else if ((device_id & 0xfff0) == 0x5A30) { |
1659 | /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ | 1671 | /* The CX23100 (0x5A3C = 23100) doesn't have an A/V decoder */ |
1660 | id = V4L2_IDENT_CX2310X_AV; | 1672 | id = V4L2_IDENT_CX2310X_AV; |
1661 | } else if ((device_id & 0xff) == (device_id >> 8)) { | 1673 | } else if ((device_id & 0xff) == (device_id >> 8)) { |
1662 | v4l_err(client, | 1674 | v4l_err(client, |
1663 | "likely a confused/unresponsive cx2388[578] A/V decoder" | 1675 | "likely a confused/unresponsive cx2388[578] A/V decoder" |
1664 | " found @ 0x%x (%s)\n", | 1676 | " found @ 0x%x (%s)\n", |
1665 | client->addr << 1, client->adapter->name); | 1677 | client->addr << 1, client->adapter->name); |
1666 | v4l_err(client, "A method to reset it from the cx25840 driver" | 1678 | v4l_err(client, "A method to reset it from the cx25840 driver" |
1667 | " software is not known at this time\n"); | 1679 | " software is not known at this time\n"); |
1668 | return -ENODEV; | 1680 | return -ENODEV; |
1669 | } else { | 1681 | } else { |
1670 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); | 1682 | v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); |
1671 | return -ENODEV; | 1683 | return -ENODEV; |
1672 | } | 1684 | } |
1673 | 1685 | ||
1674 | state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); | 1686 | state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL); |
1675 | if (state == NULL) | 1687 | if (state == NULL) |
1676 | return -ENOMEM; | 1688 | return -ENOMEM; |
1677 | 1689 | ||
1678 | sd = &state->sd; | 1690 | sd = &state->sd; |
1679 | v4l2_i2c_subdev_init(sd, client, &cx25840_ops); | 1691 | v4l2_i2c_subdev_init(sd, client, &cx25840_ops); |
1680 | switch (id) { | 1692 | switch (id) { |
1681 | case V4L2_IDENT_CX23885_AV: | 1693 | case V4L2_IDENT_CX23885_AV: |
1682 | v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", | 1694 | v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n", |
1683 | client->addr << 1, client->adapter->name); | 1695 | client->addr << 1, client->adapter->name); |
1684 | break; | 1696 | break; |
1685 | case V4L2_IDENT_CX23887_AV: | 1697 | case V4L2_IDENT_CX23887_AV: |
1686 | v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", | 1698 | v4l_info(client, "cx23887 A/V decoder found @ 0x%x (%s)\n", |
1687 | client->addr << 1, client->adapter->name); | 1699 | client->addr << 1, client->adapter->name); |
1688 | break; | 1700 | break; |
1689 | case V4L2_IDENT_CX23888_AV: | 1701 | case V4L2_IDENT_CX23888_AV: |
1690 | v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", | 1702 | v4l_info(client, "cx23888 A/V decoder found @ 0x%x (%s)\n", |
1691 | client->addr << 1, client->adapter->name); | 1703 | client->addr << 1, client->adapter->name); |
1692 | break; | 1704 | break; |
1693 | case V4L2_IDENT_CX2310X_AV: | 1705 | case V4L2_IDENT_CX2310X_AV: |
1694 | v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", | 1706 | v4l_info(client, "cx%d A/V decoder found @ 0x%x (%s)\n", |
1695 | device_id, client->addr << 1, client->adapter->name); | 1707 | device_id, client->addr << 1, client->adapter->name); |
1696 | break; | 1708 | break; |
1697 | case V4L2_IDENT_CX25840: | 1709 | case V4L2_IDENT_CX25840: |
1698 | case V4L2_IDENT_CX25841: | 1710 | case V4L2_IDENT_CX25841: |
1699 | case V4L2_IDENT_CX25842: | 1711 | case V4L2_IDENT_CX25842: |
1700 | case V4L2_IDENT_CX25843: | 1712 | case V4L2_IDENT_CX25843: |
1701 | /* Note: revision '(device_id & 0x0f) == 2' was never built. The | 1713 | /* Note: revision '(device_id & 0x0f) == 2' was never built. The |
1702 | marking skips from 0x1 == 22 to 0x3 == 23. */ | 1714 | marking skips from 0x1 == 22 to 0x3 == 23. */ |
1703 | v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", | 1715 | v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", |
1704 | (device_id & 0xfff0) >> 4, | 1716 | (device_id & 0xfff0) >> 4, |
1705 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 | 1717 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 |
1706 | : (device_id & 0x0f), | 1718 | : (device_id & 0x0f), |
1707 | client->addr << 1, client->adapter->name); | 1719 | client->addr << 1, client->adapter->name); |
1708 | break; | 1720 | break; |
1709 | case V4L2_IDENT_CX25836: | 1721 | case V4L2_IDENT_CX25836: |
1710 | case V4L2_IDENT_CX25837: | 1722 | case V4L2_IDENT_CX25837: |
1711 | default: | 1723 | default: |
1712 | v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", | 1724 | v4l_info(client, "cx25%3x-%x found @ 0x%x (%s)\n", |
1713 | (device_id & 0xfff0) >> 4, device_id & 0x0f, | 1725 | (device_id & 0xfff0) >> 4, device_id & 0x0f, |
1714 | client->addr << 1, client->adapter->name); | 1726 | client->addr << 1, client->adapter->name); |
1715 | break; | 1727 | break; |
1716 | } | 1728 | } |
1717 | 1729 | ||
1718 | state->c = client; | 1730 | state->c = client; |
1719 | state->vid_input = CX25840_COMPOSITE7; | 1731 | state->vid_input = CX25840_COMPOSITE7; |
1720 | state->aud_input = CX25840_AUDIO8; | 1732 | state->aud_input = CX25840_AUDIO8; |
1721 | state->audclk_freq = 48000; | 1733 | state->audclk_freq = 48000; |
1722 | state->pvr150_workaround = 0; | 1734 | state->pvr150_workaround = 0; |
1723 | state->audmode = V4L2_TUNER_MODE_LANG1; | 1735 | state->audmode = V4L2_TUNER_MODE_LANG1; |
1724 | state->unmute_volume = -1; | 1736 | state->unmute_volume = -1; |
1725 | state->default_volume = 228 - cx25840_read(client, 0x8d4); | 1737 | state->default_volume = 228 - cx25840_read(client, 0x8d4); |
1726 | state->default_volume = ((state->default_volume / 2) + 23) << 9; | 1738 | state->default_volume = ((state->default_volume / 2) + 23) << 9; |
1727 | state->vbi_line_offset = 8; | 1739 | state->vbi_line_offset = 8; |
1728 | state->id = id; | 1740 | state->id = id; |
1729 | state->rev = device_id; | 1741 | state->rev = device_id; |
1730 | 1742 | ||
1731 | return 0; | 1743 | return 0; |
1732 | } | 1744 | } |
1733 | 1745 | ||
1734 | static int cx25840_remove(struct i2c_client *client) | 1746 | static int cx25840_remove(struct i2c_client *client) |
1735 | { | 1747 | { |
1736 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 1748 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1737 | 1749 | ||
1738 | v4l2_device_unregister_subdev(sd); | 1750 | v4l2_device_unregister_subdev(sd); |
1739 | kfree(to_state(sd)); | 1751 | kfree(to_state(sd)); |
1740 | return 0; | 1752 | return 0; |
1741 | } | 1753 | } |
1742 | 1754 | ||
1743 | static const struct i2c_device_id cx25840_id[] = { | 1755 | static const struct i2c_device_id cx25840_id[] = { |
1744 | { "cx25840", 0 }, | 1756 | { "cx25840", 0 }, |
1745 | { } | 1757 | { } |
1746 | }; | 1758 | }; |
1747 | MODULE_DEVICE_TABLE(i2c, cx25840_id); | 1759 | MODULE_DEVICE_TABLE(i2c, cx25840_id); |
1748 | 1760 | ||
1749 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { | 1761 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { |
1750 | .name = "cx25840", | 1762 | .name = "cx25840", |
1751 | .probe = cx25840_probe, | 1763 | .probe = cx25840_probe, |
include/media/cx25840.h
1 | /* | 1 | /* |
2 | cx25840.h - definition for cx25840/1/2/3 inputs | 2 | cx25840.h - definition for cx25840/1/2/3 inputs |
3 | 3 | ||
4 | Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) | 4 | Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 2 of the License, or | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | 9 | (at your option) any later version. |
10 | 10 | ||
11 | This program is distributed in the hope that it will be useful, | 11 | This program is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | GNU General Public License for more details. | 14 | GNU General Public License for more details. |
15 | 15 | ||
16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
17 | along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #ifndef _CX25840_H_ | 21 | #ifndef _CX25840_H_ |
22 | #define _CX25840_H_ | 22 | #define _CX25840_H_ |
23 | 23 | ||
24 | /* Note that the cx25840 driver requires that the bridge driver calls the | 24 | /* Note that the cx25840 driver requires that the bridge driver calls the |
25 | v4l2_subdev's init operation in order to load the driver's firmware. | 25 | v4l2_subdev's init operation in order to load the driver's firmware. |
26 | Without this the audio standard detection will fail and you will | 26 | Without this the audio standard detection will fail and you will |
27 | only get mono. | 27 | only get mono. |
28 | 28 | ||
29 | Since loading the firmware is often problematic when the driver is | 29 | Since loading the firmware is often problematic when the driver is |
30 | compiled into the kernel I recommend postponing calling this function | 30 | compiled into the kernel I recommend postponing calling this function |
31 | until the first open of the video device. Another reason for | 31 | until the first open of the video device. Another reason for |
32 | postponing it is that loading this firmware takes a long time (seconds) | 32 | postponing it is that loading this firmware takes a long time (seconds) |
33 | due to the slow i2c bus speed. So it will speed up the boot process if | 33 | due to the slow i2c bus speed. So it will speed up the boot process if |
34 | you can avoid loading the fw as long as the video device isn't used. */ | 34 | you can avoid loading the fw as long as the video device isn't used. */ |
35 | 35 | ||
36 | enum cx25840_video_input { | 36 | enum cx25840_video_input { |
37 | /* Composite video inputs In1-In8 */ | 37 | /* Composite video inputs In1-In8 */ |
38 | CX25840_COMPOSITE1 = 1, | 38 | CX25840_COMPOSITE1 = 1, |
39 | CX25840_COMPOSITE2, | 39 | CX25840_COMPOSITE2, |
40 | CX25840_COMPOSITE3, | 40 | CX25840_COMPOSITE3, |
41 | CX25840_COMPOSITE4, | 41 | CX25840_COMPOSITE4, |
42 | CX25840_COMPOSITE5, | 42 | CX25840_COMPOSITE5, |
43 | CX25840_COMPOSITE6, | 43 | CX25840_COMPOSITE6, |
44 | CX25840_COMPOSITE7, | 44 | CX25840_COMPOSITE7, |
45 | CX25840_COMPOSITE8, | 45 | CX25840_COMPOSITE8, |
46 | 46 | ||
47 | /* S-Video inputs consist of one luma input (In1-In8) ORed with one | 47 | /* S-Video inputs consist of one luma input (In1-In8) ORed with one |
48 | chroma input (In5-In8) */ | 48 | chroma input (In5-In8) */ |
49 | CX25840_SVIDEO_LUMA1 = 0x10, | 49 | CX25840_SVIDEO_LUMA1 = 0x10, |
50 | CX25840_SVIDEO_LUMA2 = 0x20, | 50 | CX25840_SVIDEO_LUMA2 = 0x20, |
51 | CX25840_SVIDEO_LUMA3 = 0x30, | 51 | CX25840_SVIDEO_LUMA3 = 0x30, |
52 | CX25840_SVIDEO_LUMA4 = 0x40, | 52 | CX25840_SVIDEO_LUMA4 = 0x40, |
53 | CX25840_SVIDEO_LUMA5 = 0x50, | 53 | CX25840_SVIDEO_LUMA5 = 0x50, |
54 | CX25840_SVIDEO_LUMA6 = 0x60, | 54 | CX25840_SVIDEO_LUMA6 = 0x60, |
55 | CX25840_SVIDEO_LUMA7 = 0x70, | 55 | CX25840_SVIDEO_LUMA7 = 0x70, |
56 | CX25840_SVIDEO_LUMA8 = 0x80, | 56 | CX25840_SVIDEO_LUMA8 = 0x80, |
57 | CX25840_SVIDEO_CHROMA4 = 0x400, | 57 | CX25840_SVIDEO_CHROMA4 = 0x400, |
58 | CX25840_SVIDEO_CHROMA5 = 0x500, | 58 | CX25840_SVIDEO_CHROMA5 = 0x500, |
59 | CX25840_SVIDEO_CHROMA6 = 0x600, | 59 | CX25840_SVIDEO_CHROMA6 = 0x600, |
60 | CX25840_SVIDEO_CHROMA7 = 0x700, | 60 | CX25840_SVIDEO_CHROMA7 = 0x700, |
61 | CX25840_SVIDEO_CHROMA8 = 0x800, | 61 | CX25840_SVIDEO_CHROMA8 = 0x800, |
62 | 62 | ||
63 | /* S-Video aliases for common luma/chroma combinations */ | 63 | /* S-Video aliases for common luma/chroma combinations */ |
64 | CX25840_SVIDEO1 = 0x510, | 64 | CX25840_SVIDEO1 = 0x510, |
65 | CX25840_SVIDEO2 = 0x620, | 65 | CX25840_SVIDEO2 = 0x620, |
66 | CX25840_SVIDEO3 = 0x730, | 66 | CX25840_SVIDEO3 = 0x730, |
67 | CX25840_SVIDEO4 = 0x840, | 67 | CX25840_SVIDEO4 = 0x840, |
68 | 68 | ||
69 | /* Allow frames to specify specific input configurations */ | 69 | /* Allow frames to specify specific input configurations */ |
70 | CX25840_VIN1_CH1 = 0x80000000, | 70 | CX25840_VIN1_CH1 = 0x80000000, |
71 | CX25840_VIN2_CH1 = 0x80000001, | 71 | CX25840_VIN2_CH1 = 0x80000001, |
72 | CX25840_VIN3_CH1 = 0x80000002, | 72 | CX25840_VIN3_CH1 = 0x80000002, |
73 | CX25840_VIN4_CH1 = 0x80000003, | 73 | CX25840_VIN4_CH1 = 0x80000003, |
74 | CX25840_VIN5_CH1 = 0x80000004, | 74 | CX25840_VIN5_CH1 = 0x80000004, |
75 | CX25840_VIN6_CH1 = 0x80000005, | 75 | CX25840_VIN6_CH1 = 0x80000005, |
76 | CX25840_VIN7_CH1 = 0x80000006, | 76 | CX25840_VIN7_CH1 = 0x80000006, |
77 | CX25840_VIN8_CH1 = 0x80000007, | 77 | CX25840_VIN8_CH1 = 0x80000007, |
78 | CX25840_VIN4_CH2 = 0x80000000, | 78 | CX25840_VIN4_CH2 = 0x80000000, |
79 | CX25840_VIN5_CH2 = 0x80000010, | 79 | CX25840_VIN5_CH2 = 0x80000010, |
80 | CX25840_VIN6_CH2 = 0x80000020, | 80 | CX25840_VIN6_CH2 = 0x80000020, |
81 | CX25840_NONE_CH2 = 0x80000030, | 81 | CX25840_NONE_CH2 = 0x80000030, |
82 | CX25840_VIN7_CH3 = 0x80000000, | 82 | CX25840_VIN7_CH3 = 0x80000000, |
83 | CX25840_VIN8_CH3 = 0x80000040, | 83 | CX25840_VIN8_CH3 = 0x80000040, |
84 | CX25840_NONE0_CH3 = 0x80000080, | 84 | CX25840_NONE0_CH3 = 0x80000080, |
85 | CX25840_NONE1_CH3 = 0x800000c0, | 85 | CX25840_NONE1_CH3 = 0x800000c0, |
86 | CX25840_SVIDEO_ON = 0x80000100, | 86 | CX25840_SVIDEO_ON = 0x80000100, |
87 | CX25840_COMPONENT_ON = 0x80000200, | ||
87 | }; | 88 | }; |
88 | 89 | ||
89 | enum cx25840_audio_input { | 90 | enum cx25840_audio_input { |
90 | /* Audio inputs: serial or In4-In8 */ | 91 | /* Audio inputs: serial or In4-In8 */ |
91 | CX25840_AUDIO_SERIAL, | 92 | CX25840_AUDIO_SERIAL, |
92 | CX25840_AUDIO4 = 4, | 93 | CX25840_AUDIO4 = 4, |
93 | CX25840_AUDIO5, | 94 | CX25840_AUDIO5, |
94 | CX25840_AUDIO6, | 95 | CX25840_AUDIO6, |
95 | CX25840_AUDIO7, | 96 | CX25840_AUDIO7, |
96 | CX25840_AUDIO8, | 97 | CX25840_AUDIO8, |
97 | }; | 98 | }; |
98 | 99 | ||
99 | #endif | 100 | #endif |
100 | 101 |