-static const u32 xtal = 28636363;
-
-static int set_pll(struct cx8800_dev *dev, int prescale, u32 ofreq)
-{
- static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
- u64 pll;
- u32 reg;
- int i;
-
- if (prescale < 2)
- prescale = 2;
- if (prescale > 5)
- prescale = 5;
-
- pll = ofreq * 8 * prescale * (u64)(1 << 20);
- do_div(pll,xtal);
- reg = (pll & 0x3ffffff) | (pre[prescale] << 26);
- if (((reg >> 20) & 0x3f) < 14) {
- printk("%s: pll out of range\n",dev->name);
- return -1;
- }
-
- dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n",
- reg, cx_read(MO_PLL_REG), ofreq);
- cx_write(MO_PLL_REG, reg);
- for (i = 0; i < 10; i++) {
- reg = cx_read(MO_DEVICE_STATUS);
- if (reg & (1<<2)) {
- dprintk(1,"pll locked [pre=%d,ofreq=%d]\n",
- prescale,ofreq);
- return 0;
- }
- dprintk(1,"pll not locked yet, waiting ...\n");
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/10);
- }
- dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq);
- return -1;
-}
-
-static int set_tvaudio(struct cx8800_dev *dev)
-{
- if (CX88_VMUX_TELEVISION != INPUT(dev->input)->type)
- return 0;
-
- if (V4L2_STD_PAL_BG & dev->tvnorm->id) {
- dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_BG;
-
- } else if (V4L2_STD_PAL_DK & dev->tvnorm->id) {
- dev->tvaudio = nicam ? WW_NICAM_BGDKL : WW_A2_DK;
-
- } else if (V4L2_STD_PAL_I & dev->tvnorm->id) {
- dev->tvaudio = WW_NICAM_I;
-
- } else if (V4L2_STD_SECAM_L & dev->tvnorm->id) {
- dev->tvaudio = WW_SYSTEM_L_AM;
-
- } else if (V4L2_STD_SECAM_DK & dev->tvnorm->id) {
- dev->tvaudio = WW_A2_DK;
-
- } else if ((V4L2_STD_NTSC_M & dev->tvnorm->id) ||
- (V4L2_STD_PAL_M & dev->tvnorm->id)) {
- dev->tvaudio = WW_BTSC;
-
- } else if (V4L2_STD_NTSC_M_JP & dev->tvnorm->id) {
- dev->tvaudio = WW_EIAJ;
-
- } else {
- printk("%s: tvaudio support needs work for this tv norm [%s], sorry\n",
- dev->name, dev->tvnorm->name);
- dev->tvaudio = 0;
- return 0;
- }
-
- cx_andor(MO_AFECFG_IO, 0x1f, 0x0);
- cx88_set_tvaudio(dev);
- // cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO);
-
- cx_write(MO_AUDD_LNGTH, 128/8); /* fifo size */
- cx_write(MO_AUDR_LNGTH, 128/8); /* fifo size */
- cx_write(MO_AUD_DMACNTRL, 0x03); /* need audio fifo */
- return 0;
-}
-
-static int set_tvnorm(struct cx8800_dev *dev, struct cx8800_tvnorm *norm)
-{
- u32 fsc8;
- u32 adc_clock;
- u32 vdec_clock;
- u64 tmp64;
- u32 bdelay,agcdelay,htotal;
-
- dev->tvnorm = norm;
- fsc8 = norm_fsc8(norm);
- adc_clock = xtal;
- vdec_clock = fsc8;
-
- dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d\n",
- norm->name, fsc8, adc_clock, vdec_clock);
- set_pll(dev,2,vdec_clock);
-
- dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
-
-#if 1
- // FIXME: as-is from DScaler
- dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
-#endif
-
- // MO_SCONV_REG = adc clock / video dec clock * 2^17
- tmp64 = adc_clock * (u64)(1 << 17);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SCONV_REG));
- cx_write(MO_SCONV_REG, (u32)tmp64);
-
- // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22
- tmp64 = fsc8 * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP));
- cx_write(MO_SUB_STEP, (u32)tmp64);
-
- // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22
- tmp64 = 4406250 * 8 * (u64)(1 << 22);
- do_div(tmp64, vdec_clock);
- dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n",
- (u32)tmp64, cx_read(MO_SUB_STEP_DR));
- cx_write(MO_SUB_STEP_DR, (u32)tmp64);
-
- // bdelay + agcdelay
- bdelay = vdec_clock * 65 / 20000000 + 21;
- agcdelay = vdec_clock * 68 / 20000000 + 15;
- dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n",
- (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay);
- cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay);
-
- // htotal
- tmp64 = norm_htotal(norm) * (u64)vdec_clock;
- do_div(tmp64, fsc8);
- htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
- dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
- htotal, cx_read(MO_HTOTAL), (u32)tmp64);
- cx_write(MO_HTOTAL, htotal);
-
- // vbi stuff
- cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
- norm_vbipack(norm)));
-
- // audio
- set_tvaudio(dev);
-
- // tell i2c chips
-#ifdef V4L2_I2C_CLIENTS
- cx8800_call_i2c_clients(dev,VIDIOC_S_STD,&norm->id);
-#else
- {
- struct video_channel c;
- memset(&c,0,sizeof(c));
- c.channel = dev->input;
- c.norm = VIDEO_MODE_PAL;
- if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
- c.norm = VIDEO_MODE_NTSC;
- if (norm->id & V4L2_STD_SECAM)
- c.norm = VIDEO_MODE_SECAM;
- cx8800_call_i2c_clients(dev,VIDIOCSCHAN,&c);
- }
-#endif
-
- // done
- return 0;
-}
-
-static int set_scale(struct cx8800_dev *dev, unsigned int width, unsigned int height,
- enum v4l2_field field)
-{
- unsigned int swidth = norm_swidth(dev->tvnorm);
- unsigned int sheight = norm_maxh(dev->tvnorm);
- u32 value;
-
- dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
- V4L2_FIELD_HAS_TOP(field) ? "T" : "",
- V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- dev->tvnorm->name);
- if (!V4L2_FIELD_HAS_BOTH(field))
- height *= 2;
-
- // recalc H delay and scale registers
- value = (width * norm_hdelay(dev->tvnorm)) / swidth;
- value &= 0x3fe;
- cx_write(MO_HDELAY_EVEN, value);
- cx_write(MO_HDELAY_ODD, value);
- dprintk(1,"set_scale: hdelay 0x%04x\n", value);
-
- value = (swidth * 4096 / width) - 4096;
- cx_write(MO_HSCALE_EVEN, value);
- cx_write(MO_HSCALE_ODD, value);
- dprintk(1,"set_scale: hscale 0x%04x\n", value);
-
- cx_write(MO_HACTIVE_EVEN, width);
- cx_write(MO_HACTIVE_ODD, width);
- dprintk(1,"set_scale: hactive 0x%04x\n", width);
-
- // recalc V scale Register (delay is constant)
- cx_write(MO_VDELAY_EVEN, norm_vdelay(dev->tvnorm));
- cx_write(MO_VDELAY_ODD, norm_vdelay(dev->tvnorm));
- dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(dev->tvnorm));
-
- value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff;
- cx_write(MO_VSCALE_EVEN, value);
- cx_write(MO_VSCALE_ODD, value);
- dprintk(1,"set_scale: vscale 0x%04x\n", value);
-
- cx_write(MO_VACTIVE_EVEN, sheight);
- cx_write(MO_VACTIVE_ODD, sheight);
- dprintk(1,"set_scale: vactive 0x%04x\n", sheight);
-
- // setup filters
- value = 0;
- value |= (1 << 19); // CFILT (default)
- if (V4L2_FIELD_INTERLACED == field)
- value |= (1 << 3); // VINT (interlaced vertical scaling)
- if (width < 385)
- value |= (1 << 0); // 3-tap interpolation
- if (width < 193)
- value |= (1 << 1); // 5-tap interpolation
-
- cx_write(MO_FILTER_EVEN, value);
- cx_write(MO_FILTER_ODD, value);
- dprintk(1,"set_scale: filter 0x%04x\n", value);
-
- return 0;
-}
-