1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino * Copyright (c) 2003, 2004, 2005
3*86d7f5d3SJohn Marino * John Wehle <john@feith.com>. All rights reserved.
4*86d7f5d3SJohn Marino *
5*86d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino * are met:
8*86d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
9*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
10*86d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
11*86d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the
12*86d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution.
13*86d7f5d3SJohn Marino * 3. All advertising materials mentioning features or use of this software
14*86d7f5d3SJohn Marino * must display the following acknowledgement:
15*86d7f5d3SJohn Marino * This product includes software developed by John Wehle.
16*86d7f5d3SJohn Marino * 4. The name of the author may not be used to endorse or promote products
17*86d7f5d3SJohn Marino * derived from this software without specific prior written permission.
18*86d7f5d3SJohn Marino *
19*86d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20*86d7f5d3SJohn Marino * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21*86d7f5d3SJohn Marino * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22*86d7f5d3SJohn Marino * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23*86d7f5d3SJohn Marino * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24*86d7f5d3SJohn Marino * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25*86d7f5d3SJohn Marino * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*86d7f5d3SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27*86d7f5d3SJohn Marino * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28*86d7f5d3SJohn Marino * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*86d7f5d3SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
30*86d7f5d3SJohn Marino */
31*86d7f5d3SJohn Marino
32*86d7f5d3SJohn Marino /*
33*86d7f5d3SJohn Marino * Video decoder routines for the Conexant MPEG-2 Codec driver.
34*86d7f5d3SJohn Marino *
35*86d7f5d3SJohn Marino * Ideally these routines should be implemented as a separate
36*86d7f5d3SJohn Marino * driver which has a generic video decoder interface so that
37*86d7f5d3SJohn Marino * it's not necessary for each multimedia driver to re-invent
38*86d7f5d3SJohn Marino * the wheel.
39*86d7f5d3SJohn Marino */
40*86d7f5d3SJohn Marino
41*86d7f5d3SJohn Marino #include <sys/param.h>
42*86d7f5d3SJohn Marino #include <sys/systm.h>
43*86d7f5d3SJohn Marino #include <sys/conf.h>
44*86d7f5d3SJohn Marino #include <sys/uio.h>
45*86d7f5d3SJohn Marino #include <sys/kernel.h>
46*86d7f5d3SJohn Marino #include <sys/poll.h>
47*86d7f5d3SJohn Marino #include <sys/select.h>
48*86d7f5d3SJohn Marino #include <sys/resource.h>
49*86d7f5d3SJohn Marino #include <sys/bus.h>
50*86d7f5d3SJohn Marino #include <sys/rman.h>
51*86d7f5d3SJohn Marino
52*86d7f5d3SJohn Marino #include <machine/clock.h>
53*86d7f5d3SJohn Marino
54*86d7f5d3SJohn Marino #include <dev/video/cxm/cxm.h>
55*86d7f5d3SJohn Marino
56*86d7f5d3SJohn Marino #include <bus/iicbus/iiconf.h>
57*86d7f5d3SJohn Marino #include <bus/iicbus/iicbus.h>
58*86d7f5d3SJohn Marino
59*86d7f5d3SJohn Marino #include "iicbb_if.h"
60*86d7f5d3SJohn Marino
61*86d7f5d3SJohn Marino
62*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
63*86d7f5d3SJohn Marino saa7115_init = {
64*86d7f5d3SJohn Marino 19,
65*86d7f5d3SJohn Marino {
66*86d7f5d3SJohn Marino /* Full auto mode for CVBS */
67*86d7f5d3SJohn Marino { 0x01, 1, { 0x08 } },
68*86d7f5d3SJohn Marino { 0x03, 18, { 0x20, 0x90, 0x90, 0xeb, 0xe0, 0xb0, 0x40, 0x80,
69*86d7f5d3SJohn Marino 0x44, 0x40, 0x00, 0x03, 0x2a, 0x06, 0x00, 0x9d,
70*86d7f5d3SJohn Marino 0x80, 0x01 } },
71*86d7f5d3SJohn Marino { 0x17, 7, { 0x99, 0x40, 0x80, 0x77, 0x42, 0xa9, 0x01 } },
72*86d7f5d3SJohn Marino
73*86d7f5d3SJohn Marino /*
74*86d7f5d3SJohn Marino * VBI data slicer
75*86d7f5d3SJohn Marino *
76*86d7f5d3SJohn Marino * NTSC raw VBI data on lines 10 through 21
77*86d7f5d3SJohn Marino * PAL raw VBI data on lines 6 through 22
78*86d7f5d3SJohn Marino *
79*86d7f5d3SJohn Marino * Actually lines 21 and 22 are set by the
80*86d7f5d3SJohn Marino * NTSC and PAL specific configurations.
81*86d7f5d3SJohn Marino */
82*86d7f5d3SJohn Marino { 0x40, 20, { 0x40, 0x00, 0x00, 0x00, 0x00, 0xdd, 0xdd, 0xdd,
83*86d7f5d3SJohn Marino 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
84*86d7f5d3SJohn Marino 0xdd, 0xdd, 0xdd, 0xdd } },
85*86d7f5d3SJohn Marino { 0x56, 4, { 0x00, 0x00, 0x00, 0x47 } },
86*86d7f5d3SJohn Marino { 0x5c, 3, { 0x00, 0x1f, 0x35 } },
87*86d7f5d3SJohn Marino
88*86d7f5d3SJohn Marino /* I-port and X-port configuration */
89*86d7f5d3SJohn Marino { 0x80, 2, { 0x00, 0x01 } },
90*86d7f5d3SJohn Marino { 0x83, 5, { 0x00, 0x20, 0x21, 0xc5, 0x01 } },
91*86d7f5d3SJohn Marino
92*86d7f5d3SJohn Marino /* Scaler input configuration and output format settings */
93*86d7f5d3SJohn Marino { 0xc0, 4, { 0x00, 0x08, 0x00, 0x80 } },
94*86d7f5d3SJohn Marino
95*86d7f5d3SJohn Marino /* VBI scaler configuration */
96*86d7f5d3SJohn Marino { 0x90, 4, { 0x80, 0x48, 0x00, 0x84 } },
97*86d7f5d3SJohn Marino { 0xa0, 3, { 0x01, 0x00, 0x00 } },
98*86d7f5d3SJohn Marino { 0xa4, 3, { 0x80, 0x40, 0x40 } },
99*86d7f5d3SJohn Marino { 0xa8, 3, { 0x00, 0x02, 0x00 } },
100*86d7f5d3SJohn Marino { 0xac, 3, { 0x00, 0x01, 0x00 } },
101*86d7f5d3SJohn Marino { 0xb0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
102*86d7f5d3SJohn Marino { 0xb8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
103*86d7f5d3SJohn Marino
104*86d7f5d3SJohn Marino /* Audio Master Clock to Audio Serial Clock ratio */
105*86d7f5d3SJohn Marino { 0x38, 3, { 0x03, 0x10, 0x00 } },
106*86d7f5d3SJohn Marino
107*86d7f5d3SJohn Marino /* PLL2 target clock 27 MHz (using a 32.11 MHz crystal) */
108*86d7f5d3SJohn Marino { 0xf1, 4, { 0x05, 0xd0, 0x35, 0x00 } },
109*86d7f5d3SJohn Marino
110*86d7f5d3SJohn Marino /* Pulse generator */
111*86d7f5d3SJohn Marino { 0xf6, 10, { 0x61, 0x0e, 0x60, 0x0e, 0x60, 0x0e, 0x00,
112*86d7f5d3SJohn Marino 0x00, 0x00, 0x88 } }
113*86d7f5d3SJohn Marino }
114*86d7f5d3SJohn Marino };
115*86d7f5d3SJohn Marino
116*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
117*86d7f5d3SJohn Marino saa7115_mute = {
118*86d7f5d3SJohn Marino 1,
119*86d7f5d3SJohn Marino {
120*86d7f5d3SJohn Marino /* Disable I-port */
121*86d7f5d3SJohn Marino { 0x87, 1, { 0x00 } },
122*86d7f5d3SJohn Marino }
123*86d7f5d3SJohn Marino };
124*86d7f5d3SJohn Marino
125*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
126*86d7f5d3SJohn Marino saa7115_unmute = {
127*86d7f5d3SJohn Marino 1,
128*86d7f5d3SJohn Marino {
129*86d7f5d3SJohn Marino /* Enable I-port */
130*86d7f5d3SJohn Marino { 0x87, 1, { 0x01 } },
131*86d7f5d3SJohn Marino }
132*86d7f5d3SJohn Marino };
133*86d7f5d3SJohn Marino
134*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
135*86d7f5d3SJohn Marino saa7115_select_fm = {
136*86d7f5d3SJohn Marino 1,
137*86d7f5d3SJohn Marino {
138*86d7f5d3SJohn Marino /* Enable audio clock */
139*86d7f5d3SJohn Marino { 0x88, 1, { 0x33 } }
140*86d7f5d3SJohn Marino }
141*86d7f5d3SJohn Marino };
142*86d7f5d3SJohn Marino
143*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
144*86d7f5d3SJohn Marino saa7115_select_line_in_composite = {
145*86d7f5d3SJohn Marino 3,
146*86d7f5d3SJohn Marino {
147*86d7f5d3SJohn Marino /* Amp plus anti-alias filter, CVBS from AI11 */
148*86d7f5d3SJohn Marino { 0x02, 1, { 0xc0 } },
149*86d7f5d3SJohn Marino /* Adaptive luminance comb filter */
150*86d7f5d3SJohn Marino { 0x09, 1, { 0x40 } },
151*86d7f5d3SJohn Marino
152*86d7f5d3SJohn Marino /* Enable AD1, audio clock, scaler, decoder */
153*86d7f5d3SJohn Marino { 0x88, 1, { 0x70 } }
154*86d7f5d3SJohn Marino }
155*86d7f5d3SJohn Marino };
156*86d7f5d3SJohn Marino
157*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
158*86d7f5d3SJohn Marino saa7115_select_line_in_svideo = {
159*86d7f5d3SJohn Marino 3,
160*86d7f5d3SJohn Marino {
161*86d7f5d3SJohn Marino /* Amp plus anti-alias filter, Y / C from AI11 / AI21 */
162*86d7f5d3SJohn Marino { 0x02, 1, { 0xc8 } },
163*86d7f5d3SJohn Marino /* Bypass chrominance trap / comb filter */
164*86d7f5d3SJohn Marino { 0x09, 1, { 0x80 } },
165*86d7f5d3SJohn Marino
166*86d7f5d3SJohn Marino /* Enable AD1 & 2, audio clock, scaler, decoder */
167*86d7f5d3SJohn Marino { 0x88, 1, { 0xf0 } }
168*86d7f5d3SJohn Marino }
169*86d7f5d3SJohn Marino };
170*86d7f5d3SJohn Marino
171*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
172*86d7f5d3SJohn Marino saa7115_select_tuner = {
173*86d7f5d3SJohn Marino 3,
174*86d7f5d3SJohn Marino {
175*86d7f5d3SJohn Marino /* Amp plus anti-alias filter, CVBS (auto gain) from AI23 */
176*86d7f5d3SJohn Marino { 0x02, 1, { 0xc4 } },
177*86d7f5d3SJohn Marino /* Adaptive luminance comb filter */
178*86d7f5d3SJohn Marino { 0x09, 1, { 0x40 } },
179*86d7f5d3SJohn Marino
180*86d7f5d3SJohn Marino /* Enable AD2, audio clock, scaler, decoder */
181*86d7f5d3SJohn Marino { 0x88, 1, { 0xb0 } }
182*86d7f5d3SJohn Marino }
183*86d7f5d3SJohn Marino };
184*86d7f5d3SJohn Marino
185*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
186*86d7f5d3SJohn Marino saa7115_audio_clock_44100_ntsc = {
187*86d7f5d3SJohn Marino 2,
188*86d7f5d3SJohn Marino {
189*86d7f5d3SJohn Marino /* Audio clock 44.1 kHz NTSC (using a 32.11 MHz crystal) */
190*86d7f5d3SJohn Marino { 0x30, 3, { 0xbc, 0xdf, 0x02 } },
191*86d7f5d3SJohn Marino { 0x34, 3, { 0xf2, 0x00, 0x2d } }
192*86d7f5d3SJohn Marino }
193*86d7f5d3SJohn Marino };
194*86d7f5d3SJohn Marino
195*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
196*86d7f5d3SJohn Marino saa7115_audio_clock_44100_pal = {
197*86d7f5d3SJohn Marino 2,
198*86d7f5d3SJohn Marino {
199*86d7f5d3SJohn Marino /* Audio clock 44.1 kHz PAL (using a 32.11 MHz crystal) */
200*86d7f5d3SJohn Marino { 0x30, 3, { 0x00, 0x72, 0x03 } },
201*86d7f5d3SJohn Marino { 0x34, 3, { 0xf2, 0x00, 0x2d } }
202*86d7f5d3SJohn Marino }
203*86d7f5d3SJohn Marino };
204*86d7f5d3SJohn Marino
205*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
206*86d7f5d3SJohn Marino saa7115_audio_clock_48000_ntsc = {
207*86d7f5d3SJohn Marino 2,
208*86d7f5d3SJohn Marino {
209*86d7f5d3SJohn Marino /* Audio clock 48 kHz NTSC (using a 32.11 MHz crystal) */
210*86d7f5d3SJohn Marino { 0x30, 3, { 0xcd, 0x20, 0x03 } },
211*86d7f5d3SJohn Marino { 0x34, 3, { 0xce, 0xfb, 0x30 } }
212*86d7f5d3SJohn Marino }
213*86d7f5d3SJohn Marino };
214*86d7f5d3SJohn Marino
215*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
216*86d7f5d3SJohn Marino saa7115_audio_clock_48000_pal = {
217*86d7f5d3SJohn Marino 2,
218*86d7f5d3SJohn Marino {
219*86d7f5d3SJohn Marino /* Audio clock 48 kHz PAL (using a 32.11 MHz crystal) */
220*86d7f5d3SJohn Marino { 0x30, 3, { 0x00, 0xc0, 0x03 } },
221*86d7f5d3SJohn Marino { 0x34, 3, { 0xce, 0xfb, 0x30 } }
222*86d7f5d3SJohn Marino }
223*86d7f5d3SJohn Marino };
224*86d7f5d3SJohn Marino
225*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
226*86d7f5d3SJohn Marino saa7115_scaler_vcd_ntsc_double_lines = {
227*86d7f5d3SJohn Marino 13,
228*86d7f5d3SJohn Marino {
229*86d7f5d3SJohn Marino /*
230*86d7f5d3SJohn Marino * Input window = 720 x 240, output window = 352 x 240 with
231*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
232*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
233*86d7f5d3SJohn Marino * line 5 and active video starting at line 23 (see section
234*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
235*86d7f5d3SJohn Marino * NTSC active video should actually start at line 22, however
236*86d7f5d3SJohn Marino * not all channels / programs do.
237*86d7f5d3SJohn Marino */
238*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
239*86d7f5d3SJohn Marino 0x60, 0x01, 0xf0, 0x00 } },
240*86d7f5d3SJohn Marino
241*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
242*86d7f5d3SJohn Marino { 0xd0, 3, { 0x02, 0x02, 0xaa } },
243*86d7f5d3SJohn Marino
244*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
245*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
246*86d7f5d3SJohn Marino
247*86d7f5d3SJohn Marino /* Horizontal phase scaling */
248*86d7f5d3SJohn Marino { 0xd8, 3, { 0x18, 0x04, 0x00 } },
249*86d7f5d3SJohn Marino { 0xdc, 3, { 0x0c, 0x02, 0x00 } },
250*86d7f5d3SJohn Marino
251*86d7f5d3SJohn Marino /* Vertical scaling */
252*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
253*86d7f5d3SJohn Marino
254*86d7f5d3SJohn Marino /* Vertical phase offsets */
255*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
256*86d7f5d3SJohn Marino
257*86d7f5d3SJohn Marino /*
258*86d7f5d3SJohn Marino * VBI input window = 720 x 12, output window = 1440 x 12.
259*86d7f5d3SJohn Marino */
260*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
261*86d7f5d3SJohn Marino 0xa0, 0x05, 0x0c, 0x00 } },
262*86d7f5d3SJohn Marino
263*86d7f5d3SJohn Marino /* Inverted VGATE start at line 23, stop after line 263 */
264*86d7f5d3SJohn Marino { 0x15, 2, { 0x02, 0x12 } },
265*86d7f5d3SJohn Marino
266*86d7f5d3SJohn Marino /* VBI data slicer 525 lines, line 21 is closed caption */
267*86d7f5d3SJohn Marino { 0x54, 2, { 0x4d, 0x00 } },
268*86d7f5d3SJohn Marino { 0x5a, 2, { 0x06, 0x83 } },
269*86d7f5d3SJohn Marino
270*86d7f5d3SJohn Marino /* PLL2 525 lines, 27 Mhz target clock */
271*86d7f5d3SJohn Marino { 0xf0, 1, { 0xad } },
272*86d7f5d3SJohn Marino
273*86d7f5d3SJohn Marino /* Pulse generator 525 lines, 27 Mhz target clock */
274*86d7f5d3SJohn Marino { 0xf5, 1, { 0xad } }
275*86d7f5d3SJohn Marino }
276*86d7f5d3SJohn Marino };
277*86d7f5d3SJohn Marino
278*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
279*86d7f5d3SJohn Marino saa7115_scaler_vcd_pal_double_lines = {
280*86d7f5d3SJohn Marino 13,
281*86d7f5d3SJohn Marino {
282*86d7f5d3SJohn Marino /*
283*86d7f5d3SJohn Marino * Input window = 720 x 288, output window = 352 x 288 with
284*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
285*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
286*86d7f5d3SJohn Marino * line 2 and active video starting at line 25 (see section
287*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
288*86d7f5d3SJohn Marino * PAL active video should actually start at line 24, however
289*86d7f5d3SJohn Marino * not all channels / programs do.
290*86d7f5d3SJohn Marino */
291*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
292*86d7f5d3SJohn Marino 0x60, 0x01, 0x20, 0x01 } },
293*86d7f5d3SJohn Marino
294*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
295*86d7f5d3SJohn Marino { 0xd0, 3, { 0x02, 0x02, 0xaa } },
296*86d7f5d3SJohn Marino
297*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
298*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
299*86d7f5d3SJohn Marino
300*86d7f5d3SJohn Marino /* Horizontal phase scaling */
301*86d7f5d3SJohn Marino { 0xd8, 3, { 0x18, 0x04, 0x00 } },
302*86d7f5d3SJohn Marino { 0xdc, 3, { 0x0c, 0x02, 0x00 } },
303*86d7f5d3SJohn Marino
304*86d7f5d3SJohn Marino /* Vertical scaling */
305*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
306*86d7f5d3SJohn Marino
307*86d7f5d3SJohn Marino /* Vertical phase offsets */
308*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
309*86d7f5d3SJohn Marino
310*86d7f5d3SJohn Marino /*
311*86d7f5d3SJohn Marino * VBI input window = 720 x 17, output window = 1440 x 17.
312*86d7f5d3SJohn Marino */
313*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
314*86d7f5d3SJohn Marino 0xa0, 0x05, 0x11, 0x00 } },
315*86d7f5d3SJohn Marino
316*86d7f5d3SJohn Marino /* Inverted VGATE start at line 25, stop after line 313 */
317*86d7f5d3SJohn Marino { 0x15, 2, { 0x37, 0x17 } },
318*86d7f5d3SJohn Marino
319*86d7f5d3SJohn Marino /* VBI data slicer 625 lines, line 22 is closed caption */
320*86d7f5d3SJohn Marino { 0x54, 2, { 0xdd, 0x4d } },
321*86d7f5d3SJohn Marino { 0x5a, 2, { 0x03, 0x03 } },
322*86d7f5d3SJohn Marino
323*86d7f5d3SJohn Marino /* PLL2 625 lines, 27 Mhz target clock */
324*86d7f5d3SJohn Marino { 0xf0, 1, { 0xb0 } },
325*86d7f5d3SJohn Marino
326*86d7f5d3SJohn Marino /* Pulse generator 625 lines, 27 Mhz target clock */
327*86d7f5d3SJohn Marino { 0xf5, 1, { 0xb0 } }
328*86d7f5d3SJohn Marino }
329*86d7f5d3SJohn Marino };
330*86d7f5d3SJohn Marino
331*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
332*86d7f5d3SJohn Marino saa7115_scaler_svcd_ntsc = {
333*86d7f5d3SJohn Marino 13,
334*86d7f5d3SJohn Marino {
335*86d7f5d3SJohn Marino /*
336*86d7f5d3SJohn Marino * Input window = 720 x 240, output window = 480 x 240 with
337*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
338*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
339*86d7f5d3SJohn Marino * line 5 and active video starting at line 23 (see section
340*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
341*86d7f5d3SJohn Marino * NTSC active video should actually start at line 22, however
342*86d7f5d3SJohn Marino * not all channels / programs do.
343*86d7f5d3SJohn Marino */
344*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
345*86d7f5d3SJohn Marino 0xe0, 0x01, 0xf0, 0x00 } },
346*86d7f5d3SJohn Marino
347*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
348*86d7f5d3SJohn Marino { 0xd0, 3, { 0x01, 0x00, 0x00 } },
349*86d7f5d3SJohn Marino
350*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
351*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
352*86d7f5d3SJohn Marino
353*86d7f5d3SJohn Marino /* Horizontal phase scaling */
354*86d7f5d3SJohn Marino { 0xd8, 3, { 0x00, 0x06, 0x00 } },
355*86d7f5d3SJohn Marino { 0xdc, 3, { 0x00, 0x03, 0x00 } },
356*86d7f5d3SJohn Marino
357*86d7f5d3SJohn Marino /* Vertical scaling */
358*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
359*86d7f5d3SJohn Marino
360*86d7f5d3SJohn Marino /* Vertical phase offsets */
361*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
362*86d7f5d3SJohn Marino
363*86d7f5d3SJohn Marino /*
364*86d7f5d3SJohn Marino * VBI input window = 720 x 12, output window = 1440 x 12.
365*86d7f5d3SJohn Marino */
366*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
367*86d7f5d3SJohn Marino 0xa0, 0x05, 0x0c, 0x00 } },
368*86d7f5d3SJohn Marino
369*86d7f5d3SJohn Marino /* Inverted VGATE start at line 23, stop after line 263 */
370*86d7f5d3SJohn Marino { 0x15, 2, { 0x02, 0x12 } },
371*86d7f5d3SJohn Marino
372*86d7f5d3SJohn Marino /* VBI data slicer 525 lines, line 21 is closed caption */
373*86d7f5d3SJohn Marino { 0x54, 2, { 0x4d, 0x00 } },
374*86d7f5d3SJohn Marino { 0x5a, 2, { 0x06, 0x83 } },
375*86d7f5d3SJohn Marino
376*86d7f5d3SJohn Marino /* PLL2 525 lines, 27 Mhz target clock */
377*86d7f5d3SJohn Marino { 0xf0, 1, { 0xad } },
378*86d7f5d3SJohn Marino
379*86d7f5d3SJohn Marino /* Pulse generator 525 lines, 27 Mhz target clock */
380*86d7f5d3SJohn Marino { 0xf5, 1, { 0xad } }
381*86d7f5d3SJohn Marino }
382*86d7f5d3SJohn Marino };
383*86d7f5d3SJohn Marino
384*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
385*86d7f5d3SJohn Marino saa7115_scaler_svcd_pal = {
386*86d7f5d3SJohn Marino 13,
387*86d7f5d3SJohn Marino {
388*86d7f5d3SJohn Marino /*
389*86d7f5d3SJohn Marino * Input window = 720 x 288, output window = 480 x 288 with
390*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
391*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
392*86d7f5d3SJohn Marino * line 2 and active video starting at line 25 (see section
393*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
394*86d7f5d3SJohn Marino * PAL active video should actually start at line 24, however
395*86d7f5d3SJohn Marino * not all channels / programs do.
396*86d7f5d3SJohn Marino */
397*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
398*86d7f5d3SJohn Marino 0xe0, 0x01, 0x20, 0x01 } },
399*86d7f5d3SJohn Marino
400*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
401*86d7f5d3SJohn Marino { 0xd0, 3, { 0x01, 0x00, 0x00 } },
402*86d7f5d3SJohn Marino
403*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
404*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
405*86d7f5d3SJohn Marino
406*86d7f5d3SJohn Marino /* Horizontal phase scaling */
407*86d7f5d3SJohn Marino { 0xd8, 3, { 0x00, 0x06, 0x00 } },
408*86d7f5d3SJohn Marino { 0xdc, 3, { 0x00, 0x03, 0x00 } },
409*86d7f5d3SJohn Marino
410*86d7f5d3SJohn Marino /* Vertical scaling */
411*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
412*86d7f5d3SJohn Marino
413*86d7f5d3SJohn Marino /* Vertical phase offsets */
414*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
415*86d7f5d3SJohn Marino
416*86d7f5d3SJohn Marino /*
417*86d7f5d3SJohn Marino * VBI input window = 720 x 17, output window = 1440 x 17.
418*86d7f5d3SJohn Marino */
419*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
420*86d7f5d3SJohn Marino 0xa0, 0x05, 0x11, 0x00 } },
421*86d7f5d3SJohn Marino
422*86d7f5d3SJohn Marino /* Inverted VGATE start at line 25, stop after line 313 */
423*86d7f5d3SJohn Marino { 0x15, 2, { 0x37, 0x17 } },
424*86d7f5d3SJohn Marino
425*86d7f5d3SJohn Marino /* VBI data slicer 625 lines, line 22 is closed caption */
426*86d7f5d3SJohn Marino { 0x54, 2, { 0xdd, 0x4d } },
427*86d7f5d3SJohn Marino { 0x5a, 2, { 0x03, 0x03 } },
428*86d7f5d3SJohn Marino
429*86d7f5d3SJohn Marino /* PLL2 625 lines, 27 Mhz target clock */
430*86d7f5d3SJohn Marino { 0xf0, 1, { 0xb0 } },
431*86d7f5d3SJohn Marino
432*86d7f5d3SJohn Marino /* Pulse generator 625 lines, 27 Mhz target clock */
433*86d7f5d3SJohn Marino { 0xf5, 1, { 0xb0 } }
434*86d7f5d3SJohn Marino }
435*86d7f5d3SJohn Marino };
436*86d7f5d3SJohn Marino
437*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
438*86d7f5d3SJohn Marino saa7115_scaler_dvd_ntsc = {
439*86d7f5d3SJohn Marino 13,
440*86d7f5d3SJohn Marino {
441*86d7f5d3SJohn Marino /*
442*86d7f5d3SJohn Marino * Input window = 720 x 240, output window = 720 x 240 with
443*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
444*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
445*86d7f5d3SJohn Marino * line 5 and active video starting at line 23 (see section
446*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
447*86d7f5d3SJohn Marino * NTSC active video should actually start at line 22, however
448*86d7f5d3SJohn Marino * not all channels / programs do.
449*86d7f5d3SJohn Marino */
450*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x12, 0x00, 0xf2, 0x00,
451*86d7f5d3SJohn Marino 0xd0, 0x02, 0xf0, 0x00 } },
452*86d7f5d3SJohn Marino
453*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
454*86d7f5d3SJohn Marino { 0xd0, 3, { 0x01, 0x00, 0x00 } },
455*86d7f5d3SJohn Marino
456*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
457*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
458*86d7f5d3SJohn Marino
459*86d7f5d3SJohn Marino /* Horizontal phase scaling */
460*86d7f5d3SJohn Marino { 0xd8, 3, { 0x00, 0x04, 0x00 } },
461*86d7f5d3SJohn Marino { 0xdc, 3, { 0x00, 0x02, 0x00 } },
462*86d7f5d3SJohn Marino
463*86d7f5d3SJohn Marino /* Vertical scaling */
464*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
465*86d7f5d3SJohn Marino
466*86d7f5d3SJohn Marino /* Vertical phase offsets */
467*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
468*86d7f5d3SJohn Marino
469*86d7f5d3SJohn Marino /*
470*86d7f5d3SJohn Marino * VBI input window = 720 x 12, output window = 1440 x 12.
471*86d7f5d3SJohn Marino */
472*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x05, 0x00, 0x0c, 0x00,
473*86d7f5d3SJohn Marino 0xa0, 0x05, 0x0c, 0x00 } },
474*86d7f5d3SJohn Marino
475*86d7f5d3SJohn Marino /* Inverted VGATE start at line 23, stop after line 263 */
476*86d7f5d3SJohn Marino { 0x15, 2, { 0x02, 0x12 } },
477*86d7f5d3SJohn Marino
478*86d7f5d3SJohn Marino /* VBI data slicer 525 lines, line 21 is closed caption */
479*86d7f5d3SJohn Marino { 0x54, 2, { 0x4d, 0x00 } },
480*86d7f5d3SJohn Marino { 0x5a, 2, { 0x06, 0x83 } },
481*86d7f5d3SJohn Marino
482*86d7f5d3SJohn Marino /* PLL2 525 lines, 27 Mhz target clock */
483*86d7f5d3SJohn Marino { 0xf0, 1, { 0xad } },
484*86d7f5d3SJohn Marino
485*86d7f5d3SJohn Marino /* Pulse generator 525 lines, 27 Mhz target clock */
486*86d7f5d3SJohn Marino { 0xf5, 1, { 0xad } }
487*86d7f5d3SJohn Marino }
488*86d7f5d3SJohn Marino };
489*86d7f5d3SJohn Marino
490*86d7f5d3SJohn Marino static const struct cxm_saa7115_command
491*86d7f5d3SJohn Marino saa7115_scaler_dvd_pal = {
492*86d7f5d3SJohn Marino 13,
493*86d7f5d3SJohn Marino {
494*86d7f5d3SJohn Marino /*
495*86d7f5d3SJohn Marino * Input window = 720 x 288, output window = 720 x 288 with
496*86d7f5d3SJohn Marino * YS extended by 2 as per section 17.4 of the data sheet
497*86d7f5d3SJohn Marino * and YO accounting for scaler processing triggering at
498*86d7f5d3SJohn Marino * line 2 and active video starting at line 25 (see section
499*86d7f5d3SJohn Marino * 8.2 table 8 and section 8.3.1.1 table 11 of the data sheet).
500*86d7f5d3SJohn Marino * PAL active video should actually start at line 24, however
501*86d7f5d3SJohn Marino * not all channels / programs do.
502*86d7f5d3SJohn Marino */
503*86d7f5d3SJohn Marino { 0xc4, 12, { 0x02, 0x00, 0xd0, 0x02, 0x17, 0x00, 0x22, 0x01,
504*86d7f5d3SJohn Marino 0xd0, 0x02, 0x20, 0x01 } },
505*86d7f5d3SJohn Marino
506*86d7f5d3SJohn Marino /* Prefiltering and prescaling */
507*86d7f5d3SJohn Marino { 0xd0, 3, { 0x01, 0x00, 0x00 } },
508*86d7f5d3SJohn Marino
509*86d7f5d3SJohn Marino /* Brightness, contrast, and saturation */
510*86d7f5d3SJohn Marino { 0xd4, 3, { 0x80, 0x40, 0x40 } },
511*86d7f5d3SJohn Marino
512*86d7f5d3SJohn Marino /* Horizontal phase scaling */
513*86d7f5d3SJohn Marino { 0xd8, 3, { 0x00, 0x04, 0x00 } },
514*86d7f5d3SJohn Marino { 0xdc, 3, { 0x00, 0x02, 0x00 } },
515*86d7f5d3SJohn Marino
516*86d7f5d3SJohn Marino /* Vertical scaling */
517*86d7f5d3SJohn Marino { 0xe0, 5, { 0x00, 0x04, 0x00, 0x04, 0x00 } },
518*86d7f5d3SJohn Marino
519*86d7f5d3SJohn Marino /* Vertical phase offsets */
520*86d7f5d3SJohn Marino { 0xe8, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }},
521*86d7f5d3SJohn Marino
522*86d7f5d3SJohn Marino /*
523*86d7f5d3SJohn Marino * VBI input window = 720 x 17, output window = 1440 x 17.
524*86d7f5d3SJohn Marino */
525*86d7f5d3SJohn Marino { 0x94, 12, { 0x02, 0x00, 0xd0, 0x02, 0x04, 0x00, 0x11, 0x00,
526*86d7f5d3SJohn Marino 0xa0, 0x05, 0x11, 0x00 } },
527*86d7f5d3SJohn Marino
528*86d7f5d3SJohn Marino /* Inverted VGATE start at line 25, stop after line 313 */
529*86d7f5d3SJohn Marino { 0x15, 2, { 0x37, 0x17 } },
530*86d7f5d3SJohn Marino
531*86d7f5d3SJohn Marino /* VBI data slicer 625 lines, line 22 is closed caption */
532*86d7f5d3SJohn Marino { 0x54, 2, { 0xdd, 0x4d } },
533*86d7f5d3SJohn Marino { 0x5a, 2, { 0x03, 0x03 } },
534*86d7f5d3SJohn Marino
535*86d7f5d3SJohn Marino /* PLL2 625 lines, 27 Mhz target clock */
536*86d7f5d3SJohn Marino { 0xf0, 1, { 0xb0 } },
537*86d7f5d3SJohn Marino
538*86d7f5d3SJohn Marino /* Pulse generator 625 lines, 27 Mhz target clock */
539*86d7f5d3SJohn Marino { 0xf5, 1, { 0xb0 } }
540*86d7f5d3SJohn Marino }
541*86d7f5d3SJohn Marino };
542*86d7f5d3SJohn Marino
543*86d7f5d3SJohn Marino
544*86d7f5d3SJohn Marino static const struct cxm_saa7115_audio_clock
545*86d7f5d3SJohn Marino saa7115_audio_clock[] = {
546*86d7f5d3SJohn Marino { 44100, 30, &saa7115_audio_clock_44100_ntsc },
547*86d7f5d3SJohn Marino { 44100, 25, &saa7115_audio_clock_44100_pal },
548*86d7f5d3SJohn Marino { 48000, 30, &saa7115_audio_clock_48000_ntsc },
549*86d7f5d3SJohn Marino { 48000, 25, &saa7115_audio_clock_48000_pal }
550*86d7f5d3SJohn Marino };
551*86d7f5d3SJohn Marino
552*86d7f5d3SJohn Marino static const struct cxm_saa7115_scaling
553*86d7f5d3SJohn Marino saa7115_scalings[] = {
554*86d7f5d3SJohn Marino { 352, 480, 30, &saa7115_scaler_vcd_ntsc_double_lines },
555*86d7f5d3SJohn Marino { 352, 576, 25, &saa7115_scaler_vcd_pal_double_lines },
556*86d7f5d3SJohn Marino { 480, 480, 30, &saa7115_scaler_svcd_ntsc },
557*86d7f5d3SJohn Marino { 480, 576, 25, &saa7115_scaler_svcd_pal },
558*86d7f5d3SJohn Marino { 720, 480, 30, &saa7115_scaler_dvd_ntsc },
559*86d7f5d3SJohn Marino { 720, 576, 25, &saa7115_scaler_dvd_pal }
560*86d7f5d3SJohn Marino };
561*86d7f5d3SJohn Marino
562*86d7f5d3SJohn Marino
563*86d7f5d3SJohn Marino /* Reset the SAA7115 chip */
564*86d7f5d3SJohn Marino static int
cxm_saa7115_reset(device_t iicbus,int i2c_addr)565*86d7f5d3SJohn Marino cxm_saa7115_reset(device_t iicbus, int i2c_addr)
566*86d7f5d3SJohn Marino {
567*86d7f5d3SJohn Marino unsigned char msg[2];
568*86d7f5d3SJohn Marino int sent;
569*86d7f5d3SJohn Marino
570*86d7f5d3SJohn Marino /* put into reset mode */
571*86d7f5d3SJohn Marino msg[0] = 0x88;
572*86d7f5d3SJohn Marino msg[1] = 0x0b;
573*86d7f5d3SJohn Marino
574*86d7f5d3SJohn Marino if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
575*86d7f5d3SJohn Marino return -1;
576*86d7f5d3SJohn Marino
577*86d7f5d3SJohn Marino if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
578*86d7f5d3SJohn Marino || sent != sizeof(msg))
579*86d7f5d3SJohn Marino goto fail;
580*86d7f5d3SJohn Marino
581*86d7f5d3SJohn Marino iicbus_stop(iicbus);
582*86d7f5d3SJohn Marino
583*86d7f5d3SJohn Marino /* put back to operational mode */
584*86d7f5d3SJohn Marino msg[0] = 0x88;
585*86d7f5d3SJohn Marino msg[1] = 0x2b;
586*86d7f5d3SJohn Marino
587*86d7f5d3SJohn Marino if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
588*86d7f5d3SJohn Marino return -1;
589*86d7f5d3SJohn Marino
590*86d7f5d3SJohn Marino if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
591*86d7f5d3SJohn Marino || sent != sizeof(msg))
592*86d7f5d3SJohn Marino goto fail;
593*86d7f5d3SJohn Marino
594*86d7f5d3SJohn Marino iicbus_stop(iicbus);
595*86d7f5d3SJohn Marino
596*86d7f5d3SJohn Marino return 0;
597*86d7f5d3SJohn Marino
598*86d7f5d3SJohn Marino fail:
599*86d7f5d3SJohn Marino iicbus_stop(iicbus);
600*86d7f5d3SJohn Marino return -1;
601*86d7f5d3SJohn Marino }
602*86d7f5d3SJohn Marino
603*86d7f5d3SJohn Marino
604*86d7f5d3SJohn Marino /* Read from the SAA7115 registers */
605*86d7f5d3SJohn Marino static int
cxm_saa7115_read(device_t iicbus,int i2c_addr,unsigned char addr,char * buf,int len)606*86d7f5d3SJohn Marino cxm_saa7115_read(device_t iicbus, int i2c_addr,
607*86d7f5d3SJohn Marino unsigned char addr, char *buf, int len)
608*86d7f5d3SJohn Marino {
609*86d7f5d3SJohn Marino unsigned char msg[1];
610*86d7f5d3SJohn Marino int received;
611*86d7f5d3SJohn Marino int sent;
612*86d7f5d3SJohn Marino
613*86d7f5d3SJohn Marino msg[0] = addr;
614*86d7f5d3SJohn Marino
615*86d7f5d3SJohn Marino if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
616*86d7f5d3SJohn Marino return -1;
617*86d7f5d3SJohn Marino
618*86d7f5d3SJohn Marino if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
619*86d7f5d3SJohn Marino || sent != sizeof(msg))
620*86d7f5d3SJohn Marino goto fail;
621*86d7f5d3SJohn Marino
622*86d7f5d3SJohn Marino if (iicbus_repeated_start(iicbus, i2c_addr + 1, CXM_I2C_TIMEOUT) != 0)
623*86d7f5d3SJohn Marino goto fail;
624*86d7f5d3SJohn Marino
625*86d7f5d3SJohn Marino if (iicbus_read(iicbus, buf, len, &received, IIC_LAST_READ, 0) != 0)
626*86d7f5d3SJohn Marino goto fail;
627*86d7f5d3SJohn Marino
628*86d7f5d3SJohn Marino iicbus_stop(iicbus);
629*86d7f5d3SJohn Marino
630*86d7f5d3SJohn Marino return received;
631*86d7f5d3SJohn Marino
632*86d7f5d3SJohn Marino fail:
633*86d7f5d3SJohn Marino iicbus_stop(iicbus);
634*86d7f5d3SJohn Marino return -1;
635*86d7f5d3SJohn Marino }
636*86d7f5d3SJohn Marino
637*86d7f5d3SJohn Marino
638*86d7f5d3SJohn Marino /* Write to the SAA7115 registers */
639*86d7f5d3SJohn Marino static int
cxm_saa7115_write(device_t iicbus,int i2c_addr,unsigned char addr,const char * buf,int len)640*86d7f5d3SJohn Marino cxm_saa7115_write(device_t iicbus, int i2c_addr,
641*86d7f5d3SJohn Marino unsigned char addr, const char *buf, int len)
642*86d7f5d3SJohn Marino {
643*86d7f5d3SJohn Marino unsigned char msg[1];
644*86d7f5d3SJohn Marino int sent;
645*86d7f5d3SJohn Marino
646*86d7f5d3SJohn Marino msg[0] = addr;
647*86d7f5d3SJohn Marino
648*86d7f5d3SJohn Marino if (iicbus_start(iicbus, i2c_addr, CXM_I2C_TIMEOUT) != 0)
649*86d7f5d3SJohn Marino return -1;
650*86d7f5d3SJohn Marino
651*86d7f5d3SJohn Marino if (iicbus_write(iicbus, msg, sizeof(msg), &sent, CXM_I2C_TIMEOUT) != 0
652*86d7f5d3SJohn Marino || sent != sizeof(msg))
653*86d7f5d3SJohn Marino goto fail;
654*86d7f5d3SJohn Marino
655*86d7f5d3SJohn Marino if (iicbus_write(iicbus, buf, len, &sent, CXM_I2C_TIMEOUT) != 0)
656*86d7f5d3SJohn Marino goto fail;
657*86d7f5d3SJohn Marino
658*86d7f5d3SJohn Marino iicbus_stop(iicbus);
659*86d7f5d3SJohn Marino
660*86d7f5d3SJohn Marino return sent;
661*86d7f5d3SJohn Marino
662*86d7f5d3SJohn Marino fail:
663*86d7f5d3SJohn Marino iicbus_stop(iicbus);
664*86d7f5d3SJohn Marino return -1;
665*86d7f5d3SJohn Marino }
666*86d7f5d3SJohn Marino
667*86d7f5d3SJohn Marino
668*86d7f5d3SJohn Marino int
cxm_saa7115_init(struct cxm_softc * sc)669*86d7f5d3SJohn Marino cxm_saa7115_init(struct cxm_softc *sc)
670*86d7f5d3SJohn Marino {
671*86d7f5d3SJohn Marino char name[5];
672*86d7f5d3SJohn Marino unsigned char id[1];
673*86d7f5d3SJohn Marino unsigned char rev;
674*86d7f5d3SJohn Marino unsigned int i;
675*86d7f5d3SJohn Marino unsigned int nsettings;
676*86d7f5d3SJohn Marino const struct cxm_saa7115_setting *settings;
677*86d7f5d3SJohn Marino
678*86d7f5d3SJohn Marino if (cxm_saa7115_reset (sc->iicbus, CXM_I2C_SAA7115) < 0)
679*86d7f5d3SJohn Marino return -1;
680*86d7f5d3SJohn Marino
681*86d7f5d3SJohn Marino name[4] = '\0';
682*86d7f5d3SJohn Marino for (i = 0; i < 4; i++) {
683*86d7f5d3SJohn Marino id[0] = 2 + i;
684*86d7f5d3SJohn Marino
685*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x00,
686*86d7f5d3SJohn Marino id, sizeof(id)) != sizeof(id))
687*86d7f5d3SJohn Marino return -1;
688*86d7f5d3SJohn Marino
689*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x00,
690*86d7f5d3SJohn Marino id, sizeof(id)) != sizeof(id))
691*86d7f5d3SJohn Marino return -1;
692*86d7f5d3SJohn Marino
693*86d7f5d3SJohn Marino name[i] = '0' + (id[0] & 0x0f);
694*86d7f5d3SJohn Marino rev = id[0] >> 4;
695*86d7f5d3SJohn Marino }
696*86d7f5d3SJohn Marino
697*86d7f5d3SJohn Marino /*
698*86d7f5d3SJohn Marino * SAA 7115 is the only video decoder currently supported.
699*86d7f5d3SJohn Marino */
700*86d7f5d3SJohn Marino
701*86d7f5d3SJohn Marino nsettings = 0;
702*86d7f5d3SJohn Marino settings = NULL;
703*86d7f5d3SJohn Marino
704*86d7f5d3SJohn Marino if (strcmp(name, "7115") == 0) {
705*86d7f5d3SJohn Marino nsettings = saa7115_init.nsettings;
706*86d7f5d3SJohn Marino settings = saa7115_init.settings;
707*86d7f5d3SJohn Marino } else {
708*86d7f5d3SJohn Marino device_printf(sc->dev, "unknown video decoder SAA%s\n", name);
709*86d7f5d3SJohn Marino return -1;
710*86d7f5d3SJohn Marino }
711*86d7f5d3SJohn Marino
712*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
713*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
714*86d7f5d3SJohn Marino settings[i].addr,
715*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
716*86d7f5d3SJohn Marino != settings[i].nvalues)
717*86d7f5d3SJohn Marino return -1;
718*86d7f5d3SJohn Marino
719*86d7f5d3SJohn Marino if (cxm_saa7115_select_source(sc, cxm_tuner_source) < 0)
720*86d7f5d3SJohn Marino return -1;
721*86d7f5d3SJohn Marino
722*86d7f5d3SJohn Marino device_printf(sc->dev, "SAA%s rev %u video decoder\n",
723*86d7f5d3SJohn Marino name, (unsigned int)rev);
724*86d7f5d3SJohn Marino
725*86d7f5d3SJohn Marino return 0;
726*86d7f5d3SJohn Marino }
727*86d7f5d3SJohn Marino
728*86d7f5d3SJohn Marino
729*86d7f5d3SJohn Marino int
cxm_saa7115_mute(struct cxm_softc * sc)730*86d7f5d3SJohn Marino cxm_saa7115_mute(struct cxm_softc *sc)
731*86d7f5d3SJohn Marino {
732*86d7f5d3SJohn Marino unsigned int i;
733*86d7f5d3SJohn Marino unsigned int nsettings;
734*86d7f5d3SJohn Marino const struct cxm_saa7115_setting *settings;
735*86d7f5d3SJohn Marino
736*86d7f5d3SJohn Marino nsettings = saa7115_mute.nsettings;
737*86d7f5d3SJohn Marino settings = saa7115_mute.settings;
738*86d7f5d3SJohn Marino
739*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
740*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
741*86d7f5d3SJohn Marino settings[i].addr,
742*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
743*86d7f5d3SJohn Marino != settings[i].nvalues)
744*86d7f5d3SJohn Marino return -1;
745*86d7f5d3SJohn Marino
746*86d7f5d3SJohn Marino return 0;
747*86d7f5d3SJohn Marino }
748*86d7f5d3SJohn Marino
749*86d7f5d3SJohn Marino
750*86d7f5d3SJohn Marino int
cxm_saa7115_unmute(struct cxm_softc * sc)751*86d7f5d3SJohn Marino cxm_saa7115_unmute(struct cxm_softc *sc)
752*86d7f5d3SJohn Marino {
753*86d7f5d3SJohn Marino unsigned int i;
754*86d7f5d3SJohn Marino unsigned int nsettings;
755*86d7f5d3SJohn Marino const struct cxm_saa7115_setting *settings;
756*86d7f5d3SJohn Marino
757*86d7f5d3SJohn Marino nsettings = saa7115_unmute.nsettings;
758*86d7f5d3SJohn Marino settings = saa7115_unmute.settings;
759*86d7f5d3SJohn Marino
760*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
761*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
762*86d7f5d3SJohn Marino settings[i].addr,
763*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
764*86d7f5d3SJohn Marino != settings[i].nvalues)
765*86d7f5d3SJohn Marino return -1;
766*86d7f5d3SJohn Marino
767*86d7f5d3SJohn Marino return 0;
768*86d7f5d3SJohn Marino }
769*86d7f5d3SJohn Marino
770*86d7f5d3SJohn Marino
771*86d7f5d3SJohn Marino int
cxm_saa7115_select_source(struct cxm_softc * sc,enum cxm_source source)772*86d7f5d3SJohn Marino cxm_saa7115_select_source(struct cxm_softc *sc, enum cxm_source source)
773*86d7f5d3SJohn Marino {
774*86d7f5d3SJohn Marino unsigned int i;
775*86d7f5d3SJohn Marino unsigned int nsettings;
776*86d7f5d3SJohn Marino const struct cxm_saa7115_setting *settings;
777*86d7f5d3SJohn Marino
778*86d7f5d3SJohn Marino switch (source) {
779*86d7f5d3SJohn Marino case cxm_fm_source:
780*86d7f5d3SJohn Marino nsettings = saa7115_select_fm.nsettings;
781*86d7f5d3SJohn Marino settings = saa7115_select_fm.settings;
782*86d7f5d3SJohn Marino break;
783*86d7f5d3SJohn Marino
784*86d7f5d3SJohn Marino case cxm_line_in_source_composite:
785*86d7f5d3SJohn Marino nsettings = saa7115_select_line_in_composite.nsettings;
786*86d7f5d3SJohn Marino settings = saa7115_select_line_in_composite.settings;
787*86d7f5d3SJohn Marino break;
788*86d7f5d3SJohn Marino
789*86d7f5d3SJohn Marino case cxm_line_in_source_svideo:
790*86d7f5d3SJohn Marino nsettings = saa7115_select_line_in_svideo.nsettings;
791*86d7f5d3SJohn Marino settings = saa7115_select_line_in_svideo.settings;
792*86d7f5d3SJohn Marino break;
793*86d7f5d3SJohn Marino
794*86d7f5d3SJohn Marino case cxm_tuner_source:
795*86d7f5d3SJohn Marino nsettings = saa7115_select_tuner.nsettings;
796*86d7f5d3SJohn Marino settings = saa7115_select_tuner.settings;
797*86d7f5d3SJohn Marino break;
798*86d7f5d3SJohn Marino
799*86d7f5d3SJohn Marino default:
800*86d7f5d3SJohn Marino return -1;
801*86d7f5d3SJohn Marino }
802*86d7f5d3SJohn Marino
803*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
804*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
805*86d7f5d3SJohn Marino settings[i].addr,
806*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
807*86d7f5d3SJohn Marino != settings[i].nvalues)
808*86d7f5d3SJohn Marino return -1;
809*86d7f5d3SJohn Marino
810*86d7f5d3SJohn Marino return 0;
811*86d7f5d3SJohn Marino }
812*86d7f5d3SJohn Marino
813*86d7f5d3SJohn Marino
814*86d7f5d3SJohn Marino int
cxm_saa7115_configure(struct cxm_softc * sc,unsigned int width,unsigned int height,unsigned int fps,unsigned int audio_sample_rate)815*86d7f5d3SJohn Marino cxm_saa7115_configure(struct cxm_softc *sc,
816*86d7f5d3SJohn Marino unsigned int width, unsigned int height,
817*86d7f5d3SJohn Marino unsigned int fps, unsigned int audio_sample_rate)
818*86d7f5d3SJohn Marino {
819*86d7f5d3SJohn Marino unsigned char power[1];
820*86d7f5d3SJohn Marino unsigned char task[1];
821*86d7f5d3SJohn Marino unsigned int i;
822*86d7f5d3SJohn Marino unsigned int nsettings;
823*86d7f5d3SJohn Marino const struct cxm_saa7115_setting *settings;
824*86d7f5d3SJohn Marino
825*86d7f5d3SJohn Marino for (i = 0; NUM_ELEMENTS(saa7115_scalings); i++)
826*86d7f5d3SJohn Marino if (saa7115_scalings[i].width == width
827*86d7f5d3SJohn Marino && saa7115_scalings[i].height == height
828*86d7f5d3SJohn Marino && saa7115_scalings[i].fps == fps)
829*86d7f5d3SJohn Marino break;
830*86d7f5d3SJohn Marino
831*86d7f5d3SJohn Marino if (i >= NUM_ELEMENTS(saa7115_scalings))
832*86d7f5d3SJohn Marino return -1;
833*86d7f5d3SJohn Marino
834*86d7f5d3SJohn Marino nsettings = saa7115_scalings[i].scaling->nsettings;
835*86d7f5d3SJohn Marino settings = saa7115_scalings[i].scaling->settings;
836*86d7f5d3SJohn Marino
837*86d7f5d3SJohn Marino /*
838*86d7f5d3SJohn Marino * Reset the scaler.
839*86d7f5d3SJohn Marino */
840*86d7f5d3SJohn Marino
841*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88,
842*86d7f5d3SJohn Marino power, sizeof(power)) != sizeof(power))
843*86d7f5d3SJohn Marino return -1;
844*86d7f5d3SJohn Marino
845*86d7f5d3SJohn Marino power[0] &= ~0x20;
846*86d7f5d3SJohn Marino
847*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88,
848*86d7f5d3SJohn Marino power, sizeof(power)) != sizeof(power))
849*86d7f5d3SJohn Marino return -1;
850*86d7f5d3SJohn Marino
851*86d7f5d3SJohn Marino /*
852*86d7f5d3SJohn Marino * Configure the scaler.
853*86d7f5d3SJohn Marino */
854*86d7f5d3SJohn Marino
855*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
856*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
857*86d7f5d3SJohn Marino settings[i].addr,
858*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
859*86d7f5d3SJohn Marino != settings[i].nvalues)
860*86d7f5d3SJohn Marino return -1;
861*86d7f5d3SJohn Marino
862*86d7f5d3SJohn Marino /*
863*86d7f5d3SJohn Marino * Enable task register set A and B.
864*86d7f5d3SJohn Marino */
865*86d7f5d3SJohn Marino
866*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x80,
867*86d7f5d3SJohn Marino task, sizeof(task)) != sizeof(task))
868*86d7f5d3SJohn Marino return -1;
869*86d7f5d3SJohn Marino
870*86d7f5d3SJohn Marino task[0] |= 0x30;
871*86d7f5d3SJohn Marino
872*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x80,
873*86d7f5d3SJohn Marino task, sizeof(task)) != sizeof(task))
874*86d7f5d3SJohn Marino return -1;
875*86d7f5d3SJohn Marino
876*86d7f5d3SJohn Marino /*
877*86d7f5d3SJohn Marino * Enable the scaler.
878*86d7f5d3SJohn Marino */
879*86d7f5d3SJohn Marino
880*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x88,
881*86d7f5d3SJohn Marino power, sizeof(power)) != sizeof(power))
882*86d7f5d3SJohn Marino return -1;
883*86d7f5d3SJohn Marino
884*86d7f5d3SJohn Marino power[0] |= 0x20;
885*86d7f5d3SJohn Marino
886*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x88,
887*86d7f5d3SJohn Marino power, sizeof(power)) != sizeof(power))
888*86d7f5d3SJohn Marino return -1;
889*86d7f5d3SJohn Marino
890*86d7f5d3SJohn Marino /*
891*86d7f5d3SJohn Marino * Configure the audio clock.
892*86d7f5d3SJohn Marino */
893*86d7f5d3SJohn Marino
894*86d7f5d3SJohn Marino for (i = 0; NUM_ELEMENTS(saa7115_audio_clock); i++)
895*86d7f5d3SJohn Marino if (saa7115_audio_clock[i].sample_rate == audio_sample_rate
896*86d7f5d3SJohn Marino && saa7115_audio_clock[i].fps == fps)
897*86d7f5d3SJohn Marino break;
898*86d7f5d3SJohn Marino
899*86d7f5d3SJohn Marino if (i >= NUM_ELEMENTS(saa7115_audio_clock))
900*86d7f5d3SJohn Marino return -1;
901*86d7f5d3SJohn Marino
902*86d7f5d3SJohn Marino nsettings = saa7115_audio_clock[i].clock->nsettings;
903*86d7f5d3SJohn Marino settings = saa7115_audio_clock[i].clock->settings;
904*86d7f5d3SJohn Marino
905*86d7f5d3SJohn Marino for (i = 0; i < nsettings; i++)
906*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115,
907*86d7f5d3SJohn Marino settings[i].addr,
908*86d7f5d3SJohn Marino settings[i].values, settings[i].nvalues)
909*86d7f5d3SJohn Marino != settings[i].nvalues)
910*86d7f5d3SJohn Marino return -1;
911*86d7f5d3SJohn Marino
912*86d7f5d3SJohn Marino return 0;
913*86d7f5d3SJohn Marino }
914*86d7f5d3SJohn Marino
915*86d7f5d3SJohn Marino
916*86d7f5d3SJohn Marino enum cxm_source_format
cxm_saa7115_detected_format(struct cxm_softc * sc)917*86d7f5d3SJohn Marino cxm_saa7115_detected_format(struct cxm_softc *sc)
918*86d7f5d3SJohn Marino {
919*86d7f5d3SJohn Marino unsigned char status[2];
920*86d7f5d3SJohn Marino enum cxm_source_format source_format;
921*86d7f5d3SJohn Marino
922*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1e,
923*86d7f5d3SJohn Marino status, sizeof(status)) != sizeof(status))
924*86d7f5d3SJohn Marino return cxm_unknown_source_format;
925*86d7f5d3SJohn Marino
926*86d7f5d3SJohn Marino if (!(status[1] & 0x01)) {
927*86d7f5d3SJohn Marino device_printf(sc->dev, "video decoder isn't locked\n");
928*86d7f5d3SJohn Marino return cxm_unknown_source_format;
929*86d7f5d3SJohn Marino }
930*86d7f5d3SJohn Marino
931*86d7f5d3SJohn Marino source_format = cxm_unknown_source_format;
932*86d7f5d3SJohn Marino
933*86d7f5d3SJohn Marino if (!(status[1] & 0x20)) {
934*86d7f5d3SJohn Marino switch (status[0] & 0x03) {
935*86d7f5d3SJohn Marino case 0:
936*86d7f5d3SJohn Marino source_format = cxm_bw_50hz_source_format;
937*86d7f5d3SJohn Marino break;
938*86d7f5d3SJohn Marino
939*86d7f5d3SJohn Marino case 1:
940*86d7f5d3SJohn Marino source_format = cxm_ntsc_50hz_source_format;
941*86d7f5d3SJohn Marino break;
942*86d7f5d3SJohn Marino
943*86d7f5d3SJohn Marino case 2:
944*86d7f5d3SJohn Marino source_format = cxm_pal_50hz_source_format;
945*86d7f5d3SJohn Marino break;
946*86d7f5d3SJohn Marino
947*86d7f5d3SJohn Marino case 3:
948*86d7f5d3SJohn Marino source_format = cxm_secam_50hz_source_format;
949*86d7f5d3SJohn Marino break;
950*86d7f5d3SJohn Marino
951*86d7f5d3SJohn Marino default:
952*86d7f5d3SJohn Marino break;
953*86d7f5d3SJohn Marino }
954*86d7f5d3SJohn Marino } else {
955*86d7f5d3SJohn Marino switch (status[0] & 0x03) {
956*86d7f5d3SJohn Marino case 0:
957*86d7f5d3SJohn Marino source_format = cxm_bw_60hz_source_format;
958*86d7f5d3SJohn Marino break;
959*86d7f5d3SJohn Marino
960*86d7f5d3SJohn Marino case 1:
961*86d7f5d3SJohn Marino source_format = cxm_ntsc_60hz_source_format;
962*86d7f5d3SJohn Marino break;
963*86d7f5d3SJohn Marino
964*86d7f5d3SJohn Marino case 2:
965*86d7f5d3SJohn Marino source_format = cxm_pal_60hz_source_format;
966*86d7f5d3SJohn Marino break;
967*86d7f5d3SJohn Marino
968*86d7f5d3SJohn Marino default:
969*86d7f5d3SJohn Marino break;
970*86d7f5d3SJohn Marino }
971*86d7f5d3SJohn Marino }
972*86d7f5d3SJohn Marino
973*86d7f5d3SJohn Marino return source_format;
974*86d7f5d3SJohn Marino }
975*86d7f5d3SJohn Marino
976*86d7f5d3SJohn Marino
977*86d7f5d3SJohn Marino int
cxm_saa7115_detected_fps(struct cxm_softc * sc)978*86d7f5d3SJohn Marino cxm_saa7115_detected_fps(struct cxm_softc *sc)
979*86d7f5d3SJohn Marino {
980*86d7f5d3SJohn Marino unsigned char status[1];
981*86d7f5d3SJohn Marino
982*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f,
983*86d7f5d3SJohn Marino status, sizeof(status)) != sizeof(status))
984*86d7f5d3SJohn Marino return -1;
985*86d7f5d3SJohn Marino
986*86d7f5d3SJohn Marino if (!(status[0] & 0x01)) {
987*86d7f5d3SJohn Marino device_printf(sc->dev, "video decoder isn't locked\n");
988*86d7f5d3SJohn Marino return -1;
989*86d7f5d3SJohn Marino }
990*86d7f5d3SJohn Marino
991*86d7f5d3SJohn Marino return (status[0] & 0x20) ? 30 : 25;
992*86d7f5d3SJohn Marino }
993*86d7f5d3SJohn Marino
994*86d7f5d3SJohn Marino
995*86d7f5d3SJohn Marino int
cxm_saa7115_get_brightness(struct cxm_softc * sc)996*86d7f5d3SJohn Marino cxm_saa7115_get_brightness(struct cxm_softc *sc)
997*86d7f5d3SJohn Marino {
998*86d7f5d3SJohn Marino unsigned char brightness;
999*86d7f5d3SJohn Marino
1000*86d7f5d3SJohn Marino /*
1001*86d7f5d3SJohn Marino * Brightness is treated as an unsigned value by the decoder.
1002*86d7f5d3SJohn Marino * 0 = dark, 128 = ITU level, 255 = bright
1003*86d7f5d3SJohn Marino */
1004*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0a,
1005*86d7f5d3SJohn Marino &brightness, sizeof(brightness))
1006*86d7f5d3SJohn Marino != sizeof(brightness))
1007*86d7f5d3SJohn Marino return -1;
1008*86d7f5d3SJohn Marino
1009*86d7f5d3SJohn Marino return brightness;
1010*86d7f5d3SJohn Marino }
1011*86d7f5d3SJohn Marino
1012*86d7f5d3SJohn Marino
1013*86d7f5d3SJohn Marino int
cxm_saa7115_set_brightness(struct cxm_softc * sc,unsigned char brightness)1014*86d7f5d3SJohn Marino cxm_saa7115_set_brightness(struct cxm_softc *sc, unsigned char brightness)
1015*86d7f5d3SJohn Marino {
1016*86d7f5d3SJohn Marino
1017*86d7f5d3SJohn Marino /*
1018*86d7f5d3SJohn Marino * Brightness is treated as an unsigned value by the decoder.
1019*86d7f5d3SJohn Marino * 0 = dark, 128 = ITU level, 255 = bright
1020*86d7f5d3SJohn Marino */
1021*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0a,
1022*86d7f5d3SJohn Marino &brightness, sizeof(brightness))
1023*86d7f5d3SJohn Marino != sizeof(brightness))
1024*86d7f5d3SJohn Marino return -1;
1025*86d7f5d3SJohn Marino
1026*86d7f5d3SJohn Marino return 0;
1027*86d7f5d3SJohn Marino }
1028*86d7f5d3SJohn Marino
1029*86d7f5d3SJohn Marino
1030*86d7f5d3SJohn Marino int
cxm_saa7115_get_chroma_saturation(struct cxm_softc * sc)1031*86d7f5d3SJohn Marino cxm_saa7115_get_chroma_saturation(struct cxm_softc *sc)
1032*86d7f5d3SJohn Marino {
1033*86d7f5d3SJohn Marino unsigned char chroma_saturation;
1034*86d7f5d3SJohn Marino
1035*86d7f5d3SJohn Marino /*
1036*86d7f5d3SJohn Marino * Chroma saturation is treated as a signed value by the decoder.
1037*86d7f5d3SJohn Marino * -128 = -2.0 (inverse chrominance), -64 = 1.0 (inverse chrominance),
1038*86d7f5d3SJohn Marino * 0 = 0 (color off), 64 = 1.0 (ITU level), 127 = 1.984 (maximum)
1039*86d7f5d3SJohn Marino */
1040*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0c,
1041*86d7f5d3SJohn Marino &chroma_saturation, sizeof(chroma_saturation))
1042*86d7f5d3SJohn Marino != sizeof(chroma_saturation))
1043*86d7f5d3SJohn Marino return -1;
1044*86d7f5d3SJohn Marino
1045*86d7f5d3SJohn Marino return chroma_saturation;
1046*86d7f5d3SJohn Marino }
1047*86d7f5d3SJohn Marino
1048*86d7f5d3SJohn Marino
1049*86d7f5d3SJohn Marino int
cxm_saa7115_set_chroma_saturation(struct cxm_softc * sc,unsigned char chroma_saturation)1050*86d7f5d3SJohn Marino cxm_saa7115_set_chroma_saturation(struct cxm_softc *sc,
1051*86d7f5d3SJohn Marino unsigned char chroma_saturation)
1052*86d7f5d3SJohn Marino {
1053*86d7f5d3SJohn Marino
1054*86d7f5d3SJohn Marino /*
1055*86d7f5d3SJohn Marino * Chroma saturation is treated as a signed value by the decoder.
1056*86d7f5d3SJohn Marino * -128 = -2.0 (inverse chrominance), -64 = 1.0 (inverse chrominance),
1057*86d7f5d3SJohn Marino * 0 = 0 (color off), 64 = 1.0 (ITU level), 127 = 1.984 (maximum)
1058*86d7f5d3SJohn Marino */
1059*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0c,
1060*86d7f5d3SJohn Marino &chroma_saturation, sizeof(chroma_saturation))
1061*86d7f5d3SJohn Marino != sizeof(chroma_saturation))
1062*86d7f5d3SJohn Marino return -1;
1063*86d7f5d3SJohn Marino
1064*86d7f5d3SJohn Marino return 0;
1065*86d7f5d3SJohn Marino }
1066*86d7f5d3SJohn Marino
1067*86d7f5d3SJohn Marino
1068*86d7f5d3SJohn Marino int
cxm_saa7115_get_contrast(struct cxm_softc * sc)1069*86d7f5d3SJohn Marino cxm_saa7115_get_contrast(struct cxm_softc *sc)
1070*86d7f5d3SJohn Marino {
1071*86d7f5d3SJohn Marino unsigned char contrast;
1072*86d7f5d3SJohn Marino
1073*86d7f5d3SJohn Marino /*
1074*86d7f5d3SJohn Marino * Contrast is treated as a signed value by the decoder.
1075*86d7f5d3SJohn Marino * -128 = -2.0 (inverse luminance), -64 = 1.0 (inverse luminance),
1076*86d7f5d3SJohn Marino * 0 = 0 (luminance off), 64 = 1.0, 68 = 1.063 (ITU level),
1077*86d7f5d3SJohn Marino * 127 = 1.984 (maximum)
1078*86d7f5d3SJohn Marino */
1079*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0b,
1080*86d7f5d3SJohn Marino &contrast, sizeof(contrast)) != sizeof(contrast))
1081*86d7f5d3SJohn Marino return -1;
1082*86d7f5d3SJohn Marino
1083*86d7f5d3SJohn Marino return contrast;
1084*86d7f5d3SJohn Marino }
1085*86d7f5d3SJohn Marino
1086*86d7f5d3SJohn Marino
1087*86d7f5d3SJohn Marino int
cxm_saa7115_set_contrast(struct cxm_softc * sc,unsigned char contrast)1088*86d7f5d3SJohn Marino cxm_saa7115_set_contrast(struct cxm_softc *sc, unsigned char contrast)
1089*86d7f5d3SJohn Marino {
1090*86d7f5d3SJohn Marino
1091*86d7f5d3SJohn Marino /*
1092*86d7f5d3SJohn Marino * Contrast is treated as a signed value by the decoder.
1093*86d7f5d3SJohn Marino * -128 = -2.0 (inverse luminance), -64 = 1.0 (inverse luminance),
1094*86d7f5d3SJohn Marino * 0 = 0 (luminance off), 64 = 1.0, 68 = 1.063 (ITU level),
1095*86d7f5d3SJohn Marino * 127 = 1.984 (maximum)
1096*86d7f5d3SJohn Marino */
1097*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0b,
1098*86d7f5d3SJohn Marino &contrast, sizeof(contrast)) != sizeof(contrast))
1099*86d7f5d3SJohn Marino return -1;
1100*86d7f5d3SJohn Marino
1101*86d7f5d3SJohn Marino return 0;
1102*86d7f5d3SJohn Marino }
1103*86d7f5d3SJohn Marino
1104*86d7f5d3SJohn Marino
1105*86d7f5d3SJohn Marino int
cxm_saa7115_get_hue(struct cxm_softc * sc)1106*86d7f5d3SJohn Marino cxm_saa7115_get_hue(struct cxm_softc *sc)
1107*86d7f5d3SJohn Marino {
1108*86d7f5d3SJohn Marino unsigned char hue;
1109*86d7f5d3SJohn Marino
1110*86d7f5d3SJohn Marino /*
1111*86d7f5d3SJohn Marino * Hue is treated as a signed value by the decoder.
1112*86d7f5d3SJohn Marino * -128 = -180.0, 0 = 0.0, 127 = +178.6
1113*86d7f5d3SJohn Marino */
1114*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x0d,
1115*86d7f5d3SJohn Marino &hue, sizeof(hue))
1116*86d7f5d3SJohn Marino != sizeof(hue))
1117*86d7f5d3SJohn Marino return -1;
1118*86d7f5d3SJohn Marino
1119*86d7f5d3SJohn Marino return hue;
1120*86d7f5d3SJohn Marino }
1121*86d7f5d3SJohn Marino
1122*86d7f5d3SJohn Marino
1123*86d7f5d3SJohn Marino int
cxm_saa7115_set_hue(struct cxm_softc * sc,unsigned char hue)1124*86d7f5d3SJohn Marino cxm_saa7115_set_hue(struct cxm_softc *sc, unsigned char hue)
1125*86d7f5d3SJohn Marino {
1126*86d7f5d3SJohn Marino
1127*86d7f5d3SJohn Marino /*
1128*86d7f5d3SJohn Marino * Hue is treated as a signed value by the decoder.
1129*86d7f5d3SJohn Marino * -128 = -180.0, 0 = 0.0, 127 = +178.6
1130*86d7f5d3SJohn Marino */
1131*86d7f5d3SJohn Marino if (cxm_saa7115_write(sc->iicbus, CXM_I2C_SAA7115, 0x0d,
1132*86d7f5d3SJohn Marino &hue, sizeof(hue))
1133*86d7f5d3SJohn Marino != sizeof(hue))
1134*86d7f5d3SJohn Marino return -1;
1135*86d7f5d3SJohn Marino
1136*86d7f5d3SJohn Marino return 0;
1137*86d7f5d3SJohn Marino }
1138*86d7f5d3SJohn Marino
1139*86d7f5d3SJohn Marino
1140*86d7f5d3SJohn Marino int
cxm_saa7115_is_locked(struct cxm_softc * sc)1141*86d7f5d3SJohn Marino cxm_saa7115_is_locked(struct cxm_softc *sc)
1142*86d7f5d3SJohn Marino {
1143*86d7f5d3SJohn Marino unsigned char status[1];
1144*86d7f5d3SJohn Marino
1145*86d7f5d3SJohn Marino if (cxm_saa7115_read(sc->iicbus, CXM_I2C_SAA7115, 0x1f,
1146*86d7f5d3SJohn Marino status, sizeof(status)) != sizeof(status))
1147*86d7f5d3SJohn Marino return -1;
1148*86d7f5d3SJohn Marino
1149*86d7f5d3SJohn Marino return (status[0] & 0x01) ? 1 : 0;
1150*86d7f5d3SJohn Marino }
1151*86d7f5d3SJohn Marino
1152*86d7f5d3SJohn Marino
1153*86d7f5d3SJohn Marino int
cxm_saa7115_wait_for_lock(struct cxm_softc * sc)1154*86d7f5d3SJohn Marino cxm_saa7115_wait_for_lock(struct cxm_softc *sc)
1155*86d7f5d3SJohn Marino {
1156*86d7f5d3SJohn Marino unsigned int i;
1157*86d7f5d3SJohn Marino
1158*86d7f5d3SJohn Marino /*
1159*86d7f5d3SJohn Marino * Section 2.7 of the data sheet states:
1160*86d7f5d3SJohn Marino *
1161*86d7f5d3SJohn Marino * Ultra-fast frame lock (almost 1 field)
1162*86d7f5d3SJohn Marino *
1163*86d7f5d3SJohn Marino * so hopefully 500 ms is enough (the lock
1164*86d7f5d3SJohn Marino * sometimes takes a long time to occur ...
1165*86d7f5d3SJohn Marino * possibly due to the time it takes to
1166*86d7f5d3SJohn Marino * autodetect the format).
1167*86d7f5d3SJohn Marino */
1168*86d7f5d3SJohn Marino
1169*86d7f5d3SJohn Marino for (i = 0; i < 10; i++) {
1170*86d7f5d3SJohn Marino
1171*86d7f5d3SJohn Marino /*
1172*86d7f5d3SJohn Marino * The input may have just changed (prior to
1173*86d7f5d3SJohn Marino * cxm_saa7115_wait_for_lock) so start with
1174*86d7f5d3SJohn Marino * the delay to give the video decoder a
1175*86d7f5d3SJohn Marino * chance to update its status.
1176*86d7f5d3SJohn Marino */
1177*86d7f5d3SJohn Marino
1178*86d7f5d3SJohn Marino tsleep(&sc->iicbus, 0, "video", hz / 20);
1179*86d7f5d3SJohn Marino
1180*86d7f5d3SJohn Marino switch (cxm_saa7115_is_locked(sc)) {
1181*86d7f5d3SJohn Marino case 1:
1182*86d7f5d3SJohn Marino return 1;
1183*86d7f5d3SJohn Marino
1184*86d7f5d3SJohn Marino case 0:
1185*86d7f5d3SJohn Marino break;
1186*86d7f5d3SJohn Marino
1187*86d7f5d3SJohn Marino default:
1188*86d7f5d3SJohn Marino return -1;
1189*86d7f5d3SJohn Marino }
1190*86d7f5d3SJohn Marino }
1191*86d7f5d3SJohn Marino
1192*86d7f5d3SJohn Marino device_printf(sc->dev, "video decoder failed to lock\n");
1193*86d7f5d3SJohn Marino
1194*86d7f5d3SJohn Marino return 0;
1195*86d7f5d3SJohn Marino }
1196