diff options
Diffstat (limited to 'drivers/media/pci')
116 files changed, 8170 insertions, 1116 deletions
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 218144a99..f318ae9bb 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -21,6 +21,7 @@ source "drivers/media/pci/zoran/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/tw68/Kconfig" +source "drivers/media/pci/dt3155/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT @@ -32,6 +33,7 @@ source "drivers/media/pci/cx88/Kconfig" source "drivers/media/pci/bt8xx/Kconfig" source "drivers/media/pci/saa7134/Kconfig" source "drivers/media/pci/saa7164/Kconfig" +source "drivers/media/pci/cobalt/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 0baf0d296..23ce53bd4 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -24,6 +24,8 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_TW68) += tw68/ +obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ +obj-$(CONFIG_VIDEO_COBALT) += cobalt/ diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c index 2364d1658..9f1f9169f 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.c +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -54,23 +54,33 @@ void winview_volume(struct bttv *btv, __u16 volume) void gvbctv3pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned int con = 0; + unsigned int con; - if (set) { - gpio_inout(0x300, 0x300); - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x300; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x200; -/* if (t->audmode & V4L2_TUNER_MODE_MONO) - * con = 0x100; */ - gpio_bits(0x300, con); - } else { - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + gpio_inout(0x300, 0x300); + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG1: + default: + con = 0x000; + break; + case V4L2_TUNER_MODE_LANG2: + con = 0x300; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x200; + break; } + gpio_bits(0x300, con); } void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) @@ -82,47 +92,51 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) val = gpio_read(); if (set) { - con = 0x000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) { - if (t->audmode & V4L2_TUNER_MODE_LANG1) { - /* LANG1 + LANG2 */ - con = 0x100; - } - else { - /* LANG2 */ - con = 0x300; - } + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: + con = 0x300; + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + con = 0x100; + break; + default: + con = 0x000; + break; } if (con != (val & 0x300)) { gpio_bits(0x300, con); if (bttv_gpio) - bttv_gpio_tracking(btv,"gvbctv5pci"); + bttv_gpio_tracking(btv, "gvbctv5pci"); } } else { switch (val & 0x70) { case 0x10: t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x30: t->rxsubchans = V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x50: t->rxsubchans = V4L2_TUNER_SUB_LANG1; + t->audmode = V4L2_TUNER_MODE_LANG1_LANG2; break; case 0x60: t->rxsubchans = V4L2_TUNER_SUB_STEREO; + t->audmode = V4L2_TUNER_MODE_STEREO; break; case 0x70: t->rxsubchans = V4L2_TUNER_SUB_MONO; + t->audmode = V4L2_TUNER_MODE_MONO; break; default: t->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + t->audmode = V4L2_TUNER_MODE_LANG1; } - t->audmode = V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; } } @@ -142,23 +156,32 @@ void gvbctv5pci_audio(struct bttv *btv, struct v4l2_tuner *t, int set) void avermedia_tvphone_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - int val = 0; + int val; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x02; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0x01; - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x02; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x01; + break; + default: return; } + gpio_bits(0x03, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "avermedia"); } @@ -166,19 +189,31 @@ void avermedia_tv_stereo_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { int val = 0; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x01; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* STEREO */ - val = 0x02; - btaor(val, ~0x03, BT848_GPIO_DATA); - if (bttv_gpio) - bttv_gpio_tracking(btv,"avermedia"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x01; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x02; + break; + default: + val = 0; + break; + } + btaor(val, ~0x03, BT848_GPIO_DATA); + if (bttv_gpio) + bttv_gpio_tracking(btv, "avermedia"); } /* Lifetec 9415 handling */ @@ -192,23 +227,32 @@ void lt9415_audio(struct bttv *btv, struct v4l2_tuner *t, int set) return; } - if (set) { - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* A2 SAP */ - val = 0x0080; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* A2 stereo */ - val = 0x0880; - if ((t->audmode & V4L2_TUNER_MODE_LANG1) || - (t->audmode & V4L2_TUNER_MODE_MONO)) - val = 0; - gpio_bits(0x0880, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"lt9415"); - } else { - /* autodetect doesn't work with this card :-( */ - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: /* A2 SAP */ + val = 0x0080; + break; + case V4L2_TUNER_MODE_STEREO: /* A2 stereo */ + val = 0x0880; + break; + default: + val = 0; + break; + } + + gpio_bits(0x0880, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "lt9415"); } /* TDA9821 on TerraTV+ Bt848, Bt878 */ @@ -216,45 +260,69 @@ void terratv_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { unsigned int con = 0; - if (set) { - gpio_inout(0x180000,0x180000); - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x080000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x180000; - gpio_bits(0x180000, con); - if (bttv_gpio) - bttv_gpio_tracking(btv,"terratv"); - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + gpio_inout(0x180000, 0x180000); + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG2: + con = 0x080000; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x180000; + break; + default: + con = 0; + break; } + gpio_bits(0x180000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "terratv"); } void winfast2000_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned long val = 0; + unsigned long val; - if (set) { - /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ - if (t->audmode & V4L2_TUNER_MODE_MONO) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) /* Mono */ - val = 0x420000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) /* SAP */ - val = 0x410000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) /* Stereo */ - val = 0x020000; - if (val) { - gpio_bits(0x430000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"winfast2000"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + /*btor (0xc32000, BT848_GPIO_OUT_EN);*/ + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + case V4L2_TUNER_MODE_LANG1: + val = 0x420000; + break; + case V4L2_TUNER_MODE_LANG2: /* SAP */ + val = 0x410000; + break; + case V4L2_TUNER_MODE_STEREO: + val = 0x020000; + break; + default: + return; + } + + gpio_bits(0x430000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "winfast2000"); } /* @@ -272,23 +340,33 @@ void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) if (btv->radio_user) return; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x01; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x02; - } - if (val) { - gpio_bits(0x03,val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"pvbt878p9b"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x01; + break; + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_STEREO: + val = 0x02; + break; + default: + return; + } + + gpio_bits(0x03, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "pvbt878p9b"); } /* @@ -298,28 +376,37 @@ void pvbt878p9b_audio(struct bttv *btv, struct v4l2_tuner *t, int set) */ void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned int val = 0xffff; + unsigned int val; if (btv->radio_user) return; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) { - val = 0x0000; - } - if ((t->audmode & (V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2)) - || (t->audmode & V4L2_TUNER_MODE_STEREO)) { - val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ - } - if (val != 0xffff) { - gpio_bits(0x1800, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"fv2000s"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x0000; + break; + case V4L2_TUNER_MODE_LANG1: + case V4L2_TUNER_MODE_LANG2: + case V4L2_TUNER_MODE_STEREO: + val = 0x1080; /*-dk-???: 0x0880, 0x0080, 0x1800 ... */ + break; + default: + return; + } + gpio_bits(0x1800, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "fv2000s"); } /* @@ -328,26 +415,33 @@ void fv2000s_audio(struct bttv *btv, struct v4l2_tuner *t, int set) */ void windvr_audio(struct bttv *btv, struct v4l2_tuner *t, int set) { - unsigned long val = 0; + unsigned long val; - if (set) { - if (t->audmode & V4L2_TUNER_MODE_MONO) - val = 0x040000; - if (t->audmode & V4L2_TUNER_MODE_LANG1) - val = 0; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - val = 0x100000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - val = 0; - if (val) { - gpio_bits(0x140000, val); - if (bttv_gpio) - bttv_gpio_tracking(btv,"windvr"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; + } + + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + val = 0x040000; + break; + case V4L2_TUNER_MODE_LANG2: + val = 0x100000; + break; + default: + return; } + + gpio_bits(0x140000, val); + if (bttv_gpio) + bttv_gpio_tracking(btv, "windvr"); } /* @@ -360,23 +454,36 @@ void adtvk503_audio(struct bttv *btv, struct v4l2_tuner *t, int set) /* btaor(0x1e0000, ~0x1e0000, BT848_GPIO_OUT_EN); */ - if (set) { - /* btor(***, BT848_GPIO_OUT_EN); */ - if (t->audmode & V4L2_TUNER_MODE_LANG1) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_LANG2) - con = 0x00180000; - if (t->audmode & V4L2_TUNER_MODE_STEREO) - con = 0x00000000; - if (t->audmode & V4L2_TUNER_MODE_MONO) - con = 0x00060000; - if (con != 0xffffff) { - gpio_bits(0x1e0000,con); - if (bttv_gpio) - bttv_gpio_tracking(btv, "adtvk503"); - } - } else { - t->audmode = V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO | - V4L2_TUNER_MODE_LANG1 | V4L2_TUNER_MODE_LANG2; + if (!set) { + /* Not much to do here */ + t->audmode = V4L2_TUNER_MODE_LANG1; + t->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | + V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + + return; } + + /* btor(***, BT848_GPIO_OUT_EN); */ + switch (t->audmode) { + case V4L2_TUNER_MODE_LANG1: + con = 0x00000000; + break; + case V4L2_TUNER_MODE_LANG2: + con = 0x00180000; + break; + case V4L2_TUNER_MODE_STEREO: + con = 0x00000000; + break; + case V4L2_TUNER_MODE_MONO: + con = 0x00060000; + break; + default: + return; + } + + gpio_bits(0x1e0000, con); + if (bttv_gpio) + bttv_gpio_tracking(btv, "adtvk503"); } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index bc12060e0..3632958f2 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2676,7 +2676,8 @@ static int bttv_s_fbuf(struct file *file, void *f, fh->ov.w.height = fb->fmt.height; btv->init.ov.w.width = fb->fmt.width; btv->init.ov.w.height = fb->fmt.height; - kfree(fh->ov.clips); + + kfree(fh->ov.clips); fh->ov.clips = NULL; fh->ov.nclips = 0; @@ -4238,6 +4239,7 @@ fail0: iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), pci_resource_len(btv->c.pci,0)); + pci_disable_device(btv->c.pci); return result; } @@ -4281,6 +4283,7 @@ static void bttv_remove(struct pci_dev *pci_dev) iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), pci_resource_len(btv->c.pci,0)); + pci_disable_device(btv->c.pci); v4l2_device_unregister(&btv->c.v4l2_dev); bttvs[btv->c.nr] = NULL; diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index f2261dfe5..4a90eee5e 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -425,7 +425,8 @@ static int dst_set_bandwidth(struct dst_state *state, u32 bandwidth) return 0; } -static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t inversion) +static int dst_set_inversion(struct dst_state *state, + enum fe_spectral_inversion inversion) { state->inversion = inversion; switch (inversion) { @@ -442,13 +443,13 @@ static int dst_set_inversion(struct dst_state *state, fe_spectral_inversion_t in return 0; } -static int dst_set_fec(struct dst_state *state, fe_code_rate_t fec) +static int dst_set_fec(struct dst_state *state, enum fe_code_rate fec) { state->fec = fec; return 0; } -static fe_code_rate_t dst_get_fec(struct dst_state *state) +static enum fe_code_rate dst_get_fec(struct dst_state *state) { return state->fec; } @@ -499,7 +500,8 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) return 0; } -static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) +static int dst_set_modulation(struct dst_state *state, + enum fe_modulation modulation) { if (state->dst_type != DST_TYPE_IS_CABLE) return -EOPNOTSUPP; @@ -536,7 +538,7 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio return 0; } -static fe_modulation_t dst_get_modulation(struct dst_state *state) +static enum fe_modulation dst_get_modulation(struct dst_state *state) { return state->modulation; } @@ -1376,7 +1378,8 @@ static int dst_get_tuna(struct dst_state *state) return 1; } -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +static int dst_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); static int dst_write_tuna(struct dvb_frontend *fe) { @@ -1466,7 +1469,7 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd return dst_command(state, paket, 8); } -static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dst_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { int need_cmd, retval = 0; struct dst_state *state = fe->demodulator_priv; @@ -1500,7 +1503,7 @@ static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return retval; } -static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +static int dst_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct dst_state *state = fe->demodulator_priv; @@ -1525,7 +1528,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) return dst_tone_power_cmd(state); } -static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) +static int dst_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd minicmd) { struct dst_state *state = fe->demodulator_priv; @@ -1575,7 +1578,7 @@ static int bt8xx_dst_init(struct dvb_frontend *fe) return 0; } -static int dst_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int dst_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct dst_state *state = fe->demodulator_priv; @@ -1646,7 +1649,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct dst_state *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index c22c4ae06..c5cc14ef8 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -320,29 +320,27 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, if (copy_from_user(p_ca_message, arg, sizeof (struct ca_msg))) return -EFAULT; - if (p_ca_message->msg) { - dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", - 3, p_ca_message->msg); - - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; - } - dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + dprintk(verbose, DST_CA_NOTICE, 1, " Message = [%*ph]", + 3, p_ca_message->msg); - switch (command) { - case CA_APP_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - case CA_INFO: - memcpy(p_ca_message->msg, state->messages, 128); - if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) - return -EFAULT; - break; - } + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_NOTICE, 1, " Command=[0x%x]", command); + + switch (command) { + case CA_APP_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; } return 0; @@ -494,60 +492,58 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, goto free_mem_and_exit; } + /* EN50221 tag */ + command = 0; - if (p_ca_message->msg) { - /* EN50221 tag */ - command = 0; + for (i = 0; i < 3; i++) { + command = command | p_ca_message->msg[i]; + if (i < 2) + command = command << 8; + } + dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - for (i = 0; i < 3; i++) { - command = command | p_ca_message->msg[i]; - if (i < 2) - command = command << 8; + switch (command) { + case CA_PMT: + dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); + if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); + result = -1; + goto free_mem_and_exit; } - dprintk(verbose, DST_CA_DEBUG, 1, " Command=[0x%x]\n", command); - - switch (command) { - case CA_PMT: - dprintk(verbose, DST_CA_DEBUG, 1, "Command = SEND_CA_PMT"); - if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); - break; - case CA_PMT_REPLY: - dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); - /* Have to handle the 2 basic types of cards here */ - if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); - break; - case CA_APP_INFO_ENQUIRY: // only for debugging - dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); - - if ((ca_get_app_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); - break; - case CA_INFO_ENQUIRY: - dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); - - if ((ca_get_ca_info(state)) < 0) { - dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); - result = -1; - goto free_mem_and_exit; - } - dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); - break; + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT Success !"); + break; + case CA_PMT_REPLY: + dprintk(verbose, DST_CA_INFO, 1, "Command = CA_PMT_REPLY"); + /* Have to handle the 2 basic types of cards here */ + if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_PMT_REPLY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_PMT_REPLY Success !"); + break; + case CA_APP_INFO_ENQUIRY: // only for debugging + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam Application information"); + + if ((ca_get_app_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_APP_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); + break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; } + free_mem_and_exit: kfree (hw_buffer); diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h index d70d98f1a..6a2cfdd44 100644 --- a/drivers/media/pci/bt8xx/dst_common.h +++ b/drivers/media/pci/bt8xx/dst_common.h @@ -113,11 +113,11 @@ struct dst_state { u8 dst_type; u32 type_flags; u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; + enum fe_spectral_inversion inversion; u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; + enum fe_code_rate fec; + enum fe_sec_voltage voltage; + enum fe_sec_tone_mode tone; u32 decode_freq; u8 decode_lock; u16 decode_strength; @@ -127,8 +127,8 @@ struct dst_state { u32 bandwidth; u32 dst_hw_cap; u8 dst_fw_version; - fe_sec_mini_cmd_t minicmd; - fe_modulation_t modulation; + enum fe_sec_mini_cmd minicmd; + enum fe_modulation modulation; u8 messages[256]; u8 mac_address[8]; u8 fw_version[8]; diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig new file mode 100644 index 000000000..6a1c0089b --- /dev/null +++ b/drivers/media/pci/cobalt/Kconfig @@ -0,0 +1,19 @@ +config VIDEO_COBALT + tristate "Cisco Cobalt support" + depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + depends on SND + select I2C_ALGOBIT + select VIDEO_ADV7604 + select VIDEO_ADV7511 + select VIDEO_ADV7842 + select VIDEOBUF2_DMA_SG + ---help--- + This is a video4linux driver for the Cisco PCIe Cobalt card. + + This board is sadly not available outside of Cisco, but it is + very useful as an example of a real driver that uses all the + latest frameworks and APIs. + + To compile this driver as a module, choose M here: the + module will be called cobalt. diff --git a/drivers/media/pci/cobalt/Makefile b/drivers/media/pci/cobalt/Makefile new file mode 100644 index 000000000..b328955ab --- /dev/null +++ b/drivers/media/pci/cobalt/Makefile @@ -0,0 +1,5 @@ +cobalt-objs := cobalt-driver.o cobalt-irq.o cobalt-v4l2.o \ + cobalt-i2c.o cobalt-omnitek.o cobalt-flash.o cobalt-cpld.o \ + cobalt-alsa-main.o cobalt-alsa-pcm.o + +obj-$(CONFIG_VIDEO_COBALT) += cobalt.o diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c new file mode 100644 index 000000000..720e3ad93 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -0,0 +1,162 @@ +/* + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/spinlock.h> + +#include <media/v4l2-device.h> + +#include <sound/core.h> +#include <sound/initval.h> + +#include "cobalt-driver.h" +#include "cobalt-alsa.h" +#include "cobalt-alsa-pcm.h" + +static void snd_cobalt_card_free(struct snd_cobalt_card *cobsc) +{ + if (cobsc == NULL) + return; + + cobsc->s->alsa = NULL; + + kfree(cobsc); +} + +static void snd_cobalt_card_private_free(struct snd_card *sc) +{ + if (sc == NULL) + return; + snd_cobalt_card_free(sc->private_data); + sc->private_data = NULL; + sc->private_free = NULL; +} + +static int snd_cobalt_card_create(struct cobalt_stream *s, + struct snd_card *sc, + struct snd_cobalt_card **cobsc) +{ + *cobsc = kzalloc(sizeof(struct snd_cobalt_card), GFP_KERNEL); + if (*cobsc == NULL) + return -ENOMEM; + + (*cobsc)->s = s; + (*cobsc)->sc = sc; + + sc->private_data = *cobsc; + sc->private_free = snd_cobalt_card_private_free; + + return 0; +} + +static int snd_cobalt_card_set_names(struct snd_cobalt_card *cobsc) +{ + struct cobalt_stream *s = cobsc->s; + struct cobalt *cobalt = s->cobalt; + struct snd_card *sc = cobsc->sc; + + /* sc->driver is used by alsa-lib's configurator: simple, unique */ + strlcpy(sc->driver, "cobalt", sizeof(sc->driver)); + + /* sc->shortname is a symlink in /proc/asound: COBALT-M -> cardN */ + snprintf(sc->shortname, sizeof(sc->shortname), "cobalt-%d-%d", + cobalt->instance, s->video_channel); + + /* sc->longname is read from /proc/asound/cards */ + snprintf(sc->longname, sizeof(sc->longname), + "Cobalt %d HDMI %d", + cobalt->instance, s->video_channel); + + return 0; +} + +int cobalt_alsa_init(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct snd_card *sc = NULL; + struct snd_cobalt_card *cobsc; + int ret; + + /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */ + + /* (1) Check and increment the device index */ + /* This is a no-op for us. We'll use the cobalt->instance */ + + /* (2) Create a card instance */ + ret = snd_card_new(&cobalt->pci_dev->dev, SNDRV_DEFAULT_IDX1, + SNDRV_DEFAULT_STR1, THIS_MODULE, 0, &sc); + if (ret) { + cobalt_err("snd_card_new() failed with err %d\n", ret); + goto err_exit; + } + + /* (3) Create a main component */ + ret = snd_cobalt_card_create(s, sc, &cobsc); + if (ret) { + cobalt_err("snd_cobalt_card_create() failed with err %d\n", + ret); + goto err_exit_free; + } + + /* (4) Set the driver ID and name strings */ + snd_cobalt_card_set_names(cobsc); + + ret = snd_cobalt_pcm_create(cobsc); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed with err %d\n", + ret); + goto err_exit_free; + } + /* FIXME - proc files */ + + /* (7) Set the driver data and return 0 */ + /* We do this out of normal order for PCI drivers to avoid races */ + s->alsa = cobsc; + + /* (6) Register the card instance */ + ret = snd_card_register(sc); + if (ret) { + s->alsa = NULL; + cobalt_err("snd_card_register() failed with err %d\n", ret); + goto err_exit_free; + } + + return 0; + +err_exit_free: + if (sc != NULL) + snd_card_free(sc); + kfree(cobsc); +err_exit: + return ret; +} + +void cobalt_alsa_exit(struct cobalt_stream *s) +{ + struct snd_cobalt_card *cobsc = s->alsa; + + if (cobsc) + snd_card_free(cobsc->sc); + s->alsa = NULL; +} diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.c b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c new file mode 100644 index 000000000..f0bdf10cf --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.c @@ -0,0 +1,603 @@ +/* + * ALSA PCM device for the + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> + +#include <media/v4l2-device.h> + +#include <sound/core.h> +#include <sound/pcm.h> + +#include "cobalt-driver.h" +#include "cobalt-alsa.h" +#include "cobalt-alsa-pcm.h" + +static unsigned int pcm_debug; +module_param(pcm_debug, int, 0644); +MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); + +#define dprintk(fmt, arg...) \ + do { \ + if (pcm_debug) \ + pr_info("cobalt-alsa-pcm %s: " fmt, __func__, ##arg); \ + } while (0) + +static struct snd_pcm_hardware snd_cobalt_hdmi_capture = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + + .rates = SNDRV_PCM_RATE_48000, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = 4 * 240 * 8 * 4, /* 5 ms of data */ + .period_bytes_min = 1920, /* 1 sample = 8 * 4 bytes */ + .period_bytes_max = 240 * 8 * 4, /* 5 ms of 8 channel data */ + .periods_min = 1, + .periods_max = 4, +}; + +static struct snd_pcm_hardware snd_cobalt_playback = { + .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID, + + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + + .rates = SNDRV_PCM_RATE_48000, + + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 8, + .buffer_bytes_max = 4 * 240 * 8 * 4, /* 5 ms of data */ + .period_bytes_min = 1920, /* 1 sample = 8 * 4 bytes */ + .period_bytes_max = 240 * 8 * 4, /* 5 ms of 8 channel data */ + .periods_min = 1, + .periods_max = 4, +}; + +static void sample_cpy(u8 *dst, const u8 *src, u32 len, bool is_s32) +{ + static const unsigned map[8] = { 0, 1, 5, 4, 2, 3, 6, 7 }; + unsigned idx = 0; + + while (len >= (is_s32 ? 4 : 2)) { + unsigned offset = map[idx] * 4; + u32 val = src[offset + 1] + (src[offset + 2] << 8) + + (src[offset + 3] << 16); + + if (is_s32) { + *dst++ = 0; + *dst++ = val & 0xff; + } + *dst++ = (val >> 8) & 0xff; + *dst++ = (val >> 16) & 0xff; + len -= is_s32 ? 4 : 2; + idx++; + } +} + +static void cobalt_alsa_announce_pcm_data(struct snd_cobalt_card *cobsc, + u8 *pcm_data, + size_t skip, + size_t samples) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned long flags; + unsigned int oldptr; + unsigned int stride; + int length = samples; + int period_elapsed = 0; + bool is_s32; + + dprintk("cobalt alsa announce ptr=%p data=%p num_bytes=%zd\n", cobsc, + pcm_data, samples); + + substream = cobsc->capture_pcm_substream; + if (substream == NULL) { + dprintk("substream was NULL\n"); + return; + } + + runtime = substream->runtime; + if (runtime == NULL) { + dprintk("runtime was NULL\n"); + return; + } + is_s32 = runtime->format == SNDRV_PCM_FORMAT_S32_LE; + + stride = runtime->frame_bits >> 3; + if (stride == 0) { + dprintk("stride is zero\n"); + return; + } + + if (length == 0) { + dprintk("%s: length was zero\n", __func__); + return; + } + + if (runtime->dma_area == NULL) { + dprintk("dma area was NULL - ignoring\n"); + return; + } + + oldptr = cobsc->hwptr_done_capture; + if (oldptr + length >= runtime->buffer_size) { + unsigned int cnt = runtime->buffer_size - oldptr; + unsigned i; + + for (i = 0; i < cnt; i++) + sample_cpy(runtime->dma_area + (oldptr + i) * stride, + pcm_data + i * skip, + stride, is_s32); + for (i = cnt; i < length; i++) + sample_cpy(runtime->dma_area + (i - cnt) * stride, + pcm_data + i * skip, stride, is_s32); + } else { + unsigned i; + + for (i = 0; i < length; i++) + sample_cpy(runtime->dma_area + (oldptr + i) * stride, + pcm_data + i * skip, + stride, is_s32); + } + snd_pcm_stream_lock_irqsave(substream, flags); + + cobsc->hwptr_done_capture += length; + if (cobsc->hwptr_done_capture >= + runtime->buffer_size) + cobsc->hwptr_done_capture -= + runtime->buffer_size; + + cobsc->capture_transfer_done += length; + if (cobsc->capture_transfer_done >= + runtime->period_size) { + cobsc->capture_transfer_done -= + runtime->period_size; + period_elapsed = 1; + } + + snd_pcm_stream_unlock_irqrestore(substream, flags); + + if (period_elapsed) + snd_pcm_period_elapsed(substream); +} + +static int alsa_fnc(struct vb2_buffer *vb, void *priv) +{ + struct cobalt_stream *s = priv; + unsigned char *p = vb2_plane_vaddr(vb, 0); + int i; + + if (pcm_debug) { + pr_info("alsa: "); + for (i = 0; i < 8 * 4; i++) { + if (!(i & 3)) + pr_cont(" "); + pr_cont("%02x", p[i]); + } + pr_cont("\n"); + } + cobalt_alsa_announce_pcm_data(s->alsa, + vb2_plane_vaddr(vb, 0), + 8 * 4, + vb2_get_plane_payload(vb, 0) / (8 * 4)); + return 0; +} + +static int snd_cobalt_pcm_capture_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + runtime->hw = snd_cobalt_hdmi_capture; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + cobsc->capture_pcm_substream = substream; + runtime->private_data = s; + cobsc->alsa_record_cnt++; + if (cobsc->alsa_record_cnt == 1) { + int rc; + + rc = vb2_thread_start(&s->q, alsa_fnc, s, s->vdev.name); + if (rc) { + cobsc->alsa_record_cnt--; + return rc; + } + } + return 0; +} + +static int snd_cobalt_pcm_capture_close(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + cobsc->alsa_record_cnt--; + if (cobsc->alsa_record_cnt == 0) + vb2_thread_stop(&s->q); + return 0; +} + +static int snd_cobalt_pcm_ioctl(struct snd_pcm_substream *substream, + unsigned int cmd, void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + + +static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, + size_t size) +{ + struct snd_pcm_runtime *runtime = subs->runtime; + + dprintk("Allocating vbuffer\n"); + if (runtime->dma_area) { + if (runtime->dma_bytes > size) + return 0; + + vfree(runtime->dma_area); + } + runtime->dma_area = vmalloc(size); + if (!runtime->dma_area) + return -ENOMEM; + + runtime->dma_bytes = size; + + return 0; +} + +static int snd_cobalt_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + dprintk("%s called\n", __func__); + + return snd_pcm_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); +} + +static int snd_cobalt_pcm_hw_free(struct snd_pcm_substream *substream) +{ + if (substream->runtime->dma_area) { + dprintk("freeing pcm capture region\n"); + vfree(substream->runtime->dma_area); + substream->runtime->dma_area = NULL; + } + + return 0; +} + +static int snd_cobalt_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + cobsc->hwptr_done_capture = 0; + cobsc->capture_transfer_done = 0; + + return 0; +} + +static int snd_cobalt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_STOP: + return 0; + default: + return -EINVAL; + } + return 0; +} + +static +snd_pcm_uframes_t snd_cobalt_pcm_pointer(struct snd_pcm_substream *substream) +{ + snd_pcm_uframes_t hwptr_done; + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + hwptr_done = cobsc->hwptr_done_capture; + + return hwptr_done; +} + +static void pb_sample_cpy(u8 *dst, const u8 *src, u32 len, bool is_s32) +{ + static const unsigned map[8] = { 0, 1, 5, 4, 2, 3, 6, 7 }; + unsigned idx = 0; + + while (len >= (is_s32 ? 4 : 2)) { + unsigned offset = map[idx] * 4; + u8 *out = dst + offset; + + *out++ = 0; + if (is_s32) { + src++; + *out++ = *src++; + } else { + *out++ = 0; + } + *out++ = *src++; + *out = *src++; + len -= is_s32 ? 4 : 2; + idx++; + } +} + +static void cobalt_alsa_pb_pcm_data(struct snd_cobalt_card *cobsc, + u8 *pcm_data, + size_t skip, + size_t samples) +{ + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + unsigned long flags; + unsigned int pos; + unsigned int stride; + bool is_s32; + unsigned i; + + dprintk("cobalt alsa pb ptr=%p data=%p samples=%zd\n", cobsc, + pcm_data, samples); + + substream = cobsc->playback_pcm_substream; + if (substream == NULL) { + dprintk("substream was NULL\n"); + return; + } + + runtime = substream->runtime; + if (runtime == NULL) { + dprintk("runtime was NULL\n"); + return; + } + + is_s32 = runtime->format == SNDRV_PCM_FORMAT_S32_LE; + stride = runtime->frame_bits >> 3; + if (stride == 0) { + dprintk("stride is zero\n"); + return; + } + + if (samples == 0) { + dprintk("%s: samples was zero\n", __func__); + return; + } + + if (runtime->dma_area == NULL) { + dprintk("dma area was NULL - ignoring\n"); + return; + } + + pos = cobsc->pb_pos % cobsc->pb_size; + for (i = 0; i < cobsc->pb_count / (8 * 4); i++) + pb_sample_cpy(pcm_data + i * skip, + runtime->dma_area + pos + i * stride, + stride, is_s32); + snd_pcm_stream_lock_irqsave(substream, flags); + + cobsc->pb_pos += i * stride; + + snd_pcm_stream_unlock_irqrestore(substream, flags); + if (cobsc->pb_pos % cobsc->pb_count == 0) + snd_pcm_period_elapsed(substream); +} + +static int alsa_pb_fnc(struct vb2_buffer *vb, void *priv) +{ + struct cobalt_stream *s = priv; + + if (s->alsa->alsa_pb_channel) + cobalt_alsa_pb_pcm_data(s->alsa, + vb2_plane_vaddr(vb, 0), + 8 * 4, + vb2_get_plane_payload(vb, 0) / (8 * 4)); + return 0; +} + +static int snd_cobalt_pcm_playback_open(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct cobalt_stream *s = cobsc->s; + + runtime->hw = snd_cobalt_playback; + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + cobsc->playback_pcm_substream = substream; + runtime->private_data = s; + cobsc->alsa_playback_cnt++; + if (cobsc->alsa_playback_cnt == 1) { + int rc; + + rc = vb2_thread_start(&s->q, alsa_pb_fnc, s, s->vdev.name); + if (rc) { + cobsc->alsa_playback_cnt--; + return rc; + } + } + + return 0; +} + +static int snd_cobalt_pcm_playback_close(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + struct cobalt_stream *s = cobsc->s; + + cobsc->alsa_playback_cnt--; + if (cobsc->alsa_playback_cnt == 0) + vb2_thread_stop(&s->q); + return 0; +} + +static int snd_cobalt_pcm_pb_prepare(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + cobsc->pb_size = snd_pcm_lib_buffer_bytes(substream); + cobsc->pb_count = snd_pcm_lib_period_bytes(substream); + cobsc->pb_pos = 0; + + return 0; +} + +static int snd_cobalt_pcm_pb_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (cobsc->alsa_pb_channel) + return -EBUSY; + cobsc->alsa_pb_channel = true; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + cobsc->alsa_pb_channel = false; + return 0; + default: + return -EINVAL; + } +} + +static +snd_pcm_uframes_t snd_cobalt_pcm_pb_pointer(struct snd_pcm_substream *substream) +{ + struct snd_cobalt_card *cobsc = snd_pcm_substream_chip(substream); + size_t ptr; + + ptr = cobsc->pb_pos; + + return bytes_to_frames(substream->runtime, ptr) % + substream->runtime->buffer_size; +} + +static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, + unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + + return vmalloc_to_page(pageptr); +} + +static struct snd_pcm_ops snd_cobalt_pcm_capture_ops = { + .open = snd_cobalt_pcm_capture_open, + .close = snd_cobalt_pcm_capture_close, + .ioctl = snd_cobalt_pcm_ioctl, + .hw_params = snd_cobalt_pcm_hw_params, + .hw_free = snd_cobalt_pcm_hw_free, + .prepare = snd_cobalt_pcm_prepare, + .trigger = snd_cobalt_pcm_trigger, + .pointer = snd_cobalt_pcm_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +static struct snd_pcm_ops snd_cobalt_pcm_playback_ops = { + .open = snd_cobalt_pcm_playback_open, + .close = snd_cobalt_pcm_playback_close, + .ioctl = snd_cobalt_pcm_ioctl, + .hw_params = snd_cobalt_pcm_hw_params, + .hw_free = snd_cobalt_pcm_hw_free, + .prepare = snd_cobalt_pcm_pb_prepare, + .trigger = snd_cobalt_pcm_pb_trigger, + .pointer = snd_cobalt_pcm_pb_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + +int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc) +{ + struct snd_pcm *sp; + struct snd_card *sc = cobsc->sc; + struct cobalt_stream *s = cobsc->s; + struct cobalt *cobalt = s->cobalt; + int ret; + + s->q.gfp_flags |= __GFP_ZERO; + + if (!s->is_output) { + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(s->video_channel), + 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(s->video_channel), + 1); + mdelay(1); + + ret = snd_pcm_new(sc, "Cobalt PCM-In HDMI", + 0, /* PCM device 0, the only one for this card */ + 0, /* 0 playback substreams */ + 1, /* 1 capture substream */ + &sp); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed for input with err %d\n", + ret); + goto err_exit; + } + + snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, + &snd_cobalt_pcm_capture_ops); + sp->info_flags = 0; + sp->private_data = cobsc; + strlcpy(sp->name, "cobalt", sizeof(sp->name)); + } else { + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT, 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT, 1); + mdelay(1); + + ret = snd_pcm_new(sc, "Cobalt PCM-Out HDMI", + 0, /* PCM device 0, the only one for this card */ + 1, /* 0 playback substreams */ + 0, /* 1 capture substream */ + &sp); + if (ret) { + cobalt_err("snd_cobalt_pcm_create() failed for output with err %d\n", + ret); + goto err_exit; + } + + snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_PLAYBACK, + &snd_cobalt_pcm_playback_ops); + sp->info_flags = 0; + sp->private_data = cobsc; + strlcpy(sp->name, "cobalt", sizeof(sp->name)); + } + + return 0; + +err_exit: + return ret; +} diff --git a/drivers/media/pci/cobalt/cobalt-alsa-pcm.h b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h new file mode 100644 index 000000000..513fb1f71 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa-pcm.h @@ -0,0 +1,22 @@ +/* + * ALSA PCM device for the + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +int snd_cobalt_pcm_create(struct snd_cobalt_card *cobsc); diff --git a/drivers/media/pci/cobalt/cobalt-alsa.h b/drivers/media/pci/cobalt/cobalt-alsa.h new file mode 100644 index 000000000..08db699ce --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-alsa.h @@ -0,0 +1,41 @@ +/* + * ALSA interface to cobalt PCM capture streams + * + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +struct snd_card; + +struct snd_cobalt_card { + struct cobalt_stream *s; + struct snd_card *sc; + unsigned int capture_transfer_done; + unsigned int hwptr_done_capture; + unsigned alsa_record_cnt; + struct snd_pcm_substream *capture_pcm_substream; + + unsigned int pb_size; + unsigned int pb_count; + unsigned int pb_pos; + unsigned pb_filled; + bool alsa_pb_channel; + unsigned alsa_playback_cnt; + struct snd_pcm_substream *playback_pcm_substream; +}; + +int cobalt_alsa_init(struct cobalt_stream *s); +void cobalt_alsa_exit(struct cobalt_stream *s); diff --git a/drivers/media/pci/cobalt/cobalt-cpld.c b/drivers/media/pci/cobalt/cobalt-cpld.c new file mode 100644 index 000000000..e83f5c9f7 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-cpld.c @@ -0,0 +1,341 @@ +/* + * Cobalt CPLD functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/delay.h> + +#include "cobalt-cpld.h" + +#define ADRS(offset) (COBALT_BUS_CPLD_BASE + offset) + +static u16 cpld_read(struct cobalt *cobalt, u32 offset) +{ + return cobalt_bus_read32(cobalt->bar1, ADRS(offset)); +} + +static void cpld_write(struct cobalt *cobalt, u32 offset, u16 val) +{ + return cobalt_bus_write32(cobalt->bar1, ADRS(offset), val); +} + +static void cpld_info_ver3(struct cobalt *cobalt) +{ + u32 rd; + u32 tmp; + + cobalt_info("CPLD System control register (read/write)\n"); + cobalt_info("\t\tSystem control: 0x%04x (0x0f00)\n", + cpld_read(cobalt, 0)); + cobalt_info("CPLD Clock control register (read/write)\n"); + cobalt_info("\t\tClock control: 0x%04x (0x0000)\n", + cpld_read(cobalt, 0x04)); + cobalt_info("CPLD HSMA Clk Osc register (read/write) - Must set wr trigger to load default values\n"); + cobalt_info("\t\tRegister #7:\t0x%04x (0x0022)\n", + cpld_read(cobalt, 0x08)); + cobalt_info("\t\tRegister #8:\t0x%04x (0x0047)\n", + cpld_read(cobalt, 0x0c)); + cobalt_info("\t\tRegister #9:\t0x%04x (0x00fa)\n", + cpld_read(cobalt, 0x10)); + cobalt_info("\t\tRegister #10:\t0x%04x (0x0061)\n", + cpld_read(cobalt, 0x14)); + cobalt_info("\t\tRegister #11:\t0x%04x (0x001e)\n", + cpld_read(cobalt, 0x18)); + cobalt_info("\t\tRegister #12:\t0x%04x (0x0045)\n", + cpld_read(cobalt, 0x1c)); + cobalt_info("\t\tRegister #135:\t0x%04x\n", + cpld_read(cobalt, 0x20)); + cobalt_info("\t\tRegister #137:\t0x%04x\n", + cpld_read(cobalt, 0x24)); + cobalt_info("CPLD System status register (read only)\n"); + cobalt_info("\t\tSystem status: 0x%04x\n", + cpld_read(cobalt, 0x28)); + cobalt_info("CPLD MAXII info register (read only)\n"); + cobalt_info("\t\tBoard serial number: 0x%04x\n", + cpld_read(cobalt, 0x2c)); + cobalt_info("\t\tMAXII program revision: 0x%04x\n", + cpld_read(cobalt, 0x30)); + cobalt_info("CPLD temp and voltage ADT7411 registers (read only)\n"); + cobalt_info("\t\tBoard temperature: %u Celcius\n", + cpld_read(cobalt, 0x34) / 4); + cobalt_info("\t\tFPGA temperature: %u Celcius\n", + cpld_read(cobalt, 0x38) / 4); + rd = cpld_read(cobalt, 0x3c); + tmp = (rd * 33 * 1000) / (483 * 10); + cobalt_info("\t\tVDD 3V3: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x40); + tmp = (rd * 74 * 2197) / (27 * 1000); + cobalt_info("\t\tADC ch3 5V: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x44); + tmp = (rd * 74 * 2197) / (47 * 1000); + cobalt_info("\t\tADC ch4 3V: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x48); + tmp = (rd * 57 * 2197) / (47 * 1000); + cobalt_info("\t\tADC ch5 2V5: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x4c); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch6 1V8: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x50); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch7 1V5: %u,%03uV\n", tmp / 1000, tmp % 1000); + rd = cpld_read(cobalt, 0x54); + tmp = (rd * 2197) / 1000; + cobalt_info("\t\tADC ch8 0V9: %u,%03uV\n", tmp / 1000, tmp % 1000); +} + +void cobalt_cpld_status(struct cobalt *cobalt) +{ + u32 rev = cpld_read(cobalt, 0x30); + + switch (rev) { + case 3: + case 4: + case 5: + cpld_info_ver3(cobalt); + break; + default: + cobalt_info("CPLD revision %u is not supported!\n", rev); + break; + } +} + +#define DCO_MIN 4850000000ULL +#define DCO_MAX 5670000000ULL + +#define SI570_CLOCK_CTRL 0x04 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER 0x200 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER 0x100 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL 0x80 +#define S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN 0x40 + +#define SI570_REG7 0x08 +#define SI570_REG8 0x0c +#define SI570_REG9 0x10 +#define SI570_REG10 0x14 +#define SI570_REG11 0x18 +#define SI570_REG12 0x1c +#define SI570_REG135 0x20 +#define SI570_REG137 0x24 + +struct multiplier { + unsigned mult, hsdiv, n1; +}; + +/* List all possible multipliers (= hsdiv * n1). There are lots of duplicates, + which are all removed in this list to keep the list as short as possible. + The values for hsdiv and n1 are the actual values, not the register values. + */ +static const struct multiplier multipliers[] = { + { 4, 4, 1 }, { 5, 5, 1 }, { 6, 6, 1 }, + { 7, 7, 1 }, { 8, 4, 2 }, { 9, 9, 1 }, + { 10, 5, 2 }, { 11, 11, 1 }, { 12, 6, 2 }, + { 14, 7, 2 }, { 16, 4, 4 }, { 18, 9, 2 }, + { 20, 5, 4 }, { 22, 11, 2 }, { 24, 4, 6 }, + { 28, 7, 4 }, { 30, 5, 6 }, { 32, 4, 8 }, + { 36, 6, 6 }, { 40, 4, 10 }, { 42, 7, 6 }, + { 44, 11, 4 }, { 48, 4, 12 }, { 50, 5, 10 }, + { 54, 9, 6 }, { 56, 4, 14 }, { 60, 5, 12 }, + { 64, 4, 16 }, { 66, 11, 6 }, { 70, 5, 14 }, + { 72, 4, 18 }, { 80, 4, 20 }, { 84, 6, 14 }, + { 88, 11, 8 }, { 90, 5, 18 }, { 96, 4, 24 }, + { 98, 7, 14 }, { 100, 5, 20 }, { 104, 4, 26 }, + { 108, 6, 18 }, { 110, 11, 10 }, { 112, 4, 28 }, + { 120, 4, 30 }, { 126, 7, 18 }, { 128, 4, 32 }, + { 130, 5, 26 }, { 132, 11, 12 }, { 136, 4, 34 }, + { 140, 5, 28 }, { 144, 4, 36 }, { 150, 5, 30 }, + { 152, 4, 38 }, { 154, 11, 14 }, { 156, 6, 26 }, + { 160, 4, 40 }, { 162, 9, 18 }, { 168, 4, 42 }, + { 170, 5, 34 }, { 176, 11, 16 }, { 180, 5, 36 }, + { 182, 7, 26 }, { 184, 4, 46 }, { 190, 5, 38 }, + { 192, 4, 48 }, { 196, 7, 28 }, { 198, 11, 18 }, + { 198, 9, 22 }, { 200, 4, 50 }, { 204, 6, 34 }, + { 208, 4, 52 }, { 210, 5, 42 }, { 216, 4, 54 }, + { 220, 11, 20 }, { 224, 4, 56 }, { 228, 6, 38 }, + { 230, 5, 46 }, { 232, 4, 58 }, { 234, 9, 26 }, + { 238, 7, 34 }, { 240, 4, 60 }, { 242, 11, 22 }, + { 248, 4, 62 }, { 250, 5, 50 }, { 252, 6, 42 }, + { 256, 4, 64 }, { 260, 5, 52 }, { 264, 11, 24 }, + { 266, 7, 38 }, { 270, 5, 54 }, { 272, 4, 68 }, + { 276, 6, 46 }, { 280, 4, 70 }, { 286, 11, 26 }, + { 288, 4, 72 }, { 290, 5, 58 }, { 294, 7, 42 }, + { 296, 4, 74 }, { 300, 5, 60 }, { 304, 4, 76 }, + { 306, 9, 34 }, { 308, 11, 28 }, { 310, 5, 62 }, + { 312, 4, 78 }, { 320, 4, 80 }, { 322, 7, 46 }, + { 324, 6, 54 }, { 328, 4, 82 }, { 330, 11, 30 }, + { 336, 4, 84 }, { 340, 5, 68 }, { 342, 9, 38 }, + { 344, 4, 86 }, { 348, 6, 58 }, { 350, 5, 70 }, + { 352, 11, 32 }, { 360, 4, 90 }, { 364, 7, 52 }, + { 368, 4, 92 }, { 370, 5, 74 }, { 372, 6, 62 }, + { 374, 11, 34 }, { 376, 4, 94 }, { 378, 7, 54 }, + { 380, 5, 76 }, { 384, 4, 96 }, { 390, 5, 78 }, + { 392, 4, 98 }, { 396, 11, 36 }, { 400, 4, 100 }, + { 406, 7, 58 }, { 408, 4, 102 }, { 410, 5, 82 }, + { 414, 9, 46 }, { 416, 4, 104 }, { 418, 11, 38 }, + { 420, 5, 84 }, { 424, 4, 106 }, { 430, 5, 86 }, + { 432, 4, 108 }, { 434, 7, 62 }, { 440, 11, 40 }, + { 444, 6, 74 }, { 448, 4, 112 }, { 450, 5, 90 }, + { 456, 4, 114 }, { 460, 5, 92 }, { 462, 11, 42 }, + { 464, 4, 116 }, { 468, 6, 78 }, { 470, 5, 94 }, + { 472, 4, 118 }, { 476, 7, 68 }, { 480, 4, 120 }, + { 484, 11, 44 }, { 486, 9, 54 }, { 488, 4, 122 }, + { 490, 5, 98 }, { 492, 6, 82 }, { 496, 4, 124 }, + { 500, 5, 100 }, { 504, 4, 126 }, { 506, 11, 46 }, + { 510, 5, 102 }, { 512, 4, 128 }, { 516, 6, 86 }, + { 518, 7, 74 }, { 520, 5, 104 }, { 522, 9, 58 }, + { 528, 11, 48 }, { 530, 5, 106 }, { 532, 7, 76 }, + { 540, 5, 108 }, { 546, 7, 78 }, { 550, 11, 50 }, + { 552, 6, 92 }, { 558, 9, 62 }, { 560, 5, 112 }, + { 564, 6, 94 }, { 570, 5, 114 }, { 572, 11, 52 }, + { 574, 7, 82 }, { 576, 6, 96 }, { 580, 5, 116 }, + { 588, 6, 98 }, { 590, 5, 118 }, { 594, 11, 54 }, + { 600, 5, 120 }, { 602, 7, 86 }, { 610, 5, 122 }, + { 612, 6, 102 }, { 616, 11, 56 }, { 620, 5, 124 }, + { 624, 6, 104 }, { 630, 5, 126 }, { 636, 6, 106 }, + { 638, 11, 58 }, { 640, 5, 128 }, { 644, 7, 92 }, + { 648, 6, 108 }, { 658, 7, 94 }, { 660, 11, 60 }, + { 666, 9, 74 }, { 672, 6, 112 }, { 682, 11, 62 }, + { 684, 6, 114 }, { 686, 7, 98 }, { 696, 6, 116 }, + { 700, 7, 100 }, { 702, 9, 78 }, { 704, 11, 64 }, + { 708, 6, 118 }, { 714, 7, 102 }, { 720, 6, 120 }, + { 726, 11, 66 }, { 728, 7, 104 }, { 732, 6, 122 }, + { 738, 9, 82 }, { 742, 7, 106 }, { 744, 6, 124 }, + { 748, 11, 68 }, { 756, 6, 126 }, { 768, 6, 128 }, + { 770, 11, 70 }, { 774, 9, 86 }, { 784, 7, 112 }, + { 792, 11, 72 }, { 798, 7, 114 }, { 810, 9, 90 }, + { 812, 7, 116 }, { 814, 11, 74 }, { 826, 7, 118 }, + { 828, 9, 92 }, { 836, 11, 76 }, { 840, 7, 120 }, + { 846, 9, 94 }, { 854, 7, 122 }, { 858, 11, 78 }, + { 864, 9, 96 }, { 868, 7, 124 }, { 880, 11, 80 }, + { 882, 7, 126 }, { 896, 7, 128 }, { 900, 9, 100 }, + { 902, 11, 82 }, { 918, 9, 102 }, { 924, 11, 84 }, + { 936, 9, 104 }, { 946, 11, 86 }, { 954, 9, 106 }, + { 968, 11, 88 }, { 972, 9, 108 }, { 990, 11, 90 }, + { 1008, 9, 112 }, { 1012, 11, 92 }, { 1026, 9, 114 }, + { 1034, 11, 94 }, { 1044, 9, 116 }, { 1056, 11, 96 }, + { 1062, 9, 118 }, { 1078, 11, 98 }, { 1080, 9, 120 }, + { 1098, 9, 122 }, { 1100, 11, 100 }, { 1116, 9, 124 }, + { 1122, 11, 102 }, { 1134, 9, 126 }, { 1144, 11, 104 }, + { 1152, 9, 128 }, { 1166, 11, 106 }, { 1188, 11, 108 }, + { 1210, 11, 110 }, { 1232, 11, 112 }, { 1254, 11, 114 }, + { 1276, 11, 116 }, { 1298, 11, 118 }, { 1320, 11, 120 }, + { 1342, 11, 122 }, { 1364, 11, 124 }, { 1386, 11, 126 }, + { 1408, 11, 128 }, +}; + +bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned f_out) +{ + const unsigned f_xtal = 39170000; /* xtal for si598 */ + u64 dco; + u64 rfreq; + unsigned delta = 0xffffffff; + unsigned i_best = 0; + unsigned i; + u8 n1, hsdiv; + u8 regs[6]; + int found = 0; + u16 clock_ctrl; + int retries = 3; + + for (i = 0; i < ARRAY_SIZE(multipliers); i++) { + unsigned mult = multipliers[i].mult; + u32 d; + + dco = (u64)f_out * mult; + if (dco < DCO_MIN || dco > DCO_MAX) + continue; + div_u64_rem((dco << 28) + f_xtal / 2, f_xtal, &d); + if (d < delta) { + found = 1; + i_best = i; + delta = d; + } + } + if (!found) + return false; + dco = (u64)f_out * multipliers[i_best].mult; + n1 = multipliers[i_best].n1 - 1; + hsdiv = multipliers[i_best].hsdiv - 4; + rfreq = div_u64(dco << 28, f_xtal); + + clock_ctrl = cpld_read(cobalt, SI570_CLOCK_CTRL); + clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL; + clock_ctrl |= S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN; + + regs[0] = (hsdiv << 5) | (n1 >> 2); + regs[1] = ((n1 & 0x3) << 6) | (rfreq >> 32); + regs[2] = (rfreq >> 24) & 0xff; + regs[3] = (rfreq >> 16) & 0xff; + regs[4] = (rfreq >> 8) & 0xff; + regs[5] = rfreq & 0xff; + + /* The sequence of clock_ctrl flags to set is very weird. It looks + like I have to reset it, then set the new frequency and reset it + again. It shouldn't be necessary to do a reset, but if I don't, + then a strange frequency is set (156.412034 MHz, or register values + 0x01, 0xc7, 0xfc, 0x7f, 0x53, 0x62). + */ + + cobalt_dbg(1, "%u: %02x %02x %02x %02x %02x %02x\n", f_out, + regs[0], regs[1], regs[2], regs[3], regs[4], regs[5]); + while (retries--) { + u8 read_regs[6]; + + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_REG7, regs[0]); + cpld_write(cobalt, SI570_REG8, regs[1]); + cpld_write(cobalt, SI570_REG9, regs[2]); + cpld_write(cobalt, SI570_REG10, regs[3]); + cpld_write(cobalt, SI570_REG11, regs[4]); + cpld_write(cobalt, SI570_REG12, regs[5]); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_WR_TRIGGER); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL); + usleep_range(10000, 15000); + read_regs[0] = cpld_read(cobalt, SI570_REG7); + read_regs[1] = cpld_read(cobalt, SI570_REG8); + read_regs[2] = cpld_read(cobalt, SI570_REG9); + read_regs[3] = cpld_read(cobalt, SI570_REG10); + read_regs[4] = cpld_read(cobalt, SI570_REG11); + read_regs[5] = cpld_read(cobalt, SI570_REG12); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_FPGA_CTRL | + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_RST_TRIGGER); + usleep_range(10000, 15000); + cpld_write(cobalt, SI570_CLOCK_CTRL, + S01755_REG_CLOCK_CTRL_BITMAP_CLKHSMA_EN); + usleep_range(10000, 15000); + + if (!memcmp(read_regs, regs, sizeof(read_regs))) + break; + cobalt_dbg(1, "retry: %02x %02x %02x %02x %02x %02x\n", + read_regs[0], read_regs[1], read_regs[2], + read_regs[3], read_regs[4], read_regs[5]); + } + if (2 - retries) + cobalt_info("Needed %d retries\n", 2 - retries); + + return true; +} diff --git a/drivers/media/pci/cobalt/cobalt-cpld.h b/drivers/media/pci/cobalt/cobalt-cpld.h new file mode 100644 index 000000000..0fc88fd5f --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-cpld.h @@ -0,0 +1,29 @@ +/* + * Cobalt CPLD functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_CPLD_H +#define COBALT_CPLD_H + +#include "cobalt-driver.h" + +void cobalt_cpld_status(struct cobalt *cobalt); +bool cobalt_cpld_set_freq(struct cobalt *cobalt, unsigned freq); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c new file mode 100644 index 000000000..b994b8efd --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -0,0 +1,832 @@ +/* + * cobalt driver initialization and card probing + * + * Derived from cx18-driver.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/delay.h> +#include <media/adv7604.h> +#include <media/adv7842.h> +#include <media/adv7511.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ctrls.h> + +#include "cobalt-driver.h" +#include "cobalt-irq.h" +#include "cobalt-i2c.h" +#include "cobalt-v4l2.h" +#include "cobalt-flash.h" +#include "cobalt-alsa.h" +#include "cobalt-omnitek.h" + +/* add your revision and whatnot here */ +static struct pci_device_id cobalt_pci_tbl[] = { + {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl); + +static atomic_t cobalt_instance = ATOMIC_INIT(0); + +int cobalt_debug; +module_param_named(debug, cobalt_debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level. Default: 0\n"); + +int cobalt_ignore_err; +module_param_named(ignore_err, cobalt_ignore_err, int, 0644); +MODULE_PARM_DESC(ignore_err, + "If set then ignore missing i2c adapters/receivers. Default: 0\n"); + +MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes"); +MODULE_DESCRIPTION("cobalt driver"); +MODULE_LICENSE("GPL"); + +static u8 edid[256] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x50, 0x21, 0x9C, 0x27, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x12, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78, + 0x0E, 0x00, 0xB2, 0xA0, 0x57, 0x49, 0x9B, 0x26, + 0x10, 0x48, 0x4F, 0x2F, 0xCF, 0x00, 0x31, 0x59, + 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A, + 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, + 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x31, 0x55, 0x18, + 0x5E, 0x11, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x43, + 0x20, 0x39, 0x30, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0A, 0x0A, 0x0A, 0x0A, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, + 0x02, 0x03, 0x1a, 0xc0, 0x48, 0xa2, 0x10, 0x04, + 0x02, 0x01, 0x21, 0x14, 0x13, 0x23, 0x09, 0x07, + 0x07, 0x65, 0x03, 0x0c, 0x00, 0x10, 0x00, 0xe2, + 0x00, 0x2a, 0x01, 0x1d, 0x00, 0x80, 0x51, 0xd0, + 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1e, 0x8c, 0x0a, 0xd0, 0x8a, + 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7 +}; + +static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) +{ + if (enable) { + unsigned irqs = COBALT_SYSSTAT_VI0_INT1_MSK | + COBALT_SYSSTAT_VI1_INT1_MSK | + COBALT_SYSSTAT_VI2_INT1_MSK | + COBALT_SYSSTAT_VI3_INT1_MSK | + COBALT_SYSSTAT_VI0_INT2_MSK | + COBALT_SYSSTAT_VI1_INT2_MSK | + COBALT_SYSSTAT_VI2_INT2_MSK | + COBALT_SYSSTAT_VI3_INT2_MSK | + COBALT_SYSSTAT_VI0_LOST_DATA_MSK | + COBALT_SYSSTAT_VI1_LOST_DATA_MSK | + COBALT_SYSSTAT_VI2_LOST_DATA_MSK | + COBALT_SYSSTAT_VI3_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; + + if (cobalt->have_hsma_rx) + irqs |= COBALT_SYSSTAT_VIHSMA_INT1_MSK | + COBALT_SYSSTAT_VIHSMA_INT2_MSK | + COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK; + + if (cobalt->have_hsma_tx) + irqs |= COBALT_SYSSTAT_VOHSMA_INT1_MSK | + COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; + /* Clear any existing interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, 0xffffffff); + /* PIO Core interrupt mask register. + Enable ADV7604 INT1 interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, irqs); + } else { + /* Disable all ADV7604 interrupts */ + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, 0); + } +} + +static unsigned cobalt_get_sd_nr(struct v4l2_subdev *sd) +{ + struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); + unsigned i; + + for (i = 0; i < COBALT_NUM_NODES; i++) + if (sd == cobalt->streams[i].sd) + return i; + cobalt_err("Invalid adv7604 subdev pointer!\n"); + return 0; +} + +static void cobalt_notify(struct v4l2_subdev *sd, + unsigned int notification, void *arg) +{ + struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); + unsigned sd_nr = cobalt_get_sd_nr(sd); + struct cobalt_stream *s = &cobalt->streams[sd_nr]; + bool hotplug = arg ? *((int *)arg) : false; + + if (s->is_output) + return; + + switch (notification) { + case ADV76XX_HOTPLUG: + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(sd_nr), hotplug); + cobalt_dbg(1, "Set hotplug for adv %d to %d\n", sd_nr, hotplug); + break; + case V4L2_DEVICE_NOTIFY_EVENT: + cobalt_dbg(1, "Format changed for adv %d\n", sd_nr); + v4l2_event_queue(&s->vdev, arg); + break; + default: + break; + } +} + +static int get_payload_size(u16 code) +{ + switch (code) { + case 0: return 128; + case 1: return 256; + case 2: return 512; + case 3: return 1024; + case 4: return 2048; + case 5: return 4096; + default: return 0; + } + return 0; +} + +static const char *get_link_speed(u16 stat) +{ + switch (stat & PCI_EXP_LNKSTA_CLS) { + case 1: return "2.5 Gbit/s"; + case 2: return "5 Gbit/s"; + case 3: return "10 Gbit/s"; + } + return "Unknown speed"; +} + +void cobalt_pcie_status_show(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev; + struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self; + int offset; + int bus_offset; + u32 capa; + u16 stat, ctrl; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + bus_offset = pci_find_capability(pci_bus_dev, PCI_CAP_ID_EXP); + + /* Device */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_DEVCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_DEVCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_DEVSTA, &stat); + cobalt_info("PCIe device capability 0x%08x: Max payload %d\n", + capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD)); + cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n", + ctrl, + get_payload_size((ctrl & PCI_EXP_DEVCTL_PAYLOAD) >> 5), + get_payload_size((ctrl & PCI_EXP_DEVCTL_READRQ) >> 12)); + cobalt_info("PCIe device status 0x%04x\n", stat); + + /* Link */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &stat); + cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", + capa, get_link_speed(capa), + (capa & PCI_EXP_LNKCAP_MLW) >> 4); + cobalt_info("PCIe link control 0x%04x\n", ctrl); + cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n", + stat, get_link_speed(stat), + (stat & PCI_EXP_LNKSTA_NLW) >> 4); + + /* Bus */ + pci_read_config_dword(pci_bus_dev, bus_offset + PCI_EXP_LNKCAP, &capa); + cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", + capa, get_link_speed(capa), + (capa & PCI_EXP_LNKCAP_MLW) >> 4); + + /* Slot */ + pci_read_config_dword(pci_dev, offset + PCI_EXP_SLTCAP, &capa); + pci_read_config_word(pci_dev, offset + PCI_EXP_SLTCTL, &ctrl); + pci_read_config_word(pci_dev, offset + PCI_EXP_SLTSTA, &stat); + cobalt_info("PCIe slot capability 0x%08x\n", capa); + cobalt_info("PCIe slot control 0x%04x\n", ctrl); + cobalt_info("PCIe slot status 0x%04x\n", stat); +} + +static unsigned pcie_link_get_lanes(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev; + unsigned offset; + u16 link; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + if (!offset) + return 0; + pci_read_config_word(pci_dev, offset + PCI_EXP_LNKSTA, &link); + return (link & PCI_EXP_LNKSTA_NLW) >> 4; +} + +static unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) +{ + struct pci_dev *pci_dev = cobalt->pci_dev->bus->self; + unsigned offset; + u32 link; + + offset = pci_find_capability(pci_dev, PCI_CAP_ID_EXP); + if (!offset) + return 0; + pci_read_config_dword(pci_dev, offset + PCI_EXP_LNKCAP, &link); + return (link & PCI_EXP_LNKCAP_MLW) >> 4; +} + +static void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + u16 ctrl, data; + u32 adrs_l, adrs_h; + + pci_read_config_word(pci_dev, 0x52, &ctrl); + cobalt_info("MSI %s\n", ctrl & 1 ? "enable" : "disable"); + cobalt_info("MSI multiple message: Capable %u. Enable %u\n", + (1 << ((ctrl >> 1) & 7)), (1 << ((ctrl >> 4) & 7))); + if (ctrl & 0x80) + cobalt_info("MSI: 64-bit address capable\n"); + pci_read_config_dword(pci_dev, 0x54, &adrs_l); + pci_read_config_dword(pci_dev, 0x58, &adrs_h); + pci_read_config_word(pci_dev, 0x5c, &data); + if (ctrl & 0x80) + cobalt_info("MSI: Address 0x%08x%08x. Data 0x%04x\n", + adrs_h, adrs_l, data); + else + cobalt_info("MSI: Address 0x%08x. Data 0x%04x\n", + adrs_l, data); +} + +static void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + if (cobalt->bar0) { + pci_iounmap(pci_dev, cobalt->bar0); + cobalt->bar0 = NULL; + } + if (cobalt->bar1) { + pci_iounmap(pci_dev, cobalt->bar1); + cobalt->bar1 = NULL; + } +} + +static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev) +{ + free_irq(pci_dev->irq, (void *)cobalt); + + if (cobalt->msi_enabled) + pci_disable_msi(pci_dev); +} + +static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + u32 ctrl; + int ret; + + cobalt_dbg(1, "enabling pci device\n"); + + ret = pci_enable_device(pci_dev); + if (ret) { + cobalt_err("can't enable device\n"); + return ret; + } + pci_set_master(pci_dev); + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cobalt->card_rev); + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &cobalt->device_id); + + switch (cobalt->device_id) { + case PCI_DEVICE_ID_COBALT: + cobalt_info("PCI Express interface from Omnitek\n"); + break; + default: + cobalt_info("PCI Express interface provider is unknown!\n"); + break; + } + + if (pcie_link_get_lanes(cobalt) != 8) { + cobalt_err("PCI Express link width is not 8 lanes (%d)\n", + pcie_link_get_lanes(cobalt)); + if (pcie_bus_link_get_lanes(cobalt) < 8) + cobalt_err("The current slot only supports %d lanes, at least 8 are needed\n", + pcie_bus_link_get_lanes(cobalt)); + else + cobalt_err("The card is most likely not seated correctly in the PCIe slot\n"); + ret = -EIO; + goto err_disable; + } + + if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) { + ret = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + if (ret) { + cobalt_err("no suitable DMA available\n"); + goto err_disable; + } + } + + ret = pci_request_regions(pci_dev, "cobalt"); + if (ret) { + cobalt_err("error requesting regions\n"); + goto err_disable; + } + + cobalt_pcie_status_show(cobalt); + + cobalt->bar0 = pci_iomap(pci_dev, 0, 0); + cobalt->bar1 = pci_iomap(pci_dev, 1, 0); + if (cobalt->bar1 == NULL) { + cobalt->bar1 = pci_iomap(pci_dev, 2, 0); + cobalt_info("64-bit BAR\n"); + } + if (!cobalt->bar0 || !cobalt->bar1) { + ret = -EIO; + goto err_release; + } + + /* Reset the video inputs before enabling any interrupts */ + ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); + cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, ctrl & ~0xf00); + + /* Disable interrupts to prevent any spurious interrupts + from being generated. */ + cobalt_set_interrupt(cobalt, false); + + if (pci_enable_msi_range(pci_dev, 1, 1) < 1) { + cobalt_err("Could not enable MSI\n"); + cobalt->msi_enabled = false; + ret = -EIO; + goto err_release; + } + msi_config_show(cobalt, pci_dev); + cobalt->msi_enabled = true; + + /* Register IRQ */ + if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED, + cobalt->v4l2_dev.name, (void *)cobalt)) { + cobalt_err("Failed to register irq %d\n", pci_dev->irq); + ret = -EIO; + goto err_msi; + } + + omni_sg_dma_init(cobalt); + return 0; + +err_msi: + pci_disable_msi(pci_dev); + +err_release: + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(pci_dev); + +err_disable: + pci_disable_device(cobalt->pci_dev); + return ret; +} + +static int cobalt_hdl_info_get(struct cobalt *cobalt) +{ + int i; + + for (i = 0; i < COBALT_HDL_INFO_SIZE; i++) + cobalt->hdl_info[i] = + ioread8(cobalt->bar1 + COBALT_HDL_INFO_BASE + i); + cobalt->hdl_info[COBALT_HDL_INFO_SIZE - 1] = '\0'; + if (strstr(cobalt->hdl_info, COBALT_HDL_SEARCH_STR)) + return 0; + + return 1; +} + +static void cobalt_stream_struct_init(struct cobalt *cobalt) +{ + int i; + + for (i = 0; i < COBALT_NUM_STREAMS; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + + s->cobalt = cobalt; + s->flags = 0; + s->is_audio = false; + s->is_output = false; + s->is_dummy = true; + + /* The Memory DMA channels will always get a lower channel + * number than the FIFO DMA. Video input should map to the + * stream 0-3. The other can use stream struct from 4 and + * higher */ + if (i <= COBALT_HSMA_IN_NODE) { + s->dma_channel = i + cobalt->first_fifo_channel; + s->video_channel = i; + s->dma_fifo_mask = + COBALT_SYSSTAT_VI0_LOST_DATA_MSK << (4 * i); + s->adv_irq_mask = + COBALT_SYSSTAT_VI0_INT1_MSK << (4 * i); + } else if (i >= COBALT_AUDIO_IN_STREAM && + i <= COBALT_AUDIO_IN_STREAM + 4) { + unsigned idx = i - COBALT_AUDIO_IN_STREAM; + + s->dma_channel = 6 + idx; + s->is_audio = true; + s->video_channel = idx; + s->dma_fifo_mask = COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; + } else if (i == COBALT_HSMA_OUT_NODE) { + s->dma_channel = 11; + s->is_output = true; + s->video_channel = 5; + s->dma_fifo_mask = COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK; + s->adv_irq_mask = COBALT_SYSSTAT_VOHSMA_INT1_MSK; + } else if (i == COBALT_AUDIO_OUT_STREAM) { + s->dma_channel = 12; + s->is_audio = true; + s->is_output = true; + s->video_channel = 5; + s->dma_fifo_mask = COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; + } else { + /* FIXME: Memory DMA for debug purpose */ + s->dma_channel = i - COBALT_NUM_NODES; + } + cobalt_info("stream #%d -> dma channel #%d <- video channel %d\n", + i, s->dma_channel, s->video_channel); + } +} + +static int cobalt_subdevs_init(struct cobalt *cobalt) +{ + static struct adv76xx_platform_data adv7604_pdata = { + .disable_pwrdnb = 1, + .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, + .bus_order = ADV7604_BUS_ORDER_BRG, + .blank_data = 1, + .op_656_range = 1, + .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, + .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, + .dr_str_data = ADV76XX_DR_STR_HIGH, + .dr_str_clk = ADV76XX_DR_STR_HIGH, + .dr_str_sync = ADV76XX_DR_STR_HIGH, + .hdmi_free_run_mode = 1, + .inv_vs_pol = 1, + .inv_hs_pol = 1, + }; + static struct i2c_board_info adv7604_info = { + .type = "adv7604", + .addr = 0x20, + .platform_data = &adv7604_pdata, + }; + + struct cobalt_stream *s = cobalt->streams; + int i; + + for (i = 0; i < COBALT_NUM_INPUTS; i++) { + struct v4l2_subdev_format sd_fmt = { + .pad = ADV7604_PAD_SOURCE, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + struct v4l2_subdev_edid cobalt_edid = { + .pad = ADV76XX_PAD_HDMI_PORT_A, + .start_block = 0, + .blocks = 2, + .edid = edid, + }; + int err; + + s[i].pad_source = ADV7604_PAD_SOURCE; + s[i].i2c_adap = &cobalt->i2c_adap[i]; + if (s[i].i2c_adap->dev.parent == NULL) + continue; + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(i), 1); + s[i].sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s[i].i2c_adap, &adv7604_info, NULL); + if (!s[i].sd) { + if (cobalt_ignore_err) + continue; + return -ENODEV; + } + err = v4l2_subdev_call(s[i].sd, video, s_routing, + ADV76XX_PAD_HDMI_PORT_A, 0, 0); + if (err) + return err; + err = v4l2_subdev_call(s[i].sd, pad, set_edid, + &cobalt_edid); + if (err) + return err; + err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL, + &sd_fmt); + if (err) + return err; + /* Reset channel video module */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 1); + mdelay(1); + s[i].is_dummy = false; + cobalt->streams[i + COBALT_AUDIO_IN_STREAM].is_dummy = false; + } + return 0; +} + +static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) +{ + static struct adv7842_platform_data adv7842_pdata = { + .disable_pwrdnb = 1, + .ain_sel = ADV7842_AIN1_2_3_NC_SYNC_1_2, + .bus_order = ADV7842_BUS_ORDER_RBG, + .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, + .blank_data = 1, + .op_656_range = 1, + .dr_str_data = 3, + .dr_str_clk = 3, + .dr_str_sync = 3, + .mode = ADV7842_MODE_HDMI, + .hdmi_free_run_enable = 1, + .vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P, + .i2c_sdp_io = 0x4a, + .i2c_sdp = 0x48, + .i2c_cp = 0x22, + .i2c_vdp = 0x24, + .i2c_afe = 0x26, + .i2c_hdmi = 0x34, + .i2c_repeater = 0x32, + .i2c_edid = 0x36, + .i2c_infoframe = 0x3e, + .i2c_cec = 0x40, + .i2c_avlink = 0x42, + }; + static struct i2c_board_info adv7842_info = { + .type = "adv7842", + .addr = 0x20, + .platform_data = &adv7842_pdata, + }; + static struct v4l2_subdev_format sd_fmt = { + .pad = ADV7842_PAD_SOURCE, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + static struct adv7511_platform_data adv7511_pdata = { + .i2c_edid = 0x7e >> 1, + .i2c_cec = 0x7c >> 1, + .i2c_pktmem = 0x70 >> 1, + .cec_clk = 12000000, + }; + static struct i2c_board_info adv7511_info = { + .type = "adv7511", + .addr = 0x39, /* 0x39 or 0x3d */ + .platform_data = &adv7511_pdata, + }; + struct v4l2_subdev_edid cobalt_edid = { + .pad = ADV7842_EDID_PORT_A, + .start_block = 0, + .blocks = 2, + .edid = edid, + }; + struct cobalt_stream *s = &cobalt->streams[COBALT_HSMA_IN_NODE]; + + s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; + if (s->i2c_adap->dev.parent == NULL) + return 0; + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 1); + + s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s->i2c_adap, &adv7842_info, NULL); + if (s->sd) { + int err = v4l2_subdev_call(s->sd, pad, set_edid, &cobalt_edid); + + if (err) + return err; + err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt); + if (err) + return err; + cobalt->have_hsma_rx = true; + s->pad_source = ADV7842_PAD_SOURCE; + s->is_dummy = false; + cobalt->streams[4 + COBALT_AUDIO_IN_STREAM].is_dummy = false; + /* Reset channel video module */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); + mdelay(2); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 1); + mdelay(1); + return err; + } + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 0); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT, 0); + s++; + s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; + s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, + s->i2c_adap, &adv7511_info, NULL); + if (s->sd) { + /* A transmitter is hooked up, so we can set this bit */ + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 1); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); + cobalt_s_bit_sysctrl(cobalt, + COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT, 1); + cobalt->have_hsma_tx = true; + v4l2_subdev_call(s->sd, core, s_power, 1); + v4l2_subdev_call(s->sd, video, s_stream, 1); + v4l2_subdev_call(s->sd, audio, s_stream, 1); + v4l2_ctrl_s_ctrl(v4l2_ctrl_find(s->sd->ctrl_handler, + V4L2_CID_DV_TX_MODE), V4L2_DV_TX_MODE_HDMI); + s->is_dummy = false; + cobalt->streams[COBALT_AUDIO_OUT_STREAM].is_dummy = false; + return 0; + } + return -ENODEV; +} + +static int cobalt_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) +{ + struct cobalt *cobalt; + int retval = 0; + int i; + + /* FIXME - module parameter arrays constrain max instances */ + i = atomic_inc_return(&cobalt_instance) - 1; + + cobalt = kzalloc(sizeof(struct cobalt), GFP_ATOMIC); + if (cobalt == NULL) + return -ENOMEM; + cobalt->pci_dev = pci_dev; + cobalt->instance = i; + + cobalt->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev); + if (IS_ERR(cobalt->alloc_ctx)) { + kfree(cobalt); + return -ENOMEM; + } + + retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); + if (retval) { + pr_err("cobalt: v4l2_device_register of card %d failed\n", + cobalt->instance); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); + return retval; + } + snprintf(cobalt->v4l2_dev.name, sizeof(cobalt->v4l2_dev.name), + "cobalt-%d", cobalt->instance); + cobalt->v4l2_dev.notify = cobalt_notify; + cobalt_info("Initializing card %d\n", cobalt->instance); + + cobalt->irq_work_queues = + create_singlethread_workqueue(cobalt->v4l2_dev.name); + if (cobalt->irq_work_queues == NULL) { + cobalt_err("Could not create workqueue\n"); + retval = -ENOMEM; + goto err; + } + + INIT_WORK(&cobalt->irq_work_queue, cobalt_irq_work_handler); + + /* PCI Device Setup */ + retval = cobalt_setup_pci(cobalt, pci_dev, pci_id); + if (retval != 0) + goto err_wq; + + /* Show HDL version info */ + if (cobalt_hdl_info_get(cobalt)) + cobalt_info("Not able to read the HDL info\n"); + else + cobalt_info("%s", cobalt->hdl_info); + + retval = cobalt_i2c_init(cobalt); + if (retval) + goto err_pci; + + cobalt_stream_struct_init(cobalt); + + retval = cobalt_subdevs_init(cobalt); + if (retval) + goto err_i2c; + + if (!(cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE) & + COBALT_SYSSTAT_HSMA_PRSNTN_MSK)) { + retval = cobalt_subdevs_hsma_init(cobalt); + if (retval) + goto err_i2c; + } + + retval = v4l2_device_register_subdev_nodes(&cobalt->v4l2_dev); + if (retval) + goto err_i2c; + retval = cobalt_nodes_register(cobalt); + if (retval) { + cobalt_err("Error %d registering device nodes\n", retval); + goto err_i2c; + } + cobalt_set_interrupt(cobalt, true); + v4l2_device_call_all(&cobalt->v4l2_dev, 0, core, + interrupt_service_routine, 0, NULL); + + cobalt_info("Initialized cobalt card\n"); + + cobalt_flash_probe(cobalt); + + return 0; + +err_i2c: + cobalt_i2c_exit(cobalt); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); +err_pci: + cobalt_free_msi(cobalt, pci_dev); + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(cobalt->pci_dev); + pci_disable_device(cobalt->pci_dev); +err_wq: + destroy_workqueue(cobalt->irq_work_queues); +err: + if (retval == 0) + retval = -ENODEV; + cobalt_err("error %d on initialization\n", retval); + + v4l2_device_unregister(&cobalt->v4l2_dev); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); + return retval; +} + +static void cobalt_remove(struct pci_dev *pci_dev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); + struct cobalt *cobalt = to_cobalt(v4l2_dev); + int i; + + cobalt_flash_remove(cobalt); + cobalt_set_interrupt(cobalt, false); + flush_workqueue(cobalt->irq_work_queues); + cobalt_nodes_unregister(cobalt); + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + struct v4l2_subdev *sd = cobalt->streams[i].sd; + struct i2c_client *client; + + if (sd == NULL) + continue; + client = v4l2_get_subdevdata(sd); + v4l2_device_unregister_subdev(sd); + i2c_unregister_device(client); + } + cobalt_i2c_exit(cobalt); + cobalt_free_msi(cobalt, pci_dev); + cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); + cobalt_pci_iounmap(cobalt, pci_dev); + pci_release_regions(cobalt->pci_dev); + pci_disable_device(cobalt->pci_dev); + destroy_workqueue(cobalt->irq_work_queues); + + cobalt_info("removed cobalt card\n"); + + v4l2_device_unregister(v4l2_dev); + vb2_dma_sg_cleanup_ctx(cobalt->alloc_ctx); + kfree(cobalt); +} + +/* define a pci_driver for card detection */ +static struct pci_driver cobalt_pci_driver = { + .name = "cobalt", + .id_table = cobalt_pci_tbl, + .probe = cobalt_probe, + .remove = cobalt_remove, +}; + +module_pci_driver(cobalt_pci_driver); diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h new file mode 100644 index 000000000..c206df930 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -0,0 +1,380 @@ +/* + * cobalt driver internal defines and structures + * + * Derived from cx18-driver.h + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_DRIVER_H +#define COBALT_DRIVER_H + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fh.h> +#include <media/videobuf2-dma-sg.h> + +#include "m00233_video_measure_memmap_package.h" +#include "m00235_fdma_packer_memmap_package.h" +#include "m00389_cvi_memmap_package.h" +#include "m00460_evcnt_memmap_package.h" +#include "m00473_freewheel_memmap_package.h" +#include "m00479_clk_loss_detector_memmap_package.h" +#include "m00514_syncgen_flow_evcnt_memmap_package.h" + +/* System device ID */ +#define PCI_DEVICE_ID_COBALT 0x2732 + +/* Number of cobalt device nodes. */ +#define COBALT_NUM_INPUTS 4 +#define COBALT_NUM_NODES 6 + +/* Number of cobalt device streams. */ +#define COBALT_NUM_STREAMS 12 + +#define COBALT_HSMA_IN_NODE 4 +#define COBALT_HSMA_OUT_NODE 5 + +/* Cobalt audio streams */ +#define COBALT_AUDIO_IN_STREAM 6 +#define COBALT_AUDIO_OUT_STREAM 11 + +/* DMA stuff */ +#define DMA_CHANNELS_MAX 16 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 +#define COBALT_NUM_ADAPTERS 5 + +#define COBALT_CLK 50000000 + +/* System status register */ +#define COBALT_SYSSTAT_DIP0_MSK (1 << 0) +#define COBALT_SYSSTAT_DIP1_MSK (1 << 1) +#define COBALT_SYSSTAT_HSMA_PRSNTN_MSK (1 << 2) +#define COBALT_SYSSTAT_FLASH_RDYBSYN_MSK (1 << 3) +#define COBALT_SYSSTAT_VI0_5V_MSK (1 << 4) +#define COBALT_SYSSTAT_VI0_INT1_MSK (1 << 5) +#define COBALT_SYSSTAT_VI0_INT2_MSK (1 << 6) +#define COBALT_SYSSTAT_VI0_LOST_DATA_MSK (1 << 7) +#define COBALT_SYSSTAT_VI1_5V_MSK (1 << 8) +#define COBALT_SYSSTAT_VI1_INT1_MSK (1 << 9) +#define COBALT_SYSSTAT_VI1_INT2_MSK (1 << 10) +#define COBALT_SYSSTAT_VI1_LOST_DATA_MSK (1 << 11) +#define COBALT_SYSSTAT_VI2_5V_MSK (1 << 12) +#define COBALT_SYSSTAT_VI2_INT1_MSK (1 << 13) +#define COBALT_SYSSTAT_VI2_INT2_MSK (1 << 14) +#define COBALT_SYSSTAT_VI2_LOST_DATA_MSK (1 << 15) +#define COBALT_SYSSTAT_VI3_5V_MSK (1 << 16) +#define COBALT_SYSSTAT_VI3_INT1_MSK (1 << 17) +#define COBALT_SYSSTAT_VI3_INT2_MSK (1 << 18) +#define COBALT_SYSSTAT_VI3_LOST_DATA_MSK (1 << 19) +#define COBALT_SYSSTAT_VIHSMA_5V_MSK (1 << 20) +#define COBALT_SYSSTAT_VIHSMA_INT1_MSK (1 << 21) +#define COBALT_SYSSTAT_VIHSMA_INT2_MSK (1 << 22) +#define COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK (1 << 23) +#define COBALT_SYSSTAT_VOHSMA_INT1_MSK (1 << 24) +#define COBALT_SYSSTAT_VOHSMA_PLL_LOCKED_MSK (1 << 25) +#define COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK (1 << 26) +#define COBALT_SYSSTAT_AUD_PLL_LOCKED_MSK (1 << 28) +#define COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK (1 << 29) +#define COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK (1 << 30) +#define COBALT_SYSSTAT_PCIE_SMBCLK_MSK (1 << 31) + +/* Cobalt memory map */ +#define COBALT_I2C_0_BASE 0x0 +#define COBALT_I2C_1_BASE 0x080 +#define COBALT_I2C_2_BASE 0x100 +#define COBALT_I2C_3_BASE 0x180 +#define COBALT_I2C_HSMA_BASE 0x200 + +#define COBALT_SYS_CTRL_BASE 0x400 +#define COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT 1 +#define COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(n) (4 + 4 * (n)) +#define COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(n) (5 + 4 * (n)) +#define COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(n) (6 + 4 * (n)) +#define COBALT_SYS_CTRL_AUDIO_IPP_RESETN_BIT(n) (7 + 4 * (n)) +#define COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT 24 +#define COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT 25 +#define COBALT_SYS_CTRL_AUDIO_OPP_RESETN_BIT 27 + +#define COBALT_SYS_STAT_BASE 0x500 +#define COBALT_SYS_STAT_MASK (COBALT_SYS_STAT_BASE + 0x08) +#define COBALT_SYS_STAT_EDGE (COBALT_SYS_STAT_BASE + 0x0c) + +#define COBALT_HDL_INFO_BASE 0x4800 +#define COBALT_HDL_INFO_SIZE 0x200 + +#define COBALT_VID_BASE 0x10000 +#define COBALT_VID_SIZE 0x1000 + +#define COBALT_CVI(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE) +#define COBALT_CVI_VMR(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x100) +#define COBALT_CVI_EVCNT(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x200) +#define COBALT_CVI_FREEWHEEL(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x300) +#define COBALT_CVI_CLK_LOSS(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x400) +#define COBALT_CVI_PACKER(cobalt, c) \ + (cobalt->bar1 + COBALT_VID_BASE + (c) * COBALT_VID_SIZE + 0x500) + +#define COBALT_TX_BASE(cobalt) (cobalt->bar1 + COBALT_VID_BASE + 0x5000) + +#define DMA_INTERRUPT_STATUS_REG 0x08 + +#define COBALT_HDL_SEARCH_STR "** HDL version info **" + +/* Cobalt CPU bus interface */ +#define COBALT_BUS_BAR1_BASE 0x600 +#define COBALT_BUS_SRAM_BASE 0x0 +#define COBALT_BUS_CPLD_BASE 0x00600000 +#define COBALT_BUS_FLASH_BASE 0x08000000 + +/* FDMA to PCIe packing */ +#define COBALT_BYTES_PER_PIXEL_YUYV 2 +#define COBALT_BYTES_PER_PIXEL_RGB24 3 +#define COBALT_BYTES_PER_PIXEL_RGB32 4 + +/* debugging */ +extern int cobalt_debug; +extern int cobalt_ignore_err; + +#define cobalt_err(fmt, arg...) v4l2_err(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_warn(fmt, arg...) v4l2_warn(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_info(fmt, arg...) v4l2_info(&cobalt->v4l2_dev, fmt, ## arg) +#define cobalt_dbg(level, fmt, arg...) \ + v4l2_dbg(level, cobalt_debug, &cobalt->v4l2_dev, fmt, ## arg) + +struct cobalt; +struct cobalt_i2c_regs; + +/* Per I2C bus private algo callback data */ +struct cobalt_i2c_data { + struct cobalt *cobalt; + struct cobalt_i2c_regs __iomem *regs; +}; + +struct pci_consistent_buffer { + void *virt; + dma_addr_t bus; + size_t bytes; +}; + +struct sg_dma_desc_info { + void *virt; + dma_addr_t bus; + unsigned size; + void *last_desc_virt; + struct device *dev; +}; + +#define COBALT_MAX_WIDTH 1920 +#define COBALT_MAX_HEIGHT 1200 +#define COBALT_MAX_BPP 3 +#define COBALT_MAX_FRAMESZ \ + (COBALT_MAX_WIDTH * COBALT_MAX_HEIGHT * COBALT_MAX_BPP) + +#define NR_BUFS VIDEO_MAX_FRAME + +#define COBALT_STREAM_FL_DMA_IRQ 0 +#define COBALT_STREAM_FL_ADV_IRQ 1 + +struct cobalt_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct cobalt_buffer *to_cobalt_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct cobalt_buffer, vb); +} + +struct cobalt_stream { + struct video_device vdev; + struct vb2_queue q; + struct list_head bufs; + struct i2c_adapter *i2c_adap; + struct v4l2_subdev *sd; + struct mutex lock; + spinlock_t irqlock; + struct v4l2_dv_timings timings; + u32 input; + u32 pad_source; + u32 width, height, bpp; + u32 stride; + u32 pixfmt; + u32 sequence; + u32 colorspace; + u32 xfer_func; + u32 ycbcr_enc; + u32 quantization; + + u8 dma_channel; + int video_channel; + unsigned dma_fifo_mask; + unsigned adv_irq_mask; + struct sg_dma_desc_info dma_desc_info[NR_BUFS]; + unsigned long flags; + bool unstable_frame; + bool enable_cvi; + bool enable_freewheel; + unsigned skip_first_frames; + bool is_output; + bool is_audio; + bool is_dummy; + + struct cobalt *cobalt; + struct snd_cobalt_card *alsa; +}; + +struct snd_cobalt_card; + +/* Struct to hold info about cobalt cards */ +struct cobalt { + int instance; + struct pci_dev *pci_dev; + struct v4l2_device v4l2_dev; + void *alloc_ctx; + + void __iomem *bar0, *bar1; + + u8 card_rev; + u16 device_id; + + /* device nodes */ + struct cobalt_stream streams[DMA_CHANNELS_MAX]; + struct i2c_adapter i2c_adap[COBALT_NUM_ADAPTERS]; + struct cobalt_i2c_data i2c_data[COBALT_NUM_ADAPTERS]; + bool have_hsma_rx; + bool have_hsma_tx; + + /* irq */ + struct workqueue_struct *irq_work_queues; + struct work_struct irq_work_queue; /* work entry */ + /* irq counters */ + u32 irq_adv1; + u32 irq_adv2; + u32 irq_advout; + u32 irq_dma_tot; + u32 irq_dma[COBALT_NUM_STREAMS]; + u32 irq_none; + u32 irq_full_fifo; + + bool msi_enabled; + + /* omnitek dma */ + int dma_channels; + int first_fifo_channel; + bool pci_32_bit; + + char hdl_info[COBALT_HDL_INFO_SIZE]; + + /* NOR flash */ + struct mtd_info *mtd; +}; + +static inline struct cobalt *to_cobalt(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct cobalt, v4l2_dev); +} + +static inline void cobalt_write_bar0(struct cobalt *cobalt, u32 reg, u32 val) +{ + iowrite32(val, cobalt->bar0 + reg); +} + +static inline u32 cobalt_read_bar0(struct cobalt *cobalt, u32 reg) +{ + return ioread32(cobalt->bar0 + reg); +} + +static inline void cobalt_write_bar1(struct cobalt *cobalt, u32 reg, u32 val) +{ + iowrite32(val, cobalt->bar1 + reg); +} + +static inline u32 cobalt_read_bar1(struct cobalt *cobalt, u32 reg) +{ + return ioread32(cobalt->bar1 + reg); +} + +static inline u32 cobalt_g_sysctrl(struct cobalt *cobalt) +{ + return cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); +} + +static inline void cobalt_s_bit_sysctrl(struct cobalt *cobalt, + int bit, int val) +{ + u32 ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); + + cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, + (ctrl & ~(1UL << bit)) | (val << bit)); +} + +static inline u32 cobalt_g_sysstat(struct cobalt *cobalt) +{ + return cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE); +} + +#define ADRS_REG (bar1 + COBALT_BUS_BAR1_BASE + 0) +#define LOWER_DATA (bar1 + COBALT_BUS_BAR1_BASE + 4) +#define UPPER_DATA (bar1 + COBALT_BUS_BAR1_BASE + 6) + +static inline u32 cobalt_bus_read32(void __iomem *bar1, u32 bus_adrs) +{ + iowrite32(bus_adrs, ADRS_REG); + return ioread32(LOWER_DATA); +} + +static inline void cobalt_bus_write16(void __iomem *bar1, + u32 bus_adrs, u16 data) +{ + iowrite32(bus_adrs, ADRS_REG); + if (bus_adrs & 2) + iowrite16(data, UPPER_DATA); + else + iowrite16(data, LOWER_DATA); +} + +static inline void cobalt_bus_write32(void __iomem *bar1, + u32 bus_adrs, u16 data) +{ + iowrite32(bus_adrs, ADRS_REG); + if (bus_adrs & 2) + iowrite32(data, UPPER_DATA); + else + iowrite32(data, LOWER_DATA); +} + +/*==============Prototypes==================*/ + +void cobalt_pcie_status_show(struct cobalt *cobalt); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-flash.c b/drivers/media/pci/cobalt/cobalt-flash.c new file mode 100644 index 000000000..04dcaf919 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-flash.c @@ -0,0 +1,128 @@ +/* + * Cobalt NOR flash functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/time.h> + +#include "cobalt-flash.h" + +#define ADRS(offset) (COBALT_BUS_FLASH_BASE + offset) + +static struct map_info cobalt_flash_map = { + .name = "cobalt-flash", + .bankwidth = 2, /* 16 bits */ + .size = 0x4000000, /* 64MB */ + .phys = 0, /* offset */ +}; + +static map_word flash_read16(struct map_info *map, unsigned long offset) +{ + map_word r; + + r.x[0] = cobalt_bus_read32(map->virt, ADRS(offset)); + if (offset & 0x2) + r.x[0] >>= 16; + else + r.x[0] &= 0x0000ffff; + + return r; +} + +static void flash_write16(struct map_info *map, const map_word datum, + unsigned long offset) +{ + u16 data = (u16)datum.x[0]; + + cobalt_bus_write16(map->virt, ADRS(offset), data); +} + +static void flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + u32 src = from; + u8 *dest = to; + u32 data; + + while (len) { + data = cobalt_bus_read32(map->virt, ADRS(src)); + do { + *dest = data >> (8 * (src & 3)); + src++; + dest++; + len--; + } while (len && (src % 4)); + } +} + +static void flash_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + const u8 *src = from; + u32 dest = to; + + pr_info("%s: offset 0x%x: length %zu\n", __func__, dest, len); + while (len) { + u16 data = 0xffff; + + do { + data = *src << (8 * (dest & 1)); + src++; + dest++; + len--; + } while (len && (dest % 2)); + + cobalt_bus_write16(map->virt, ADRS(dest - 2), data); + } +} + +int cobalt_flash_probe(struct cobalt *cobalt) +{ + struct map_info *map = &cobalt_flash_map; + struct mtd_info *mtd; + + BUG_ON(!map_bankwidth_supported(map->bankwidth)); + map->virt = cobalt->bar1; + map->read = flash_read16; + map->write = flash_write16; + map->copy_from = flash_copy_from; + map->copy_to = flash_copy_to; + + mtd = do_map_probe("cfi_probe", map); + cobalt->mtd = mtd; + if (!mtd) { + cobalt_err("Probe CFI flash failed!\n"); + return -1; + } + + mtd->owner = THIS_MODULE; + mtd->dev.parent = &cobalt->pci_dev->dev; + mtd_device_register(mtd, NULL, 0); + return 0; +} + +void cobalt_flash_remove(struct cobalt *cobalt) +{ + if (cobalt->mtd) { + mtd_device_unregister(cobalt->mtd); + map_destroy(cobalt->mtd); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-flash.h b/drivers/media/pci/cobalt/cobalt-flash.h new file mode 100644 index 000000000..8077daea5 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-flash.h @@ -0,0 +1,29 @@ +/* + * Cobalt NOR flash functions + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_FLASH_H +#define COBALT_FLASH_H + +#include "cobalt-driver.h" + +int cobalt_flash_probe(struct cobalt *cobalt); +void cobalt_flash_remove(struct cobalt *cobalt); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c new file mode 100644 index 000000000..ad16b89b8 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-i2c.c @@ -0,0 +1,396 @@ +/* + * cobalt I2C functions + * + * Derived from cx18-i2c.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "cobalt-driver.h" +#include "cobalt-i2c.h" + +struct cobalt_i2c_regs { + /* Clock prescaler register lo-byte */ + u8 prerlo; + u8 dummy0[3]; + /* Clock prescaler register high-byte */ + u8 prerhi; + u8 dummy1[3]; + /* Control register */ + u8 ctr; + u8 dummy2[3]; + /* Transmit/Receive register */ + u8 txr_rxr; + u8 dummy3[3]; + /* Command and Status register */ + u8 cr_sr; + u8 dummy4[3]; +}; + +/* CTR[7:0] - Control register */ + +/* I2C Core enable bit */ +#define M00018_CTR_BITMAP_EN_MSK (1 << 7) + +/* I2C Core interrupt enable bit */ +#define M00018_CTR_BITMAP_IEN_MSK (1 << 6) + +/* CR[7:0] - Command register */ + +/* I2C start condition */ +#define M00018_CR_BITMAP_STA_MSK (1 << 7) + +/* I2C stop condition */ +#define M00018_CR_BITMAP_STO_MSK (1 << 6) + +/* I2C read from slave */ +#define M00018_CR_BITMAP_RD_MSK (1 << 5) + +/* I2C write to slave */ +#define M00018_CR_BITMAP_WR_MSK (1 << 4) + +/* I2C ack */ +#define M00018_CR_BITMAP_ACK_MSK (1 << 3) + +/* I2C Interrupt ack */ +#define M00018_CR_BITMAP_IACK_MSK (1 << 0) + +/* SR[7:0] - Status register */ + +/* Receive acknowledge from slave */ +#define M00018_SR_BITMAP_RXACK_MSK (1 << 7) + +/* Busy, I2C bus busy (as defined by start / stop bits) */ +#define M00018_SR_BITMAP_BUSY_MSK (1 << 6) + +/* Arbitration lost - core lost arbitration */ +#define M00018_SR_BITMAP_AL_MSK (1 << 5) + +/* Transfer in progress */ +#define M00018_SR_BITMAP_TIP_MSK (1 << 1) + +/* Interrupt flag */ +#define M00018_SR_BITMAP_IF_MSK (1 << 0) + +/* Frequency, in Hz */ +#define I2C_FREQUENCY 400000 +#define ALT_CPU_FREQ 83333333 + +static struct cobalt_i2c_regs __iomem * +cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx) +{ + switch (idx) { + case 0: + default: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_0_BASE); + case 1: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_1_BASE); + case 2: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_2_BASE); + case 3: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_3_BASE); + case 4: + return (struct cobalt_i2c_regs __iomem *) + (cobalt->bar1 + COBALT_I2C_HSMA_BASE); + } +} + +/* Do low-level i2c byte transfer. + * Returns -1 in case of an error or 0 otherwise. + */ +static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap, bool start, bool stop, + u8 *data, u16 len) +{ + unsigned long start_time; + int status; + int cmd; + int i; + + for (i = 0; i < len; i++) { + /* Setup data */ + iowrite8(data[i], ®s->txr_rxr); + + /* Setup command */ + if (i == 0 && start != 0) { + /* Write + Start */ + cmd = M00018_CR_BITMAP_WR_MSK | + M00018_CR_BITMAP_STA_MSK; + } else if (i == len - 1 && stop != 0) { + /* Write + Stop */ + cmd = M00018_CR_BITMAP_WR_MSK | + M00018_CR_BITMAP_STO_MSK; + } else { + /* Write only */ + cmd = M00018_CR_BITMAP_WR_MSK; + } + + /* Execute command */ + iowrite8(cmd, ®s->cr_sr); + + /* Wait for transfer to complete (TIP = 0) */ + start_time = jiffies; + status = ioread8(®s->cr_sr); + while (status & M00018_SR_BITMAP_TIP_MSK) { + if (time_after(jiffies, start_time + adap->timeout)) + return -ETIMEDOUT; + cond_resched(); + status = ioread8(®s->cr_sr); + } + + /* Verify ACK */ + if (status & M00018_SR_BITMAP_RXACK_MSK) { + /* NO ACK! */ + return -EIO; + } + + /* Verify arbitration */ + if (status & M00018_SR_BITMAP_AL_MSK) { + /* Arbitration lost! */ + return -EIO; + } + } + return 0; +} + +/* Do low-level i2c byte read. + * Returns -1 in case of an error or 0 otherwise. + */ +static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap, bool start, bool stop, + u8 *data, u16 len) +{ + unsigned long start_time; + int status; + int cmd; + int i; + + for (i = 0; i < len; i++) { + /* Setup command */ + if (i == 0 && start != 0) { + /* Read + Start */ + cmd = M00018_CR_BITMAP_RD_MSK | + M00018_CR_BITMAP_STA_MSK; + } else if (i == len - 1 && stop != 0) { + /* Read + Stop */ + cmd = M00018_CR_BITMAP_RD_MSK | + M00018_CR_BITMAP_STO_MSK; + } else { + /* Read only */ + cmd = M00018_CR_BITMAP_RD_MSK; + } + + /* Last byte to read, no ACK */ + if (i == len - 1) + cmd |= M00018_CR_BITMAP_ACK_MSK; + + /* Execute command */ + iowrite8(cmd, ®s->cr_sr); + + /* Wait for transfer to complete (TIP = 0) */ + start_time = jiffies; + status = ioread8(®s->cr_sr); + while (status & M00018_SR_BITMAP_TIP_MSK) { + if (time_after(jiffies, start_time + adap->timeout)) + return -ETIMEDOUT; + cond_resched(); + status = ioread8(®s->cr_sr); + } + + /* Verify arbitration */ + if (status & M00018_SR_BITMAP_AL_MSK) { + /* Arbitration lost! */ + return -EIO; + } + + /* Store data */ + data[i] = ioread8(®s->txr_rxr); + } + return 0; +} + +/* Generate stop condition on i2c bus. + * The m00018 stop isn't doing the right thing (wrong timing). + * So instead send a start condition, 8 zeroes and a stop condition. + */ +static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs, + struct i2c_adapter *adap) +{ + u8 data = 0; + + return cobalt_tx_bytes(regs, adap, true, true, &data, 1); +} + +static int cobalt_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct cobalt_i2c_data *data = adap->algo_data; + struct cobalt_i2c_regs __iomem *regs = data->regs; + struct i2c_msg *pmsg; + unsigned short flags; + int ret = 0; + int i, j; + + for (i = 0; i < num; i++) { + int stop = (i == num - 1); + + pmsg = &msgs[i]; + flags = pmsg->flags; + + if (!(pmsg->flags & I2C_M_NOSTART)) { + u8 addr = pmsg->addr << 1; + + if (flags & I2C_M_RD) + addr |= 1; + if (flags & I2C_M_REV_DIR_ADDR) + addr ^= 1; + for (j = 0; j < adap->retries; j++) { + ret = cobalt_tx_bytes(regs, adap, true, false, + &addr, 1); + if (!ret) + break; + cobalt_stop(regs, adap); + } + if (ret < 0) + return ret; + ret = 0; + } + if (pmsg->flags & I2C_M_RD) { + /* read bytes into buffer */ + ret = cobalt_rx_bytes(regs, adap, false, stop, + pmsg->buf, pmsg->len); + if (ret < 0) + goto bailout; + } else { + /* write bytes from buffer */ + ret = cobalt_tx_bytes(regs, adap, false, stop, + pmsg->buf, pmsg->len); + if (ret < 0) + goto bailout; + } + } + ret = i; + +bailout: + if (ret < 0) + cobalt_stop(regs, adap); + return ret; +} + +static u32 cobalt_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cobalt_i2c_adap_template = { + .name = "cobalt i2c driver", + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .owner = THIS_MODULE, +}; + +static const struct i2c_algorithm cobalt_algo = { + .master_xfer = cobalt_xfer, + .functionality = cobalt_func, +}; + +/* init + register i2c algo-bit adapter */ +int cobalt_i2c_init(struct cobalt *cobalt) +{ + int i, err; + int status; + int prescale; + unsigned long start_time; + + cobalt_dbg(1, "i2c init\n"); + + /* Define I2C clock prescaler */ + prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1; + + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + struct cobalt_i2c_regs __iomem *regs = + cobalt_i2c_regs(cobalt, i); + struct i2c_adapter *adap = &cobalt->i2c_adap[i]; + + /* Disable I2C */ + iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->cr_sr); + iowrite8(0, ®s->ctr); + iowrite8(0, ®s->cr_sr); + + start_time = jiffies; + do { + if (time_after(jiffies, start_time + HZ)) { + if (cobalt_ignore_err) { + adap->dev.parent = NULL; + return 0; + } + return -ETIMEDOUT; + } + status = ioread8(®s->cr_sr); + } while (status & M00018_SR_BITMAP_TIP_MSK); + + /* Disable I2C */ + iowrite8(0, ®s->ctr); + iowrite8(0, ®s->cr_sr); + + /* Calculate i2c prescaler */ + iowrite8(prescale & 0xff, ®s->prerlo); + iowrite8((prescale >> 8) & 0xff, ®s->prerhi); + /* Enable I2C, interrupts disabled */ + iowrite8(M00018_CTR_BITMAP_EN_MSK, ®s->ctr); + /* Setup algorithm for adapter */ + cobalt->i2c_data[i].cobalt = cobalt; + cobalt->i2c_data[i].regs = regs; + *adap = cobalt_i2c_adap_template; + adap->algo = &cobalt_algo; + adap->algo_data = &cobalt->i2c_data[i]; + adap->retries = 3; + sprintf(adap->name + strlen(adap->name), + " #%d-%d", cobalt->instance, i); + i2c_set_adapdata(adap, &cobalt->v4l2_dev); + adap->dev.parent = &cobalt->pci_dev->dev; + err = i2c_add_adapter(adap); + if (err) { + if (cobalt_ignore_err) { + adap->dev.parent = NULL; + return 0; + } + while (i--) + i2c_del_adapter(&cobalt->i2c_adap[i]); + return err; + } + cobalt_info("registered bus %s\n", adap->name); + } + return 0; +} + +void cobalt_i2c_exit(struct cobalt *cobalt) +{ + int i; + + cobalt_dbg(1, "i2c exit\n"); + + for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { + cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name); + i2c_del_adapter(&cobalt->i2c_adap[i]); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-i2c.h b/drivers/media/pci/cobalt/cobalt-i2c.h new file mode 100644 index 000000000..a4c1cfaac --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-i2c.h @@ -0,0 +1,25 @@ +/* + * cobalt I2C functions + * + * Derived from cx18-i2c.h + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* init + register i2c algo-bit adapter */ +int cobalt_i2c_init(struct cobalt *cobalt); +void cobalt_i2c_exit(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c new file mode 100644 index 000000000..d1f5898d1 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -0,0 +1,258 @@ +/* + * cobalt interrupt handling + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <media/adv7604.h> + +#include "cobalt-driver.h" +#include "cobalt-irq.h" +#include "cobalt-omnitek.h" + +static void cobalt_dma_stream_queue_handler(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00473_freewheel_regmap __iomem *fw = + COBALT_CVI_FREEWHEEL(s->cobalt, rx); + struct m00233_video_measure_regmap __iomem *vmr = + COBALT_CVI_VMR(s->cobalt, rx); + struct m00389_cvi_regmap __iomem *cvi = + COBALT_CVI(s->cobalt, rx); + struct m00479_clk_loss_detector_regmap __iomem *clkloss = + COBALT_CVI_CLK_LOSS(s->cobalt, rx); + struct cobalt_buffer *cb; + bool skip = false; + + spin_lock(&s->irqlock); + + if (list_empty(&s->bufs)) { + pr_err("no buffers!\n"); + spin_unlock(&s->irqlock); + return; + } + + /* Give the fresh filled up buffer to the user. + * Note that the interrupt is only sent if the DMA can continue + * with a new buffer, so it is always safe to return this buffer + * to userspace. */ + cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); + list_del(&cb->list); + spin_unlock(&s->irqlock); + + if (s->is_audio || s->is_output) + goto done; + + if (s->unstable_frame) { + uint32_t stat = ioread32(&vmr->irq_status); + + iowrite32(stat, &vmr->irq_status); + if (!(ioread32(&vmr->status) & + M00233_STATUS_BITMAP_INIT_DONE_MSK)) { + cobalt_dbg(1, "!init_done\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + + if (ioread32(&clkloss->status) & + M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) { + iowrite32(0, &clkloss->ctrl); + iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); + cobalt_dbg(1, "no clock\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if ((stat & (M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK | + M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK)) || + ioread32(&vmr->vactive_area) != s->timings.bt.height || + ioread32(&vmr->hactive_area) != s->timings.bt.width) { + cobalt_dbg(1, "unstable\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if (!s->enable_cvi) { + s->enable_cvi = true; + iowrite32(M00389_CONTROL_BITMAP_ENABLE_MSK, &cvi->control); + goto done; + } + if (!(ioread32(&cvi->status) & M00389_STATUS_BITMAP_LOCK_MSK)) { + cobalt_dbg(1, "cvi no lock\n"); + if (s->enable_freewheel) + goto restart_fw; + goto done; + } + if (!s->enable_freewheel) { + cobalt_dbg(1, "stable\n"); + s->enable_freewheel = true; + iowrite32(0, &fw->ctrl); + goto done; + } + cobalt_dbg(1, "enabled fw\n"); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK | + M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK, + &vmr->control); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK, &fw->ctrl); + s->enable_freewheel = false; + s->unstable_frame = false; + s->skip_first_frames = 2; + skip = true; + goto done; + } + if (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) { +restart_fw: + cobalt_dbg(1, "lost lock\n"); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, + &vmr->control); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | + M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, + &fw->ctrl); + iowrite32(0, &cvi->control); + s->unstable_frame = true; + s->enable_freewheel = false; + s->enable_cvi = false; + } +done: + if (s->skip_first_frames) { + skip = true; + s->skip_first_frames--; + } + v4l2_get_timestamp(&cb->vb.v4l2_buf.timestamp); + /* TODO: the sequence number should be read from the FPGA so we + also know about dropped frames. */ + cb->vb.v4l2_buf.sequence = s->sequence++; + vb2_buffer_done(&cb->vb, (skip || s->unstable_frame) ? + VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE); +} + +irqreturn_t cobalt_irq_handler(int irq, void *dev_id) +{ + struct cobalt *cobalt = (struct cobalt *)dev_id; + u32 dma_interrupt = + cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG) & 0xffff; + u32 mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + u32 edge = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_EDGE); + int i; + + /* Clear DMA interrupt */ + cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, dma_interrupt); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, mask & ~edge); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, edge); + + for (i = 0; i < COBALT_NUM_STREAMS; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + unsigned dma_fifo_mask = s->dma_fifo_mask; + + if (dma_interrupt & (1 << s->dma_channel)) { + cobalt->irq_dma[i]++; + /* Give fresh buffer to user and chain newly + * queued buffers */ + cobalt_dma_stream_queue_handler(s); + if (!s->is_audio) { + edge &= ~dma_fifo_mask; + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask & ~edge); + } + } + if (s->is_audio) + continue; + if (edge & s->adv_irq_mask) + set_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags); + if ((edge & mask & dma_fifo_mask) && vb2_is_streaming(&s->q)) { + cobalt_info("full rx FIFO %d\n", i); + cobalt->irq_full_fifo++; + } + } + + queue_work(cobalt->irq_work_queues, &cobalt->irq_work_queue); + + if (edge & mask & (COBALT_SYSSTAT_VI0_INT1_MSK | + COBALT_SYSSTAT_VI1_INT1_MSK | + COBALT_SYSSTAT_VI2_INT1_MSK | + COBALT_SYSSTAT_VI3_INT1_MSK | + COBALT_SYSSTAT_VIHSMA_INT1_MSK | + COBALT_SYSSTAT_VOHSMA_INT1_MSK)) + cobalt->irq_adv1++; + if (edge & mask & (COBALT_SYSSTAT_VI0_INT2_MSK | + COBALT_SYSSTAT_VI1_INT2_MSK | + COBALT_SYSSTAT_VI2_INT2_MSK | + COBALT_SYSSTAT_VI3_INT2_MSK | + COBALT_SYSSTAT_VIHSMA_INT2_MSK)) + cobalt->irq_adv2++; + if (edge & mask & COBALT_SYSSTAT_VOHSMA_INT1_MSK) + cobalt->irq_advout++; + if (dma_interrupt) + cobalt->irq_dma_tot++; + if (!(edge & mask) && !dma_interrupt) + cobalt->irq_none++; + dma_interrupt = cobalt_read_bar0(cobalt, DMA_INTERRUPT_STATUS_REG); + + return IRQ_HANDLED; +} + +void cobalt_irq_work_handler(struct work_struct *work) +{ + struct cobalt *cobalt = + container_of(work, struct cobalt, irq_work_queue); + int i; + + for (i = 0; i < COBALT_NUM_NODES; i++) { + struct cobalt_stream *s = &cobalt->streams[i]; + + if (test_and_clear_bit(COBALT_STREAM_FL_ADV_IRQ, &s->flags)) { + u32 mask; + + v4l2_subdev_call(cobalt->streams[i].sd, core, + interrupt_service_routine, 0, NULL); + mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask | s->adv_irq_mask); + } + } +} + +void cobalt_irq_log_status(struct cobalt *cobalt) +{ + u32 mask; + int i; + + cobalt_info("irq: adv1=%u adv2=%u advout=%u none=%u full=%u\n", + cobalt->irq_adv1, cobalt->irq_adv2, cobalt->irq_advout, + cobalt->irq_none, cobalt->irq_full_fifo); + cobalt_info("irq: dma_tot=%u (", cobalt->irq_dma_tot); + for (i = 0; i < COBALT_NUM_STREAMS; i++) + pr_cont("%s%u", i ? "/" : "", cobalt->irq_dma[i]); + pr_cont(")\n"); + cobalt->irq_dma_tot = cobalt->irq_adv1 = cobalt->irq_adv2 = 0; + cobalt->irq_advout = cobalt->irq_none = cobalt->irq_full_fifo = 0; + memset(cobalt->irq_dma, 0, sizeof(cobalt->irq_dma)); + + mask = cobalt_read_bar1(cobalt, COBALT_SYS_STAT_MASK); + cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, + mask | + COBALT_SYSSTAT_VI0_LOST_DATA_MSK | + COBALT_SYSSTAT_VI1_LOST_DATA_MSK | + COBALT_SYSSTAT_VI2_LOST_DATA_MSK | + COBALT_SYSSTAT_VI3_LOST_DATA_MSK | + COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK | + COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK); +} diff --git a/drivers/media/pci/cobalt/cobalt-irq.h b/drivers/media/pci/cobalt/cobalt-irq.h new file mode 100644 index 000000000..5119484a2 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-irq.h @@ -0,0 +1,25 @@ +/* + * cobalt interrupt handling + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/interrupt.h> + +irqreturn_t cobalt_irq_handler(int irq, void *dev_id); +void cobalt_irq_work_handler(struct work_struct *work); +void cobalt_irq_log_status(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c new file mode 100644 index 000000000..a28a8482c --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-omnitek.c @@ -0,0 +1,341 @@ +/* + * Omnitek Scatter-Gather DMA Controller + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/string.h> +#include <linux/io.h> +#include <linux/pci_regs.h> +#include <linux/spinlock.h> + +#include "cobalt-driver.h" +#include "cobalt-omnitek.h" + +/* descriptor */ +#define END_OF_CHAIN (1 << 1) +#define INTERRUPT_ENABLE (1 << 2) +#define WRITE_TO_PCI (1 << 3) +#define READ_FROM_PCI (0 << 3) +#define DESCRIPTOR_FLAG_MSK (END_OF_CHAIN | INTERRUPT_ENABLE | WRITE_TO_PCI) +#define NEXT_ADRS_MSK 0xffffffe0 + +/* control/status register */ +#define ENABLE (1 << 0) +#define START (1 << 1) +#define ABORT (1 << 2) +#define DONE (1 << 4) +#define SG_INTERRUPT (1 << 5) +#define EVENT_INTERRUPT (1 << 6) +#define SCATTER_GATHER_MODE (1 << 8) +#define DISABLE_VIDEO_RESYNC (1 << 9) +#define EVENT_INTERRUPT_ENABLE (1 << 10) +#define DIRECTIONAL_MSK (3 << 16) +#define INPUT_ONLY (0 << 16) +#define OUTPUT_ONLY (1 << 16) +#define BIDIRECTIONAL (2 << 16) +#define DMA_TYPE_MEMORY (0 << 18) +#define DMA_TYPE_FIFO (1 << 18) + +#define BASE (cobalt->bar0) +#define CAPABILITY_HEADER (BASE) +#define CAPABILITY_REGISTER (BASE + 0x04) +#define PCI_64BIT (1 << 8) +#define LOCAL_64BIT (1 << 9) +#define INTERRUPT_STATUS (BASE + 0x08) +#define PCI(c) (BASE + 0x40 + ((c) * 0x40)) +#define SIZE(c) (BASE + 0x58 + ((c) * 0x40)) +#define DESCRIPTOR(c) (BASE + 0x50 + ((c) * 0x40)) +#define CS_REG(c) (BASE + 0x60 + ((c) * 0x40)) +#define BYTES_TRANSFERRED(c) (BASE + 0x64 + ((c) * 0x40)) + + +static char *get_dma_direction(u32 status) +{ + switch (status & DIRECTIONAL_MSK) { + case INPUT_ONLY: return "Input"; + case OUTPUT_ONLY: return "Output"; + case BIDIRECTIONAL: return "Bidirectional"; + } + return ""; +} + +static void show_dma_capability(struct cobalt *cobalt) +{ + u32 header = ioread32(CAPABILITY_HEADER); + u32 capa = ioread32(CAPABILITY_REGISTER); + u32 i; + + cobalt_info("Omnitek DMA capability: ID 0x%02x Version 0x%02x Next 0x%x Size 0x%x\n", + header & 0xff, (header >> 8) & 0xff, + (header >> 16) & 0xffff, (capa >> 24) & 0xff); + + switch ((capa >> 8) & 0x3) { + case 0: + cobalt_info("Omnitek DMA: 32 bits PCIe and Local\n"); + break; + case 1: + cobalt_info("Omnitek DMA: 64 bits PCIe, 32 bits Local\n"); + break; + case 3: + cobalt_info("Omnitek DMA: 64 bits PCIe and Local\n"); + break; + } + + for (i = 0; i < (capa & 0xf); i++) { + u32 status = ioread32(CS_REG(i)); + + cobalt_info("Omnitek DMA channel #%d: %s %s\n", i, + status & DMA_TYPE_FIFO ? "FIFO" : "MEMORY", + get_dma_direction(status)); + } +} + +void omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc) +{ + struct cobalt *cobalt = s->cobalt; + + iowrite32((u32)((u64)desc->bus >> 32), DESCRIPTOR(s->dma_channel) + 4); + iowrite32((u32)desc->bus & NEXT_ADRS_MSK, DESCRIPTOR(s->dma_channel)); + iowrite32(ENABLE | SCATTER_GATHER_MODE | START, CS_REG(s->dma_channel)); +} + +bool is_dma_done(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + + if (ioread32(CS_REG(s->dma_channel)) & DONE) + return true; + + return false; +} + +void omni_sg_dma_abort_channel(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + + if (is_dma_done(s) == false) + iowrite32(ABORT, CS_REG(s->dma_channel)); +} + +int omni_sg_dma_init(struct cobalt *cobalt) +{ + u32 capa = ioread32(CAPABILITY_REGISTER); + int i; + + cobalt->first_fifo_channel = 0; + cobalt->dma_channels = capa & 0xf; + if (capa & PCI_64BIT) + cobalt->pci_32_bit = false; + else + cobalt->pci_32_bit = true; + + for (i = 0; i < cobalt->dma_channels; i++) { + u32 status = ioread32(CS_REG(i)); + u32 ctrl = ioread32(CS_REG(i)); + + if (!(ctrl & DONE)) + iowrite32(ABORT, CS_REG(i)); + + if (!(status & DMA_TYPE_FIFO)) + cobalt->first_fifo_channel++; + } + show_dma_capability(cobalt); + return 0; +} + +int descriptor_list_create(struct cobalt *cobalt, + struct scatterlist *scatter_list, bool to_pci, unsigned sglen, + unsigned size, unsigned width, unsigned stride, + struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = (struct sg_dma_descriptor *)desc->virt; + dma_addr_t next = desc->bus; + unsigned offset = 0; + unsigned copy_bytes = width; + unsigned copied = 0; + bool first = true; + + /* Must be 4-byte aligned */ + WARN_ON(sg_dma_address(scatter_list) & 3); + WARN_ON(size & 3); + WARN_ON(next & 3); + WARN_ON(stride & 3); + WARN_ON(stride < width); + if (width >= stride) + copy_bytes = stride = size; + + while (size) { + dma_addr_t addr = sg_dma_address(scatter_list) + offset; + unsigned bytes; + + if (addr == 0) + return -EFAULT; + if (cobalt->pci_32_bit) { + WARN_ON((u64)addr >> 32); + if ((u64)addr >> 32) + return -EFAULT; + } + + /* PCIe address */ + d->pci_l = addr & 0xffffffff; + /* If dma_addr_t is 32 bits, then addr >> 32 is actually the + equivalent of addr >> 0 in gcc. So must cast to u64. */ + d->pci_h = (u64)addr >> 32; + + /* Sync to start of streaming frame */ + d->local = 0; + d->reserved0 = 0; + + /* Transfer bytes */ + bytes = min(sg_dma_len(scatter_list) - offset, + copy_bytes - copied); + + if (first) { + if (to_pci) + d->local = 0x11111111; + first = false; + if (sglen == 1) { + /* Make sure there are always at least two + * descriptors */ + d->bytes = (bytes / 2) & ~3; + d->reserved1 = 0; + size -= d->bytes; + copied += d->bytes; + offset += d->bytes; + addr += d->bytes; + next += sizeof(struct sg_dma_descriptor); + d->next_h = (u32)((u64)next >> 32); + d->next_l = (u32)next | + (to_pci ? WRITE_TO_PCI : 0); + bytes -= d->bytes; + d++; + /* PCIe address */ + d->pci_l = addr & 0xffffffff; + /* If dma_addr_t is 32 bits, then addr >> 32 + * is actually the equivalent of addr >> 0 in + * gcc. So must cast to u64. */ + d->pci_h = (u64)addr >> 32; + + /* Sync to start of streaming frame */ + d->local = 0; + d->reserved0 = 0; + } + } + + d->bytes = bytes; + d->reserved1 = 0; + size -= bytes; + copied += bytes; + offset += bytes; + + if (copied == copy_bytes) { + while (copied < stride) { + bytes = min(sg_dma_len(scatter_list) - offset, + stride - copied); + copied += bytes; + offset += bytes; + size -= bytes; + if (sg_dma_len(scatter_list) == offset) { + offset = 0; + scatter_list = sg_next(scatter_list); + } + } + copied = 0; + } else { + offset = 0; + scatter_list = sg_next(scatter_list); + } + + /* Next descriptor + control bits */ + next += sizeof(struct sg_dma_descriptor); + if (size == 0) { + /* Loopback to the first descriptor */ + d->next_h = (u32)((u64)desc->bus >> 32); + d->next_l = (u32)desc->bus | + (to_pci ? WRITE_TO_PCI : 0) | INTERRUPT_ENABLE; + if (!to_pci) + d->local = 0x22222222; + desc->last_desc_virt = d; + } else { + d->next_h = (u32)((u64)next >> 32); + d->next_l = (u32)next | (to_pci ? WRITE_TO_PCI : 0); + } + d++; + } + return 0; +} + +void descriptor_list_chain(struct sg_dma_desc_info *this, + struct sg_dma_desc_info *next) +{ + struct sg_dma_descriptor *d = this->last_desc_virt; + u32 direction = d->next_l & WRITE_TO_PCI; + + if (next == NULL) { + d->next_h = 0; + d->next_l = direction | INTERRUPT_ENABLE | END_OF_CHAIN; + } else { + d->next_h = (u32)((u64)next->bus >> 32); + d->next_l = (u32)next->bus | direction | INTERRUPT_ENABLE; + } +} + +void *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes) +{ + desc->size = bytes; + desc->virt = dma_alloc_coherent(desc->dev, bytes, + &desc->bus, GFP_KERNEL); + return desc->virt; +} + +void descriptor_list_free(struct sg_dma_desc_info *desc) +{ + if (desc->virt) + dma_free_coherent(desc->dev, desc->size, + desc->virt, desc->bus); + desc->virt = NULL; +} + +void descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l |= INTERRUPT_ENABLE; +} + +void descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l &= ~INTERRUPT_ENABLE; +} + +void descriptor_list_loopback(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_h = (u32)((u64)desc->bus >> 32); + d->next_l = (u32)desc->bus | (d->next_l & DESCRIPTOR_FLAG_MSK); +} + +void descriptor_list_end_of_chain(struct sg_dma_desc_info *desc) +{ + struct sg_dma_descriptor *d = desc->last_desc_virt; + + d->next_l |= END_OF_CHAIN; +} diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.h b/drivers/media/pci/cobalt/cobalt-omnitek.h new file mode 100644 index 000000000..e5c6d032c --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-omnitek.h @@ -0,0 +1,62 @@ +/* + * Omnitek Scatter-Gather DMA Controller + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef COBALT_OMNITEK_H +#define COBALT_OMNITEK_H + +#include <linux/scatterlist.h> +#include "cobalt-driver.h" + +struct sg_dma_descriptor { + u32 pci_l; + u32 pci_h; + + u32 local; + u32 reserved0; + + u32 next_l; + u32 next_h; + + u32 bytes; + u32 reserved1; +}; + +int omni_sg_dma_init(struct cobalt *cobalt); +void omni_sg_dma_abort_channel(struct cobalt_stream *s); +void omni_sg_dma_start(struct cobalt_stream *s, struct sg_dma_desc_info *desc); +bool is_dma_done(struct cobalt_stream *s); + +int descriptor_list_create(struct cobalt *cobalt, + struct scatterlist *scatter_list, bool to_pci, unsigned sglen, + unsigned size, unsigned width, unsigned stride, + struct sg_dma_desc_info *desc); + +void descriptor_list_chain(struct sg_dma_desc_info *this, + struct sg_dma_desc_info *next); +void descriptor_list_loopback(struct sg_dma_desc_info *desc); +void descriptor_list_end_of_chain(struct sg_dma_desc_info *desc); + +void *descriptor_list_allocate(struct sg_dma_desc_info *desc, size_t bytes); +void descriptor_list_free(struct sg_dma_desc_info *desc); + +void descriptor_list_interrupt_enable(struct sg_dma_desc_info *desc); +void descriptor_list_interrupt_disable(struct sg_dma_desc_info *desc); + +#endif diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c new file mode 100644 index 000000000..b40c2d141 --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -0,0 +1,1272 @@ +/* + * cobalt V4L2 API + * + * Derived from ivtv-ioctl.c and cx18-fileops.c + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/math64.h> +#include <linux/pci.h> +#include <linux/v4l2-dv-timings.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/adv7604.h> +#include <media/adv7842.h> + +#include "cobalt-alsa.h" +#include "cobalt-cpld.h" +#include "cobalt-driver.h" +#include "cobalt-v4l2.h" +#include "cobalt-irq.h" +#include "cobalt-omnitek.h" + +static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60; + +/* vb2 DMA streaming ops */ + +static int cobalt_queue_setup(struct vb2_queue *q, + const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct cobalt_stream *s = q->drv_priv; + unsigned size = s->stride * s->height; + + if (*num_buffers < 3) + *num_buffers = 3; + if (*num_buffers > NR_BUFS) + *num_buffers = NR_BUFS; + *num_planes = 1; + if (fmt) { + if (fmt->fmt.pix.sizeimage < size) + return -EINVAL; + size = fmt->fmt.pix.sizeimage; + } + sizes[0] = size; + alloc_ctxs[0] = s->cobalt->alloc_ctx; + return 0; +} + +static int cobalt_buf_init(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + struct cobalt *cobalt = s->cobalt; + const size_t max_pages_per_line = + (COBALT_MAX_WIDTH * COBALT_MAX_BPP) / PAGE_SIZE + 2; + const size_t bytes = + COBALT_MAX_HEIGHT * max_pages_per_line * 0x20; + const size_t audio_bytes = ((1920 * 4) / PAGE_SIZE + 1) * 0x20; + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + struct sg_table *sg_desc = vb2_dma_sg_plane_desc(vb, 0); + unsigned size; + int ret; + + size = s->stride * s->height; + if (vb2_plane_size(vb, 0) < size) { + cobalt_info("data will not fit into plane (%lu < %u)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + if (desc->virt == NULL) { + desc->dev = &cobalt->pci_dev->dev; + descriptor_list_allocate(desc, + s->is_audio ? audio_bytes : bytes); + if (desc->virt == NULL) + return -ENOMEM; + } + ret = descriptor_list_create(cobalt, sg_desc->sgl, + !s->is_output, sg_desc->nents, size, + s->width * s->bpp, s->stride, desc); + if (ret) + descriptor_list_free(desc); + return ret; +} + +static void cobalt_buf_cleanup(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + + descriptor_list_free(desc); +} + +static int cobalt_buf_prepare(struct vb2_buffer *vb) +{ + struct cobalt_stream *s = vb->vb2_queue->drv_priv; + + vb2_set_plane_payload(vb, 0, s->stride * s->height); + vb->v4l2_buf.field = V4L2_FIELD_NONE; + return 0; +} + +static void chain_all_buffers(struct cobalt_stream *s) +{ + struct sg_dma_desc_info *desc[NR_BUFS]; + struct cobalt_buffer *cb; + struct list_head *p; + int i = 0; + + list_for_each(p, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + desc[i] = &s->dma_desc_info[cb->vb.v4l2_buf.index]; + if (i > 0) + descriptor_list_chain(desc[i-1], desc[i]); + i++; + } +} + +static void cobalt_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct cobalt_stream *s = q->drv_priv; + struct cobalt_buffer *cb = to_cobalt_buffer(vb); + struct sg_dma_desc_info *desc = &s->dma_desc_info[vb->v4l2_buf.index]; + unsigned long flags; + + /* Prepare new buffer */ + descriptor_list_loopback(desc); + descriptor_list_interrupt_disable(desc); + + spin_lock_irqsave(&s->irqlock, flags); + list_add_tail(&cb->list, &s->bufs); + chain_all_buffers(s); + spin_unlock_irqrestore(&s->irqlock, flags); +} + +static void cobalt_enable_output(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct v4l2_bt_timings *bt = &s->timings.bt; + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + unsigned fmt = s->pixfmt != V4L2_PIX_FMT_BGR32 ? + M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK : 0; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + if (!cobalt_cpld_set_freq(cobalt, bt->pixelclock)) { + cobalt_err("pixelclock out of range\n"); + return; + } + + sd_fmt.format.colorspace = s->colorspace; + sd_fmt.format.xfer_func = s->xfer_func; + sd_fmt.format.ycbcr_enc = s->ycbcr_enc; + sd_fmt.format.quantization = s->quantization; + sd_fmt.format.width = bt->width; + sd_fmt.format.height = bt->height; + + /* Set up FDMA packer */ + switch (s->pixfmt) { + case V4L2_PIX_FMT_YUYV: + sd_fmt.format.code = MEDIA_BUS_FMT_UYVY8_1X16; + break; + case V4L2_PIX_FMT_BGR32: + sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24; + break; + } + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); + + iowrite32(0, &vo->control); + /* 1080p60 */ + iowrite32(bt->hsync, &vo->sync_generator_h_sync_length); + iowrite32(bt->hbackporch, &vo->sync_generator_h_backporch_length); + iowrite32(bt->width, &vo->sync_generator_h_active_length); + iowrite32(bt->hfrontporch, &vo->sync_generator_h_frontporch_length); + iowrite32(bt->vsync, &vo->sync_generator_v_sync_length); + iowrite32(bt->vbackporch, &vo->sync_generator_v_backporch_length); + iowrite32(bt->height, &vo->sync_generator_v_active_length); + iowrite32(bt->vfrontporch, &vo->sync_generator_v_frontporch_length); + iowrite32(0x9900c1, &vo->error_color); + + iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK | fmt, + &vo->control); + iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK | fmt, &vo->control); + iowrite32(M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK | + M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK | + fmt, &vo->control); +} + +static void cobalt_enable_input(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int ch = (int)s->video_channel; + struct m00235_fdma_packer_regmap __iomem *packer; + struct v4l2_subdev_format sd_fmt_yuyv = { + .pad = s->pad_source, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_YUYV8_1X16, + }; + struct v4l2_subdev_format sd_fmt_rgb = { + .pad = s->pad_source, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format.code = MEDIA_BUS_FMT_RGB888_1X24, + }; + + cobalt_dbg(1, "video_channel %d (%s, %s)\n", + s->video_channel, + s->input == 0 ? "hdmi" : "generator", + "YUYV"); + + packer = COBALT_CVI_PACKER(cobalt, ch); + + /* Set up FDMA packer */ + switch (s->pixfmt) { + case V4L2_PIX_FMT_YUYV: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + (1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_yuyv); + break; + case V4L2_PIX_FMT_RGB24: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + (2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_rgb); + break; + case V4L2_PIX_FMT_BGR32: + iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK | + M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK | + (3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST), + &packer->control); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, + &sd_fmt_rgb); + break; + } +} + +static void cobalt_dma_start_streaming(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00460_evcnt_regmap __iomem *evcnt = + COBALT_CVI_EVCNT(cobalt, rx); + struct cobalt_buffer *cb; + unsigned long flags; + + spin_lock_irqsave(&s->irqlock, flags); + if (!s->is_output) { + iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); + iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); + } else { + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + u32 ctrl = ioread32(&vo->control); + + ctrl &= ~(M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK | + M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK); + iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, + &vo->control); + iowrite32(ctrl | M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK, + &vo->control); + } + cb = list_first_entry(&s->bufs, struct cobalt_buffer, list); + omni_sg_dma_start(s, &s->dma_desc_info[cb->vb.v4l2_buf.index]); + spin_unlock_irqrestore(&s->irqlock, flags); +} + +static int cobalt_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cobalt_stream *s = q->drv_priv; + struct cobalt *cobalt = s->cobalt; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + int rx = s->video_channel; + struct m00389_cvi_regmap __iomem *cvi = COBALT_CVI(cobalt, rx); + struct m00460_evcnt_regmap __iomem *evcnt = COBALT_CVI_EVCNT(cobalt, rx); + struct v4l2_bt_timings *bt = &s->timings.bt; + u64 tot_size; + u32 clk_freq; + + if (s->is_audio) + goto done; + if (s->is_output) { + s->unstable_frame = false; + cobalt_enable_output(s); + goto done; + } + + cobalt_enable_input(s); + + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + + iowrite32(M00460_CONTROL_BITMAP_CLEAR_MSK, &evcnt->control); + iowrite32(M00460_CONTROL_BITMAP_ENABLE_MSK, &evcnt->control); + iowrite32(bt->width, &cvi->frame_width); + iowrite32(bt->height, &cvi->frame_height); + tot_size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + iowrite32(div_u64((u64)V4L2_DV_BT_FRAME_WIDTH(bt) * COBALT_CLK * 4, + bt->pixelclock), &vmr->hsync_timeout_val); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + clk_freq = ioread32(&fw->clk_freq); + iowrite32(clk_freq / 1000000, &clkloss->ref_clk_cnt_val); + /* The lower bound for the clock frequency is 0.5% lower as is + * allowed by the spec */ + iowrite32(div_u64(bt->pixelclock * 995, 1000000000), + &clkloss->test_clk_cnt_val); + /* will be enabled after the first frame has been received */ + iowrite32(bt->width * bt->height, &fw->active_length); + iowrite32(div_u64((u64)clk_freq * tot_size, bt->pixelclock), + &fw->total_length); + iowrite32(M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK | + M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK, + &vmr->irq_triggers); + iowrite32(0, &cvi->control); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + + iowrite32(0xff, &fw->output_color); + iowrite32(M00479_CTRL_BITMAP_ENABLE_MSK, &clkloss->ctrl); + iowrite32(M00473_CTRL_BITMAP_ENABLE_MSK | + M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK, &fw->ctrl); + s->unstable_frame = true; + s->enable_freewheel = false; + s->enable_cvi = false; + s->skip_first_frames = 0; + +done: + s->sequence = 0; + cobalt_dma_start_streaming(s); + return 0; +} + +static void cobalt_dma_stop_streaming(struct cobalt_stream *s) +{ + struct cobalt *cobalt = s->cobalt; + struct sg_dma_desc_info *desc; + struct cobalt_buffer *cb; + struct list_head *p; + unsigned long flags; + int timeout_msec = 100; + int rx = s->video_channel; + struct m00460_evcnt_regmap __iomem *evcnt = + COBALT_CVI_EVCNT(cobalt, rx); + + if (!s->is_output) { + iowrite32(0, &evcnt->control); + } else if (!s->is_audio) { + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + + iowrite32(M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK, &vo->control); + iowrite32(0, &vo->control); + } + + /* Try to stop the DMA engine gracefully */ + spin_lock_irqsave(&s->irqlock, flags); + list_for_each(p, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + desc = &s->dma_desc_info[cb->vb.v4l2_buf.index]; + /* Stop DMA after this descriptor chain */ + descriptor_list_end_of_chain(desc); + } + spin_unlock_irqrestore(&s->irqlock, flags); + + /* Wait 100 milisecond for DMA to finish, abort on timeout. */ + if (!wait_event_timeout(s->q.done_wq, is_dma_done(s), + msecs_to_jiffies(timeout_msec))) { + omni_sg_dma_abort_channel(s); + pr_warn("aborted\n"); + } + cobalt_write_bar0(cobalt, DMA_INTERRUPT_STATUS_REG, + 1 << s->dma_channel); +} + +static void cobalt_stop_streaming(struct vb2_queue *q) +{ + struct cobalt_stream *s = q->drv_priv; + struct cobalt *cobalt = s->cobalt; + int rx = s->video_channel; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + struct cobalt_buffer *cb; + struct list_head *p, *safe; + unsigned long flags; + + cobalt_dma_stop_streaming(s); + + /* Return all buffers to user space */ + spin_lock_irqsave(&s->irqlock, flags); + list_for_each_safe(p, safe, &s->bufs) { + cb = list_entry(p, struct cobalt_buffer, list); + list_del(&cb->list); + vb2_buffer_done(&cb->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&s->irqlock, flags); + + if (s->is_audio || s->is_output) + return; + + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + iowrite32(0, &vmr->control); + iowrite32(M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK, &vmr->control); + iowrite32(0, &fw->ctrl); + iowrite32(0, &clkloss->ctrl); +} + +static const struct vb2_ops cobalt_qops = { + .queue_setup = cobalt_queue_setup, + .buf_init = cobalt_buf_init, + .buf_cleanup = cobalt_buf_cleanup, + .buf_prepare = cobalt_buf_prepare, + .buf_queue = cobalt_buf_queue, + .start_streaming = cobalt_start_streaming, + .stop_streaming = cobalt_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* V4L2 ioctls */ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg) +{ + struct v4l2_dbg_register *regs = arg; + void __iomem *adrs = cobalt->bar1 + regs->reg; + + cobalt_info("cobalt_cobaltc: adrs = %p\n", adrs); + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + regs->size = 4; + if (cmd == VIDIOC_DBG_S_REGISTER) + iowrite32(regs->val, adrs); + else + regs->val = ioread32(adrs); + return 0; +} + +static int cobalt_g_register(struct file *file, void *priv_fh, + struct v4l2_dbg_register *reg) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg); +} + +static int cobalt_s_register(struct file *file, void *priv_fh, + const struct v4l2_dbg_register *reg) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + return cobalt_cobaltc(cobalt, VIDIOC_DBG_S_REGISTER, + (struct v4l2_dbg_register *)reg); +} +#endif + +static int cobalt_querycap(struct file *file, void *priv_fh, + struct v4l2_capability *vcap) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + + strlcpy(vcap->driver, "cobalt", sizeof(vcap->driver)); + strlcpy(vcap->card, "cobalt", sizeof(vcap->card)); + snprintf(vcap->bus_info, sizeof(vcap->bus_info), + "PCIe:%s", pci_name(cobalt->pci_dev)); + vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (s->is_output) + vcap->device_caps |= V4L2_CAP_VIDEO_OUTPUT; + else + vcap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_VIDEO_CAPTURE; + if (cobalt->have_hsma_tx) + vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; + return 0; +} + +static void cobalt_video_input_status_show(struct cobalt_stream *s) +{ + struct m00389_cvi_regmap __iomem *cvi; + struct m00233_video_measure_regmap __iomem *vmr; + struct m00473_freewheel_regmap __iomem *fw; + struct m00479_clk_loss_detector_regmap __iomem *clkloss; + struct m00235_fdma_packer_regmap __iomem *packer; + int rx = s->video_channel; + struct cobalt *cobalt = s->cobalt; + u32 cvi_ctrl, cvi_stat; + u32 vmr_ctrl, vmr_stat; + + cvi = COBALT_CVI(cobalt, rx); + vmr = COBALT_CVI_VMR(cobalt, rx); + fw = COBALT_CVI_FREEWHEEL(cobalt, rx); + clkloss = COBALT_CVI_CLK_LOSS(cobalt, rx); + packer = COBALT_CVI_PACKER(cobalt, rx); + cvi_ctrl = ioread32(&cvi->control); + cvi_stat = ioread32(&cvi->status); + vmr_ctrl = ioread32(&vmr->control); + vmr_stat = ioread32(&vmr->control); + cobalt_info("rx%d: cvi resolution: %dx%d\n", rx, + ioread32(&cvi->frame_width), ioread32(&cvi->frame_height)); + cobalt_info("rx%d: cvi control: %s%s%s\n", rx, + (cvi_ctrl & M00389_CONTROL_BITMAP_ENABLE_MSK) ? + "enable " : "disable ", + (cvi_ctrl & M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? + "HSync- " : "HSync+ ", + (cvi_ctrl & M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? + "VSync- " : "VSync+ "); + cobalt_info("rx%d: cvi status: %s%s\n", rx, + (cvi_stat & M00389_STATUS_BITMAP_LOCK_MSK) ? + "lock " : "no-lock ", + (cvi_stat & M00389_STATUS_BITMAP_ERROR_MSK) ? + "error " : "no-error "); + + cobalt_info("rx%d: Measurements: %s%s%s%s%s%s%s\n", rx, + (vmr_ctrl & M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK) ? + "HSync- " : "HSync+ ", + (vmr_ctrl & M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK) ? + "VSync- " : "VSync+ ", + (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK) ? + "enabled " : "disabled ", + (vmr_ctrl & M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK) ? + "irq-enabled " : "irq-disabled ", + (vmr_ctrl & M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK) ? + "update-on-hsync " : "", + (vmr_stat & M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK) ? + "hsync-timeout " : "", + (vmr_stat & M00233_STATUS_BITMAP_INIT_DONE_MSK) ? + "init-done" : ""); + cobalt_info("rx%d: irq_status: 0x%02x irq_triggers: 0x%02x\n", rx, + ioread32(&vmr->irq_status) & 0xff, + ioread32(&vmr->irq_triggers) & 0xff); + cobalt_info("rx%d: vsync: %d\n", rx, ioread32(&vmr->vsync_time)); + cobalt_info("rx%d: vbp: %d\n", rx, ioread32(&vmr->vback_porch)); + cobalt_info("rx%d: vact: %d\n", rx, ioread32(&vmr->vactive_area)); + cobalt_info("rx%d: vfb: %d\n", rx, ioread32(&vmr->vfront_porch)); + cobalt_info("rx%d: hsync: %d\n", rx, ioread32(&vmr->hsync_time)); + cobalt_info("rx%d: hbp: %d\n", rx, ioread32(&vmr->hback_porch)); + cobalt_info("rx%d: hact: %d\n", rx, ioread32(&vmr->hactive_area)); + cobalt_info("rx%d: hfb: %d\n", rx, ioread32(&vmr->hfront_porch)); + cobalt_info("rx%d: Freewheeling: %s%s%s\n", rx, + (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_ENABLE_MSK) ? + "enabled " : "disabled ", + (ioread32(&fw->ctrl) & M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK) ? + "forced " : "", + (ioread32(&fw->status) & M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK) ? + "freewheeling " : "video-passthrough "); + iowrite32(0xff, &vmr->irq_status); + cobalt_info("rx%d: Clock Loss Detection: %s%s\n", rx, + (ioread32(&clkloss->ctrl) & M00479_CTRL_BITMAP_ENABLE_MSK) ? + "enabled " : "disabled ", + (ioread32(&clkloss->status) & M00479_STATUS_BITMAP_CLOCK_MISSING_MSK) ? + "clock-missing " : "found-clock "); + cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control)); +} + +static int cobalt_log_status(struct file *file, void *priv_fh) +{ + struct cobalt_stream *s = video_drvdata(file); + struct cobalt *cobalt = s->cobalt; + struct m00514_syncgen_flow_evcnt_regmap __iomem *vo = + COBALT_TX_BASE(cobalt); + u8 stat; + + cobalt_info("%s", cobalt->hdl_info); + cobalt_info("sysctrl: %08x, sysstat: %08x\n", + cobalt_g_sysctrl(cobalt), + cobalt_g_sysstat(cobalt)); + cobalt_info("dma channel: %d, video channel: %d\n", + s->dma_channel, s->video_channel); + cobalt_pcie_status_show(cobalt); + cobalt_cpld_status(cobalt); + cobalt_irq_log_status(cobalt); + v4l2_subdev_call(s->sd, core, log_status); + if (!s->is_output) { + cobalt_video_input_status_show(s); + return 0; + } + + stat = ioread32(&vo->rd_status); + + cobalt_info("tx: status: %s%s\n", + (stat & M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK) ? + "no_data " : "", + (stat & M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK) ? + "ready_buffer_full " : ""); + cobalt_info("tx: evcnt: %d\n", ioread32(&vo->rd_evcnt_count)); + return 0; +} + +static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + if (timings->index) + return -EINVAL; + memset(timings->reserved, 0, sizeof(timings->reserved)); + timings->timings = cea1080p60; + return 0; + } + timings->pad = 0; + return v4l2_subdev_call(s->sd, + pad, enum_dv_timings, timings); +} + +static int cobalt_s_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + int err; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + err = v4l2_subdev_call(s->sd, + video, s_dv_timings, timings); + if (!err) { + s->timings = *timings; + s->width = timings->bt.width; + s->height = timings->bt.height; + s->stride = timings->bt.width * s->bpp; + } + return err; +} + +static int cobalt_g_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + return v4l2_subdev_call(s->sd, + video, g_dv_timings, timings); +} + +static int cobalt_query_dv_timings(struct file *file, void *priv_fh, + struct v4l2_dv_timings *timings) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (s->input == 1) { + *timings = cea1080p60; + return 0; + } + return v4l2_subdev_call(s->sd, + video, query_dv_timings, timings); +} + +static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, + struct v4l2_dv_timings_cap *cap) +{ + struct cobalt_stream *s = video_drvdata(file); + + cap->pad = 0; + return v4l2_subdev_call(s->sd, + pad, dv_timings_cap, cap); +} + +static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_fmtdesc *f) +{ + switch (f->index) { + case 0: + strlcpy(f->description, "YUV 4:2:2", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case 1: + strlcpy(f->description, "RGB24", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_RGB24; + break; + case 2: + strlcpy(f->description, "RGB32", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_BGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt; + + pix->width = s->width; + pix->height = s->height; + pix->bytesperline = s->stride; + pix->field = V4L2_FIELD_NONE; + + if (s->input == 1) { + pix->colorspace = V4L2_COLORSPACE_SRGB; + } else { + sd_fmt.pad = s->pad_source; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); + v4l2_fill_pix_format(pix, &sd_fmt.format); + } + + pix->pixelformat = s->pixfmt; + pix->sizeimage = pix->bytesperline * pix->height; + + return 0; +} + +static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt; + + /* Check for min (QCIF) and max (Full HD) size */ + if ((pix->width < 176) || (pix->height < 144)) { + pix->width = 176; + pix->height = 144; + } + + if ((pix->width > 1920) || (pix->height > 1080)) { + pix->width = 1920; + pix->height = 1080; + } + + /* Make width multiple of 4 */ + pix->width &= ~0x3; + + /* Make height multiple of 2 */ + pix->height &= ~0x1; + + if (s->input == 1) { + /* Generator => fixed format only */ + pix->width = 1920; + pix->height = 1080; + pix->colorspace = V4L2_COLORSPACE_SRGB; + } else { + sd_fmt.pad = s->pad_source; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_subdev_call(s->sd, pad, get_fmt, NULL, &sd_fmt); + v4l2_fill_pix_format(pix, &sd_fmt.format); + } + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + default: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_YUYV); + pix->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case V4L2_PIX_FMT_RGB24: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB24); + break; + case V4L2_PIX_FMT_BGR32: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB32); + break; + } + + pix->sizeimage = pix->bytesperline * pix->height; + pix->field = V4L2_FIELD_NONE; + pix->priv = 0; + + return 0; +} + +static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + + if (cobalt_try_fmt_vid_cap(file, priv_fh, f)) + return -EINVAL; + + s->width = pix->width; + s->height = pix->height; + s->stride = pix->bytesperline; + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + break; + case V4L2_PIX_FMT_RGB24: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB24; + break; + case V4L2_PIX_FMT_BGR32: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + break; + default: + return -EINVAL; + } + s->pixfmt = pix->pixelformat; + cobalt_enable_input(s); + + return 0; +} + +static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + + /* Check for min (QCIF) and max (Full HD) size */ + if ((pix->width < 176) || (pix->height < 144)) { + pix->width = 176; + pix->height = 144; + } + + if ((pix->width > 1920) || (pix->height > 1080)) { + pix->width = 1920; + pix->height = 1080; + } + + /* Make width multiple of 4 */ + pix->width &= ~0x3; + + /* Make height multiple of 2 */ + pix->height &= ~0x1; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + default: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_YUYV); + pix->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case V4L2_PIX_FMT_BGR32: + pix->bytesperline = max(pix->bytesperline & ~0x3, + pix->width * COBALT_BYTES_PER_PIXEL_RGB32); + break; + } + + pix->sizeimage = pix->bytesperline * pix->height; + pix->field = V4L2_FIELD_NONE; + + return 0; +} + +static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = s->width; + pix->height = s->height; + pix->bytesperline = s->stride; + pix->field = V4L2_FIELD_NONE; + pix->pixelformat = s->pixfmt; + pix->colorspace = s->colorspace; + pix->xfer_func = s->xfer_func; + pix->ycbcr_enc = s->ycbcr_enc; + pix->quantization = s->quantization; + pix->sizeimage = pix->bytesperline * pix->height; + + return 0; +} + +static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_fmtdesc *f) +{ + switch (f->index) { + case 0: + strlcpy(f->description, "YUV 4:2:2", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_YUYV; + break; + case 1: + strlcpy(f->description, "RGB32", sizeof(f->description)); + f->pixelformat = V4L2_PIX_FMT_BGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, + struct v4l2_format *f) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_subdev_format sd_fmt = { 0 }; + u32 code; + + if (cobalt_try_fmt_vid_out(file, priv_fh, f)) + return -EINVAL; + + if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt || + pix->width != s->width || pix->height != s->height || + pix->bytesperline != s->stride)) + return -EBUSY; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + code = MEDIA_BUS_FMT_UYVY8_1X16; + break; + case V4L2_PIX_FMT_BGR32: + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + code = MEDIA_BUS_FMT_RGB888_1X24; + break; + default: + return -EINVAL; + } + s->width = pix->width; + s->height = pix->height; + s->stride = pix->bytesperline; + s->pixfmt = pix->pixelformat; + s->colorspace = pix->colorspace; + s->xfer_func = pix->xfer_func; + s->ycbcr_enc = pix->ycbcr_enc; + s->quantization = pix->quantization; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + v4l2_fill_mbus_format(&sd_fmt.format, pix, code); + v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt); + return 0; +} + +static int cobalt_enum_input(struct file *file, void *priv_fh, + struct v4l2_input *inp) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (inp->index > 1) + return -EINVAL; + if (inp->index == 0) + snprintf(inp->name, sizeof(inp->name), + "HDMI-%d", s->video_channel); + else + snprintf(inp->name, sizeof(inp->name), + "Generator-%d", s->video_channel); + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + if (inp->index == 1) + return 0; + return v4l2_subdev_call(s->sd, + video, g_input_status, &inp->status); +} + +static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) +{ + struct cobalt_stream *s = video_drvdata(file); + + *i = s->input; + return 0; +} + +static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) +{ + struct cobalt_stream *s = video_drvdata(file); + + if (i >= 2) + return -EINVAL; + if (vb2_is_busy(&s->q)) + return -EBUSY; + s->input = i; + + cobalt_enable_input(s); + + if (s->input == 1) /* Test Pattern Generator */ + return 0; + + return v4l2_subdev_call(s->sd, video, s_routing, + ADV76XX_PAD_HDMI_PORT_A, 0, 0); +} + +static int cobalt_enum_output(struct file *file, void *priv_fh, + struct v4l2_output *out) +{ + if (out->index) + return -EINVAL; + snprintf(out->name, sizeof(out->name), "HDMI-%d", out->index); + out->type = V4L2_OUTPUT_TYPE_ANALOG; + out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; + return 0; +} + +static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + +static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) +{ + struct cobalt_stream *s = video_drvdata(file); + u32 pad = edid->pad; + int ret; + + if (edid->pad >= (s->is_output ? 1 : 2)) + return -EINVAL; + edid->pad = 0; + ret = v4l2_subdev_call(s->sd, pad, get_edid, edid); + edid->pad = pad; + return ret; +} + +static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) +{ + struct cobalt_stream *s = video_drvdata(file); + u32 pad = edid->pad; + int ret; + + if (edid->pad >= 2) + return -EINVAL; + edid->pad = 0; + ret = v4l2_subdev_call(s->sd, pad, set_edid, edid); + edid->pad = pad; + return ret; +} + +static int cobalt_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_event_subscribe(fh, sub, 4, NULL); + } + return v4l2_ctrl_subscribe_event(fh, sub); +} + +static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + a->parm.capture.timeperframe.numerator = 1; + a->parm.capture.timeperframe.denominator = 60; + a->parm.capture.readbuffers = 3; + return 0; +} + +static const struct v4l2_ioctl_ops cobalt_ioctl_ops = { + .vidioc_querycap = cobalt_querycap, + .vidioc_g_parm = cobalt_g_parm, + .vidioc_log_status = cobalt_log_status, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_input = cobalt_enum_input, + .vidioc_g_input = cobalt_g_input, + .vidioc_s_input = cobalt_s_input, + .vidioc_enum_fmt_vid_cap = cobalt_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cobalt_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cobalt_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cobalt_try_fmt_vid_cap, + .vidioc_enum_output = cobalt_enum_output, + .vidioc_g_output = cobalt_g_output, + .vidioc_s_output = cobalt_s_output, + .vidioc_enum_fmt_vid_out = cobalt_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = cobalt_g_fmt_vid_out, + .vidioc_s_fmt_vid_out = cobalt_s_fmt_vid_out, + .vidioc_try_fmt_vid_out = cobalt_try_fmt_vid_out, + .vidioc_s_dv_timings = cobalt_s_dv_timings, + .vidioc_g_dv_timings = cobalt_g_dv_timings, + .vidioc_query_dv_timings = cobalt_query_dv_timings, + .vidioc_enum_dv_timings = cobalt_enum_dv_timings, + .vidioc_dv_timings_cap = cobalt_dv_timings_cap, + .vidioc_g_edid = cobalt_g_edid, + .vidioc_s_edid = cobalt_s_edid, + .vidioc_subscribe_event = cobalt_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cobalt_g_register, + .vidioc_s_register = cobalt_s_register, +#endif +}; + +static const struct v4l2_ioctl_ops cobalt_ioctl_empty_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = cobalt_g_register, + .vidioc_s_register = cobalt_s_register, +#endif +}; + +/* Register device nodes */ + +static const struct v4l2_file_operations cobalt_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +static const struct v4l2_file_operations cobalt_out_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .write = vb2_fop_write, +}; + +static const struct v4l2_file_operations cobalt_empty_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .unlocked_ioctl = video_ioctl2, + .release = v4l2_fh_release, +}; + +static int cobalt_node_register(struct cobalt *cobalt, int node) +{ + static const struct v4l2_dv_timings dv1080p60 = + V4L2_DV_BT_CEA_1920X1080P60; + struct cobalt_stream *s = cobalt->streams + node; + struct video_device *vdev = &s->vdev; + struct vb2_queue *q = &s->q; + int ret; + + mutex_init(&s->lock); + spin_lock_init(&s->irqlock); + + snprintf(vdev->name, sizeof(vdev->name), + "%s-%d", cobalt->v4l2_dev.name, node); + s->width = 1920; + /* Audio frames are just 4 lines of 1920 bytes */ + s->height = s->is_audio ? 4 : 1080; + + if (s->is_audio) { + s->bpp = 1; + s->pixfmt = V4L2_PIX_FMT_GREY; + } else if (s->is_output) { + s->bpp = COBALT_BYTES_PER_PIXEL_RGB32; + s->pixfmt = V4L2_PIX_FMT_BGR32; + } else { + s->bpp = COBALT_BYTES_PER_PIXEL_YUYV; + s->pixfmt = V4L2_PIX_FMT_YUYV; + } + s->colorspace = V4L2_COLORSPACE_SRGB; + s->stride = s->width * s->bpp; + + if (!s->is_audio) { + if (s->is_dummy) + cobalt_warn("Setting up dummy video node %d\n", node); + vdev->v4l2_dev = &cobalt->v4l2_dev; + if (s->is_dummy) + vdev->fops = &cobalt_empty_fops; + else + vdev->fops = s->is_output ? &cobalt_out_fops : + &cobalt_fops; + vdev->release = video_device_release_empty; + vdev->vfl_dir = s->is_output ? VFL_DIR_TX : VFL_DIR_RX; + vdev->lock = &s->lock; + if (s->sd) + vdev->ctrl_handler = s->sd->ctrl_handler; + s->timings = dv1080p60; + v4l2_subdev_call(s->sd, video, s_dv_timings, &s->timings); + if (!s->is_output && s->sd) + cobalt_enable_input(s); + vdev->ioctl_ops = s->is_dummy ? &cobalt_ioctl_empty_ops : + &cobalt_ioctl_ops; + } + + INIT_LIST_HEAD(&s->bufs); + q->type = s->is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT : + V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->io_modes |= s->is_output ? VB2_WRITE : VB2_READ; + q->drv_priv = s; + q->buf_struct_size = sizeof(struct cobalt_buffer); + q->ops = &cobalt_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &s->lock; + vdev->queue = q; + + video_set_drvdata(vdev, s); + ret = vb2_queue_init(q); + if (!s->is_audio && ret == 0) + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + else if (!s->is_dummy) + ret = cobalt_alsa_init(s); + + if (ret < 0) { + if (!s->is_audio) + cobalt_err("couldn't register v4l2 device node %d\n", + node); + return ret; + } + cobalt_info("registered node %d\n", node); + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cobalt_nodes_register(struct cobalt *cobalt) +{ + int node, ret; + + /* Setup V4L2 Devices */ + for (node = 0; node < COBALT_NUM_STREAMS; node++) { + ret = cobalt_node_register(cobalt, node); + if (ret) + return ret; + } + return 0; +} + +/* Unregister v4l2 devices */ +void cobalt_nodes_unregister(struct cobalt *cobalt) +{ + int node; + + /* Teardown all streams */ + for (node = 0; node < COBALT_NUM_STREAMS; node++) { + struct cobalt_stream *s = cobalt->streams + node; + struct video_device *vdev = &s->vdev; + + if (!s->is_audio) + video_unregister_device(vdev); + else if (!s->is_dummy) + cobalt_alsa_exit(s); + } +} diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.h b/drivers/media/pci/cobalt/cobalt-v4l2.h new file mode 100644 index 000000000..62be553cd --- /dev/null +++ b/drivers/media/pci/cobalt/cobalt-v4l2.h @@ -0,0 +1,22 @@ +/* + * cobalt V4L2 API + * + * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +int cobalt_nodes_register(struct cobalt *cobalt); +void cobalt_nodes_unregister(struct cobalt *cobalt); diff --git a/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h new file mode 100644 index 000000000..9bc9ef1fd --- /dev/null +++ b/drivers/media/pci/cobalt/m00233_video_measure_memmap_package.h @@ -0,0 +1,115 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H +#define M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00233_video_measure_regmap { + uint32_t irq_status; /* Reg 0x0000 */ + /* The vertical counter starts on rising edge of vsync */ + uint32_t vsync_time; /* Reg 0x0004 */ + uint32_t vback_porch; /* Reg 0x0008 */ + uint32_t vactive_area; /* Reg 0x000c */ + uint32_t vfront_porch; /* Reg 0x0010 */ + /* The horizontal counter starts on rising edge of hsync. */ + uint32_t hsync_time; /* Reg 0x0014 */ + uint32_t hback_porch; /* Reg 0x0018 */ + uint32_t hactive_area; /* Reg 0x001c */ + uint32_t hfront_porch; /* Reg 0x0020 */ + uint32_t control; /* Reg 0x0024, Default=0x0 */ + uint32_t irq_triggers; /* Reg 0x0028, Default=0xff */ + /* Value is given in number of register bus clock periods between */ + /* falling and rising edge of hsync. Must be non-zero. */ + uint32_t hsync_timeout_val; /* Reg 0x002c, Default=0x1fff */ + uint32_t status; /* Reg 0x0030 */ +}; + +#define M00233_VIDEO_MEASURE_REG_IRQ_STATUS_OFST 0 +#define M00233_VIDEO_MEASURE_REG_VSYNC_TIME_OFST 4 +#define M00233_VIDEO_MEASURE_REG_VBACK_PORCH_OFST 8 +#define M00233_VIDEO_MEASURE_REG_VACTIVE_AREA_OFST 12 +#define M00233_VIDEO_MEASURE_REG_VFRONT_PORCH_OFST 16 +#define M00233_VIDEO_MEASURE_REG_HSYNC_TIME_OFST 20 +#define M00233_VIDEO_MEASURE_REG_HBACK_PORCH_OFST 24 +#define M00233_VIDEO_MEASURE_REG_HACTIVE_AREA_OFST 28 +#define M00233_VIDEO_MEASURE_REG_HFRONT_PORCH_OFST 32 +#define M00233_VIDEO_MEASURE_REG_CONTROL_OFST 36 +#define M00233_VIDEO_MEASURE_REG_IRQ_TRIGGERS_OFST 40 +#define M00233_VIDEO_MEASURE_REG_HSYNC_TIMEOUT_VAL_OFST 44 +#define M00233_VIDEO_MEASURE_REG_STATUS_OFST 48 + +/******************************************************************* + * Bit Mask for register + * M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* irq_status [7:0] */ +#define M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_OFST (0) +#define M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VSYNC_TIME_OFST) +#define M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_OFST (1) +#define M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VBACK_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_OFST (2) +#define M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VACTIVE_AREA_OFST) +#define M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_OFST (3) +#define M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_VFRONT_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_OFST (4) +#define M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HSYNC_TIME_OFST) +#define M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_OFST (5) +#define M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HBACK_PORCH_OFST) +#define M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_OFST (6) +#define M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HACTIVE_AREA_OFST) +#define M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_OFST (7) +#define M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_MSK (0x1 << M00233_IRQ_STATUS_BITMAP_HFRONT_PORCH_OFST) +/* control [4:0] */ +#define M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (0) +#define M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00233_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (1) +#define M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00233_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +#define M00233_CONTROL_BITMAP_ENABLE_MEASURE_OFST (2) +#define M00233_CONTROL_BITMAP_ENABLE_MEASURE_MSK (0x1 << M00233_CONTROL_BITMAP_ENABLE_MEASURE_OFST) +#define M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_OFST (3) +#define M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_MSK (0x1 << M00233_CONTROL_BITMAP_ENABLE_INTERRUPT_OFST) +#define M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_OFST (4) +#define M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_MSK (0x1 << M00233_CONTROL_BITMAP_UPDATE_ON_HSYNC_OFST) +/* irq_triggers [7:0] */ +#define M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_OFST (0) +#define M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VSYNC_TIME_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_OFST (1) +#define M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VBACK_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_OFST (2) +#define M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VACTIVE_AREA_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_OFST (3) +#define M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_VFRONT_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_OFST (4) +#define M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HSYNC_TIME_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_OFST (5) +#define M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HBACK_PORCH_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_OFST (6) +#define M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HACTIVE_AREA_OFST) +#define M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_OFST (7) +#define M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_MSK (0x1 << M00233_IRQ_TRIGGERS_BITMAP_HFRONT_PORCH_OFST) +/* status [1:0] */ +#define M00233_STATUS_BITMAP_HSYNC_TIMEOUT_OFST (0) +#define M00233_STATUS_BITMAP_HSYNC_TIMEOUT_MSK (0x1 << M00233_STATUS_BITMAP_HSYNC_TIMEOUT_OFST) +#define M00233_STATUS_BITMAP_INIT_DONE_OFST (1) +#define M00233_STATUS_BITMAP_INIT_DONE_MSK (0x1 << M00233_STATUS_BITMAP_INIT_DONE_OFST) + +#endif /*M00233_VIDEO_MEASURE_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h new file mode 100644 index 000000000..a480529f5 --- /dev/null +++ b/drivers/media/pci/cobalt/m00235_fdma_packer_memmap_package.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00235_FDMA_PACKER_MEMMAP_PACKAGE_H +#define M00235_FDMA_PACKER_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00235_FDMA_PACKER_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00235_fdma_packer_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ +}; + +#define M00235_FDMA_PACKER_REG_CONTROL_OFST 0 + +/******************************************************************* + * Bit Mask for register + * M00235_FDMA_PACKER_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [3:0] */ +#define M00235_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00235_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00235_CONTROL_BITMAP_ENABLE_OFST) +#define M00235_CONTROL_BITMAP_PACK_FORMAT_OFST (1) +#define M00235_CONTROL_BITMAP_PACK_FORMAT_MSK (0x3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST) +#define M00235_CONTROL_BITMAP_ENDIAN_FORMAT_OFST (3) +#define M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK (0x1 << M00235_CONTROL_BITMAP_ENDIAN_FORMAT_OFST) + +#endif /*M00235_FDMA_PACKER_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h new file mode 100644 index 000000000..602419e58 --- /dev/null +++ b/drivers/media/pci/cobalt/m00389_cvi_memmap_package.h @@ -0,0 +1,59 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00389_CVI_MEMMAP_PACKAGE_H +#define M00389_CVI_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00389_CVI_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00389_cvi_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t frame_width; /* Reg 0x0004, Default=0x10 */ + uint32_t frame_height; /* Reg 0x0008, Default=0xc */ + uint32_t freewheel_period; /* Reg 0x000c, Default=0x0 */ + uint32_t error_color; /* Reg 0x0010, Default=0x0 */ + uint32_t status; /* Reg 0x0014 */ +}; + +#define M00389_CVI_REG_CONTROL_OFST 0 +#define M00389_CVI_REG_FRAME_WIDTH_OFST 4 +#define M00389_CVI_REG_FRAME_HEIGHT_OFST 8 +#define M00389_CVI_REG_FREEWHEEL_PERIOD_OFST 12 +#define M00389_CVI_REG_ERROR_COLOR_OFST 16 +#define M00389_CVI_REG_STATUS_OFST 20 + +/******************************************************************* + * Bit Mask for register + * M00389_CVI_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [2:0] */ +#define M00389_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00389_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00389_CONTROL_BITMAP_ENABLE_OFST) +#define M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (1) +#define M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00389_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (2) +#define M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00389_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +/* status [1:0] */ +#define M00389_STATUS_BITMAP_LOCK_OFST (0) +#define M00389_STATUS_BITMAP_LOCK_MSK (0x1 << M00389_STATUS_BITMAP_LOCK_OFST) +#define M00389_STATUS_BITMAP_ERROR_OFST (1) +#define M00389_STATUS_BITMAP_ERROR_MSK (0x1 << M00389_STATUS_BITMAP_ERROR_OFST) + +#endif /*M00389_CVI_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h new file mode 100644 index 000000000..95471c995 --- /dev/null +++ b/drivers/media/pci/cobalt/m00460_evcnt_memmap_package.h @@ -0,0 +1,44 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00460_EVCNT_MEMMAP_PACKAGE_H +#define M00460_EVCNT_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00460_EVCNT_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00460_evcnt_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t count; /* Reg 0x0004 */ +}; + +#define M00460_EVCNT_REG_CONTROL_OFST 0 +#define M00460_EVCNT_REG_COUNT_OFST 4 + +/******************************************************************* + * Bit Mask for register + * M00460_EVCNT_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [1:0] */ +#define M00460_CONTROL_BITMAP_ENABLE_OFST (0) +#define M00460_CONTROL_BITMAP_ENABLE_MSK (0x1 << M00460_CONTROL_BITMAP_ENABLE_OFST) +#define M00460_CONTROL_BITMAP_CLEAR_OFST (1) +#define M00460_CONTROL_BITMAP_CLEAR_MSK (0x1 << M00460_CONTROL_BITMAP_CLEAR_OFST) + +#endif /*M00460_EVCNT_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h new file mode 100644 index 000000000..384a3e156 --- /dev/null +++ b/drivers/media/pci/cobalt/m00473_freewheel_memmap_package.h @@ -0,0 +1,57 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00473_FREEWHEEL_MEMMAP_PACKAGE_H +#define M00473_FREEWHEEL_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00473_FREEWHEEL_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00473_freewheel_regmap { + uint32_t ctrl; /* Reg 0x0000, Default=0x0 */ + uint32_t status; /* Reg 0x0004 */ + uint32_t active_length; /* Reg 0x0008, Default=0x1fa400 */ + uint32_t total_length; /* Reg 0x000c, Default=0x31151b */ + uint32_t data_width; /* Reg 0x0010 */ + uint32_t output_color; /* Reg 0x0014, Default=0xffff */ + uint32_t clk_freq; /* Reg 0x0018 */ +}; + +#define M00473_FREEWHEEL_REG_CTRL_OFST 0 +#define M00473_FREEWHEEL_REG_STATUS_OFST 4 +#define M00473_FREEWHEEL_REG_ACTIVE_LENGTH_OFST 8 +#define M00473_FREEWHEEL_REG_TOTAL_LENGTH_OFST 12 +#define M00473_FREEWHEEL_REG_DATA_WIDTH_OFST 16 +#define M00473_FREEWHEEL_REG_OUTPUT_COLOR_OFST 20 +#define M00473_FREEWHEEL_REG_CLK_FREQ_OFST 24 + +/******************************************************************* + * Bit Mask for register + * M00473_FREEWHEEL_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* ctrl [1:0] */ +#define M00473_CTRL_BITMAP_ENABLE_OFST (0) +#define M00473_CTRL_BITMAP_ENABLE_MSK (0x1 << M00473_CTRL_BITMAP_ENABLE_OFST) +#define M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_OFST (1) +#define M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_MSK (0x1 << M00473_CTRL_BITMAP_FORCE_FREEWHEEL_MODE_OFST) +/* status [0:0] */ +#define M00473_STATUS_BITMAP_FREEWHEEL_MODE_OFST (0) +#define M00473_STATUS_BITMAP_FREEWHEEL_MODE_MSK (0x1 << M00473_STATUS_BITMAP_FREEWHEEL_MODE_OFST) + +#endif /*M00473_FREEWHEEL_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h new file mode 100644 index 000000000..2a029026b --- /dev/null +++ b/drivers/media/pci/cobalt/m00479_clk_loss_detector_memmap_package.h @@ -0,0 +1,53 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H +#define M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00479_clk_loss_detector_regmap { + /* Control module */ + uint32_t ctrl; /* Reg 0x0000, Default=0x0 */ + uint32_t status; /* Reg 0x0004 */ + /* Number of ref clk cycles before checking the clock under test */ + uint32_t ref_clk_cnt_val; /* Reg 0x0008, Default=0xc4 */ + /* Number of test clk cycles required in the ref_clk_cnt_val period + * to ensure that the test clock is performing as expected */ + uint32_t test_clk_cnt_val; /* Reg 0x000c, Default=0xa */ +}; + +#define M00479_CLK_LOSS_DETECTOR_REG_CTRL_OFST 0 +#define M00479_CLK_LOSS_DETECTOR_REG_STATUS_OFST 4 +#define M00479_CLK_LOSS_DETECTOR_REG_REF_CLK_CNT_VAL_OFST 8 +#define M00479_CLK_LOSS_DETECTOR_REG_TEST_CLK_CNT_VAL_OFST 12 + +/******************************************************************* + * Bit Mask for register + * M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* ctrl [0:0] */ +#define M00479_CTRL_BITMAP_ENABLE_OFST (0) +#define M00479_CTRL_BITMAP_ENABLE_MSK (0x1 << M00479_CTRL_BITMAP_ENABLE_OFST) +/* status [0:0] */ +#define M00479_STATUS_BITMAP_CLOCK_MISSING_OFST (0) +#define M00479_STATUS_BITMAP_CLOCK_MISSING_MSK (0x1 << M00479_STATUS_BITMAP_CLOCK_MISSING_OFST) + +#endif /*M00479_CLK_LOSS_DETECTOR_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h new file mode 100644 index 000000000..bdef2df5d --- /dev/null +++ b/drivers/media/pci/cobalt/m00514_syncgen_flow_evcnt_memmap_package.h @@ -0,0 +1,88 @@ +/* + * Copyright 2014-2015 Cisco Systems, Inc. and/or its affiliates. + * All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H +#define M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H + +/******************************************************************* + * Register Block + * M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_VHD_REGMAP + *******************************************************************/ +struct m00514_syncgen_flow_evcnt_regmap { + uint32_t control; /* Reg 0x0000, Default=0x0 */ + uint32_t sync_generator_h_sync_length; /* Reg 0x0004, Default=0x0 */ + uint32_t sync_generator_h_backporch_length; /* Reg 0x0008, Default=0x0 */ + uint32_t sync_generator_h_active_length; /* Reg 0x000c, Default=0x0 */ + uint32_t sync_generator_h_frontporch_length; /* Reg 0x0010, Default=0x0 */ + uint32_t sync_generator_v_sync_length; /* Reg 0x0014, Default=0x0 */ + uint32_t sync_generator_v_backporch_length; /* Reg 0x0018, Default=0x0 */ + uint32_t sync_generator_v_active_length; /* Reg 0x001c, Default=0x0 */ + uint32_t sync_generator_v_frontporch_length; /* Reg 0x0020, Default=0x0 */ + uint32_t error_color; /* Reg 0x0024, Default=0x0 */ + uint32_t rd_status; /* Reg 0x0028 */ + uint32_t rd_evcnt_count; /* Reg 0x002c */ +}; + +#define M00514_SYNCGEN_FLOW_EVCNT_REG_CONTROL_OFST 0 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_SYNC_LENGTH_OFST 4 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_BACKPORCH_LENGTH_OFST 8 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_ACTIVE_LENGTH_OFST 12 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_H_FRONTPORCH_LENGTH_OFST 16 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_SYNC_LENGTH_OFST 20 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_BACKPORCH_LENGTH_OFST 24 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_ACTIVE_LENGTH_OFST 28 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_SYNC_GENERATOR_V_FRONTPORCH_LENGTH_OFST 32 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_ERROR_COLOR_OFST 36 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_RD_STATUS_OFST 40 +#define M00514_SYNCGEN_FLOW_EVCNT_REG_RD_EVCNT_COUNT_OFST 44 + +/******************************************************************* + * Bit Mask for register + * M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_VHD_BITMAP + *******************************************************************/ +/* control [7:0] */ +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_OFST (0) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_MSK (0x1 << M00514_CONTROL_BITMAP_SYNC_GENERATOR_LOAD_PARAM_OFST) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_OFST (1) +#define M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_SYNC_GENERATOR_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_OFST (2) +#define M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_FLOW_CTRL_OUTPUT_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST (3) +#define M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_MSK (0x1 << M00514_CONTROL_BITMAP_HSYNC_POLARITY_LOW_OFST) +#define M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST (4) +#define M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_MSK (0x1 << M00514_CONTROL_BITMAP_VSYNC_POLARITY_LOW_OFST) +#define M00514_CONTROL_BITMAP_EVCNT_ENABLE_OFST (5) +#define M00514_CONTROL_BITMAP_EVCNT_ENABLE_MSK (0x1 << M00514_CONTROL_BITMAP_EVCNT_ENABLE_OFST) +#define M00514_CONTROL_BITMAP_EVCNT_CLEAR_OFST (6) +#define M00514_CONTROL_BITMAP_EVCNT_CLEAR_MSK (0x1 << M00514_CONTROL_BITMAP_EVCNT_CLEAR_OFST) +#define M00514_CONTROL_BITMAP_FORMAT_16_BPP_OFST (7) +#define M00514_CONTROL_BITMAP_FORMAT_16_BPP_MSK (0x1 << M00514_CONTROL_BITMAP_FORMAT_16_BPP_OFST) +/* error_color [23:0] */ +#define M00514_ERROR_COLOR_BITMAP_BLUE_OFST (0) +#define M00514_ERROR_COLOR_BITMAP_BLUE_MSK (0xff << M00514_ERROR_COLOR_BITMAP_BLUE_OFST) +#define M00514_ERROR_COLOR_BITMAP_GREEN_OFST (8) +#define M00514_ERROR_COLOR_BITMAP_GREEN_MSK (0xff << M00514_ERROR_COLOR_BITMAP_GREEN_OFST) +#define M00514_ERROR_COLOR_BITMAP_RED_OFST (16) +#define M00514_ERROR_COLOR_BITMAP_RED_MSK (0xff << M00514_ERROR_COLOR_BITMAP_RED_OFST) +/* rd_status [1:0] */ +#define M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_OFST (0) +#define M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_MSK (0x1 << M00514_RD_STATUS_BITMAP_FLOW_CTRL_NO_DATA_ERROR_OFST) +#define M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_OFST (1) +#define M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_MSK (0x1 << M00514_RD_STATUS_BITMAP_READY_BUFFER_FULL_OFST) + +#endif /*M00514_SYNCGEN_FLOW_EVCNT_MEMMAP_PACKAGE_H*/ diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index 5a55630d0..30bbe8d1e 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -945,14 +945,17 @@ static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int cx18_av_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); int HSC, VSC, Vsrc, Hsrc, filter, Vlines; int is_50Hz = !(state->std & V4L2_STD_525_60); - if (fmt->code != MEDIA_BUS_FMT_FIXED) + if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; fmt->field = V4L2_FIELD_INTERLACED; @@ -987,6 +990,9 @@ static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt return -ERANGE; } + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); VSC &= 0x1fff; @@ -1285,7 +1291,6 @@ static const struct v4l2_subdev_video_ops cx18_av_video_ops = { .s_std = cx18_av_s_std, .s_routing = cx18_av_s_video_routing, .s_stream = cx18_av_s_stream, - .s_mbus_fmt = cx18_av_s_mbus_fmt, }; static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { @@ -1295,12 +1300,17 @@ static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { .s_raw_fmt = cx18_av_s_raw_fmt, }; +static const struct v4l2_subdev_pad_ops cx18_av_pad_ops = { + .set_fmt = cx18_av_set_fmt, +}; + static const struct v4l2_subdev_ops cx18_av_ops = { .core = &cx18_av_general_ops, .tuner = &cx18_av_tuner_ops, .audio = &cx18_av_audio_ops, .video = &cx18_av_video_ops, .vbi = &cx18_av_vbi_ops, + .pad = &cx18_av_pad_ops, }; int cx18_av_probe(struct cx18 *cx) diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index 4aeb7c6b8..71227a155 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -93,13 +93,16 @@ static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *fmt = &format.format; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); + fmt->width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt->height = cxhdl->height; + fmt->code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 9de2958b5..4754fd135 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -786,11 +786,11 @@ static void cx18_init_struct2(struct cx18 *cx) { int i; - for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS - 1; i++) if (cx->card->video_inputs[i].video_type == 0) break; cx->nof_inputs = i; - for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS - 1; i++) if (cx->card->audio_inputs[i].audio_type == 0) break; cx->nof_audio_inputs = i; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 79aee30d5..55525af1f 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -267,7 +267,9 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct cx18_stream *s = &cx->streams[id->type]; int ret; int w, h; @@ -296,10 +298,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->vb_bytes_per_line = 1440; /* Packed */ } - mbus_fmt.width = cx->cxhdl.width = w; - mbus_fmt.height = cx->cxhdl.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); + format.format.width = cx->cxhdl.width = w; + format.format.height = cx->cxhdl.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return cx18_g_fmt_vid_cap(file, fh, fmt); } diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 0a91df2c9..aaf4e46ff 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -759,7 +759,7 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr) if (0 != ret) goto err; - inter->state[ci_nr - 1] = state; + inter->state[ci_nr - 1] = state; altera_hw_filt_init(config, ci_nr); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 36fad8178..ac9d2df69 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -572,7 +572,8 @@ static struct stb6100_config prof_8000_stb6100_config = { .refclock = 27000000, }; -static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int p8000_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -587,7 +588,7 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) } static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -616,7 +617,7 @@ static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, } static int dvbsky_s952_portc_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx23885_tsport *port = fe->dvb->priv; struct cx23885_dev *dev = port->dev; @@ -856,18 +857,12 @@ static struct mt2063_config terratec_mt2063_config[] = { }, }; -static const struct tda10071_config hauppauge_tda10071_config = { - .demod_i2c_addr = 0x05, - .tuner_i2c_addr = 0x54, +static const struct tda10071_platform_data hauppauge_tda10071_pdata = { + .clk = 40444000, /* 40.444 MHz */ .i2c_wr_max = 64, .ts_mode = TDA10071_TS_SERIAL, - .spec_inv = 0, - .xtal = 40444000, /* 40.444 MHz */ .pll_multiplier = 20, -}; - -static const struct a8293_config hauppauge_a8293_config = { - .i2c_addr = 0x0b, + .tuner_i2c_addr = 0x54, }; static const struct si2165_config hauppauge_hvr4400_si2165_config = { @@ -1190,8 +1185,10 @@ static int dvb_register(struct cx23885_tsport *port) struct i2c_board_info info; struct i2c_adapter *adapter; struct i2c_client *client_demod = NULL, *client_tuner = NULL; + struct i2c_client *client_sec = NULL; const struct m88ds3103_config *p_m88ds3103_config = NULL; - int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL; + int (*p_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) = NULL; int mfe_shared = 0; /* bus not shared by default */ int ret; @@ -1797,21 +1794,46 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage; break; - case CX23885_BOARD_HAUPPAUGE_HVR4400: + case CX23885_BOARD_HAUPPAUGE_HVR4400: { + struct tda10071_platform_data tda10071_pdata = hauppauge_tda10071_pdata; + struct a8293_platform_data a8293_pdata = {}; + i2c_bus = &dev->i2c_bus[0]; i2c_bus2 = &dev->i2c_bus[1]; switch (port->nr) { /* port b */ case 1: - fe0->dvb.frontend = dvb_attach(tda10071_attach, - &hauppauge_tda10071_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend == NULL) - break; - if (!dvb_attach(a8293_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_a8293_config)) + /* attach demod + tuner combo */ + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE); + info.addr = 0x05; + info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + fe0->dvb.frontend = tda10071_pdata.get_dvb_frontend(client_demod); + port->i2c_client_demod = client_demod; + + /* attach SEC */ + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); goto frontend_detach; + } + port->i2c_client_sec = client_sec; break; /* port c */ case 2: @@ -1829,17 +1851,46 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; - case CX23885_BOARD_HAUPPAUGE_STARBURST: + } + case CX23885_BOARD_HAUPPAUGE_STARBURST: { + struct tda10071_platform_data tda10071_pdata = hauppauge_tda10071_pdata; + struct a8293_platform_data a8293_pdata = {}; + i2c_bus = &dev->i2c_bus[0]; - fe0->dvb.frontend = dvb_attach(tda10071_attach, - &hauppauge_tda10071_config, - &i2c_bus->i2c_adap); - if (fe0->dvb.frontend != NULL) { - dvb_attach(a8293_attach, fe0->dvb.frontend, - &i2c_bus->i2c_adap, - &hauppauge_a8293_config); + + /* attach demod + tuner combo */ + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "tda10071_cx24118", I2C_NAME_SIZE); + info.addr = 0x05; + info.platform_data = &tda10071_pdata; + request_module("tda10071"); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; } + fe0->dvb.frontend = tda10071_pdata.get_dvb_frontend(client_demod); + port->i2c_client_demod = client_demod; + + /* attach SEC */ + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); + goto frontend_detach; + } + port->i2c_client_sec = client_sec; break; + } case CX23885_BOARD_DVBSKY_T9580: case CX23885_BOARD_DVBSKY_S950: i2c_bus = &dev->i2c_bus[0]; @@ -1857,6 +1908,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -1912,6 +1964,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -1957,6 +2010,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -1986,6 +2040,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -2031,6 +2086,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&ts2020_config, 0, sizeof(ts2020_config)); ts2020_config.fe = fe0->dvb.frontend; + ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "ts2020", I2C_NAME_SIZE); info.addr = 0x60; @@ -2093,6 +2149,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -2111,6 +2168,7 @@ static int dvb_register(struct cx23885_tsport *port) case CX23885_BOARD_HAUPPAUGE_HVR5525: switch (port->nr) { struct m88rs6000t_config m88rs6000t_config; + struct a8293_platform_data a8293_pdata = {}; /* port b - satellite */ case 1: @@ -2122,10 +2180,20 @@ static int dvb_register(struct cx23885_tsport *port) break; /* attach SEC */ - if (!dvb_attach(a8293_attach, fe0->dvb.frontend, - &dev->i2c_bus[0].i2c_adap, - &hauppauge_a8293_config)) + a8293_pdata.dvb_frontend = fe0->dvb.frontend; + memset(&info, 0, sizeof(info)); + strlcpy(info.type, "a8293", I2C_NAME_SIZE); + info.addr = 0x0b; + info.platform_data = &a8293_pdata; + request_module("a8293"); + client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info); + if (!client_sec || !client_sec->dev.driver) + goto frontend_detach; + if (!try_module_get(client_sec->dev.driver->owner)) { + i2c_unregister_device(client_sec); goto frontend_detach; + } + port->i2c_client_sec = client_sec; /* attach tuner */ memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config)); @@ -2172,6 +2240,7 @@ static int dvb_register(struct cx23885_tsport *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = fe0->dvb.frontend; + si2157_config.if_port = 1; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); info.addr = 0x60; @@ -2238,6 +2307,14 @@ static int dvb_register(struct cx23885_tsport *port) return 0; frontend_detach: + /* remove I2C client for SEC */ + client_sec = port->i2c_client_sec; + if (client_sec) { + module_put(client_sec->dev.driver->owner); + i2c_unregister_device(client_sec); + port->i2c_client_sec = NULL; + } + /* remove I2C client for tuner */ client_tuner = port->i2c_client_tuner; if (client_tuner) { @@ -2339,6 +2416,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) i2c_unregister_device(client); } + /* remove I2C client for SEC */ + client = port->i2c_client_sec; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + /* remove I2C client for tuner */ client = port->i2c_client_tuner; if (client) { diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 6f817d873..a6c45eb0a 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -144,7 +144,7 @@ static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) return ret; } -int f300_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +int f300_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { u8 buf[16]; diff --git a/drivers/media/pci/cx23885/cx23885-f300.h b/drivers/media/pci/cx23885/cx23885-f300.h index e73344c94..be14d7de7 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.h +++ b/drivers/media/pci/cx23885/cx23885-f300.h @@ -1,2 +1,2 @@ extern int f300_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index ddcfa4876..5cdaf6ec5 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -581,7 +581,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int err; dprintk(2, "%s()\n", __func__); @@ -600,10 +602,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, dev->width, dev->height, dev->field); - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); + /* set_fmt overwrites f->fmt.pix.field, restore it */ f->fmt.pix.field = dev->field; return 0; } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index aeda8d399..027ead438 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -304,11 +304,12 @@ struct cx23885_tsport { struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; + struct i2c_client *i2c_client_sec; struct i2c_client *i2c_client_ci; int (*set_frontend)(struct dvb_frontend *fe); int (*fe_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); }; struct cx23885_kernel_ir { diff --git a/drivers/media/pci/cx25821/cx25821-medusa-reg.h b/drivers/media/pci/cx25821/cx25821-medusa-reg.h index c98ac946b..2e10643a8 100644 --- a/drivers/media/pci/cx25821/cx25821-medusa-reg.h +++ b/drivers/media/pci/cx25821/cx25821-medusa-reg.h @@ -84,9 +84,9 @@ #define ABIST_BIN4_VGA3 0x01D4 #define ABIST_BIN5_VGA4 0x01D8 #define ABIST_BIN6_VGA5 0x01DC -#define ABIST_BIN7_VGA6 0x0x1E0 -#define ABIST_CLAMP_A 0x0x1E4 -#define ABIST_CLAMP_B 0x0x1E8 +#define ABIST_BIN7_VGA6 0x01E0 +#define ABIST_CLAMP_A 0x01E4 +#define ABIST_CLAMP_B 0x01E8 #define ABIST_CLAMP_C 0x01EC #define ABIST_CLAMP_D 0x01F0 #define ABIST_CLAMP_E 0x01F4 diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 3501be9f1..aab7cf4c9 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -519,6 +519,8 @@ void cx88_wakeup(struct cx88_core *core, buf = list_entry(q->active.next, struct cx88_buffer, list); v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.field = core->field; + buf->vb.v4l2_buf.sequence = q->count++; list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index b0347e9b5..6e9a75a0e 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -449,7 +449,7 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe, } static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -465,7 +465,7 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, } static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -481,7 +481,7 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, } static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev= fe->dvb->priv; struct cx88_core *core = dev->core; @@ -505,7 +505,7 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, } static int vp1027_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; @@ -897,7 +897,7 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) } static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, - fe_sec_tone_mode_t tone) + enum fe_sec_tone_mode tone) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; @@ -919,7 +919,7 @@ static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, } static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, - fe_sec_voltage_t voltage) + enum fe_sec_voltage voltage) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 98344540c..34f505744 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -173,7 +173,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, /* reset counter */ cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ dprintk( 1, "setting the interrupt mask\n" ); @@ -216,8 +216,6 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); cx8802_start_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; return 0; } @@ -260,7 +258,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) if (list_empty(&cx88q->active)) { dprintk( 1, "queue is empty - first active\n" ); list_add_tail(&buf->list, &cx88q->active); - buf->count = cx88q->count++; dprintk(1,"[%p/%d] %s - first active\n", buf, buf->vb.v4l2_buf.index, __func__); @@ -269,7 +266,6 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) dprintk( 1, "queue is not empty - append to active\n" ); prev = list_entry(cx88q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &cx88q->active); - buf->count = cx88q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk( 1, "[%p/%d] %s - append to active\n", buf, buf->vb.v4l2_buf.index, __func__); diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 32eb7fdb8..7510e80eb 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -59,7 +59,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, /* reset counter */ cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); @@ -102,8 +102,6 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); cx8800_start_vbi_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; return 0; } @@ -175,7 +173,6 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); cx8800_start_vbi_dma(dev, q, buf); - buf->count = q->count++; dprintk(2,"[%p/%d] vbi_queue - first active\n", buf, buf->vb.v4l2_buf.index); @@ -183,7 +180,6 @@ static void buffer_queue(struct vb2_buffer *vb) buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &q->active); - buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2,"[%p/%d] buffer_queue - append to active\n", buf, buf->vb.v4l2_buf.index); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index c9decd80b..400e5caef 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -370,7 +370,7 @@ static int start_video_dma(struct cx8800_dev *dev, /* reset counter */ cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); - q->count = 1; + q->count = 0; /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); @@ -410,7 +410,6 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(MO_VID_INTMSK, 0x0f0011); return 0; } -#endif static int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) @@ -423,11 +422,10 @@ static int restart_video_queue(struct cx8800_dev *dev, dprintk(2,"restart_queue [%p/%d]: restart dma\n", buf, buf->vb.v4l2_buf.index); start_video_dma(dev, q, buf); - list_for_each_entry(buf, &q->active, list) - buf->count = q->count++; } return 0; } +#endif /* ------------------------------------------------------------------ */ @@ -523,7 +521,6 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); - buf->count = q->count++; dprintk(2,"[%p/%d] buffer_queue - first active\n", buf, buf->vb.v4l2_buf.index); @@ -531,7 +528,6 @@ static void buffer_queue(struct vb2_buffer *vb) buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &q->active); - buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); dprintk(2, "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.v4l2_buf.index); @@ -771,6 +767,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index b9fe1ac24..785fe2e0d 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -327,7 +327,6 @@ struct cx88_buffer { /* cx88 specific */ unsigned int bpl; struct cx88_riscmem risc; - u32 count; }; struct cx88_dmaqueue { @@ -376,9 +375,10 @@ struct cx88_core { /* config info -- dvb */ #if IS_ENABLED(CONFIG_VIDEO_CX88_DVB) - int (*prev_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + int (*prev_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); #endif - void (*gate_ctrl)(struct cx88_core *core, int open); + void (*gate_ctrl)(struct cx88_core *core, int open); /* state info */ struct task_struct *kthread; diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9e3492e20..0ac2dd35f 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -1630,7 +1630,8 @@ fail1: printk(KERN_ERR "fail1\n"); if (dev->msi) pci_disable_msi(dev->pdev); - free_irq(dev->pdev->irq, dev); + if (stat == 0) + free_irq(dev->pdev->irq, dev); fail: printk(KERN_ERR "fail\n"); ddb_unmap(dev); diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index ed1171673..88915fb87 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -591,7 +591,8 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) return container_of(fe->dvb, struct dm1105_dev, dvb_adapter); } -static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int dm1105_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig new file mode 100644 index 000000000..5145e0dfa --- /dev/null +++ b/drivers/media/pci/dt3155/Kconfig @@ -0,0 +1,13 @@ +config VIDEO_DT3155 + tristate "DT3155 frame grabber" + depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on HAS_DMA + select VIDEOBUF2_DMA_CONTIG + default n + ---help--- + Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. + Say Y here if you have this hardware. + In doubt, say N. + + To compile this driver as a module, choose M here: the + module will be called dt3155. diff --git a/drivers/media/pci/dt3155/Makefile b/drivers/media/pci/dt3155/Makefile new file mode 100644 index 000000000..89fa637ec --- /dev/null +++ b/drivers/media/pci/dt3155/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_DT3155) += dt3155.o diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c new file mode 100644 index 000000000..8df634518 --- /dev/null +++ b/drivers/media/pci/dt3155/dt3155.c @@ -0,0 +1,631 @@ +/*************************************************************************** + * Copyright (C) 2006-2010 by Marin Mitov * + * mitov@issp.bas.bg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ + +#include <linux/module.h> +#include <linux/stringify.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-common.h> +#include <media/videobuf2-dma-contig.h> + +#include "dt3155.h" + +#define DT3155_DEVICE_ID 0x1223 + +/** + * read_i2c_reg - reads an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: pointer to byte the read data will be placed in + * + * returns: zero on success or error code + * + * This function starts reading the specified (by index) register + * and busy waits for the process to finish. The result is placed + * in a byte pointed by data. + */ +static int read_i2c_reg(void __iomem *addr, u8 index, u8 *data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_READ, addr + IIC_CSR2); + mmiowb(); + udelay(45); /* wait at least 43 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + tmp = ioread32(addr + IIC_CSR1); + if (tmp & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + *data = tmp >> 24; + return 0; +} + +/** + * write_i2c_reg - writes to an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: data to be written + * + * returns: zero on success or error code + * + * This function starts writing the specified (by index) register + * and busy waits for the process to finish. + */ +static int write_i2c_reg(void __iomem *addr, u8 index, u8 data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2); + mmiowb(); + udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + return 0; +} + +/** + * write_i2c_reg_nowait - writes to an internal i2c register + * + * @addr: dt3155 mmio base address + * @index: index (internal address) of register to read + * @data: data to be written + * + * This function starts writing the specified (by index) register + * and then returns. + */ +static void write_i2c_reg_nowait(void __iomem *addr, u8 index, u8 data) +{ + u32 tmp = index; + + iowrite32((tmp << 17) | IIC_WRITE | data, addr + IIC_CSR2); + mmiowb(); +} + +/** + * wait_i2c_reg - waits the read/write to finish + * + * @addr: dt3155 mmio base address + * + * returns: zero on success or error code + * + * This function waits reading/writing to finish. + */ +static int wait_i2c_reg(void __iomem *addr) +{ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + udelay(65); /* wait at least 63 usec for NEW_CYCLE to clear */ + if (ioread32(addr + IIC_CSR2) & NEW_CYCLE) + return -EIO; /* error: NEW_CYCLE not cleared */ + if (ioread32(addr + IIC_CSR1) & DIRECT_ABORT) { + /* reset DIRECT_ABORT bit */ + iowrite32(DIRECT_ABORT, addr + IIC_CSR1); + return -EIO; /* error: DIRECT_ABORT set */ + } + return 0; +} + +static int +dt3155_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) + +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vq); + unsigned size = pd->width * pd->height; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + if (fmt && fmt->fmt.pix.sizeimage < size) + return -EINVAL; + *num_planes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size; + alloc_ctxs[0] = pd->alloc_ctx; + return 0; +} + +static int dt3155_buf_prepare(struct vb2_buffer *vb) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue); + + vb2_set_plane_payload(vb, 0, pd->width * pd->height); + return 0; +} + +static int dt3155_start_streaming(struct vb2_queue *q, unsigned count) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(q); + struct vb2_buffer *vb = pd->curr_buf; + dma_addr_t dma_addr; + + pd->sequence = 0; + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + iowrite32(dma_addr, pd->regs + EVEN_DMA_START); + iowrite32(dma_addr + pd->width, pd->regs + ODD_DMA_START); + iowrite32(pd->width, pd->regs + EVEN_DMA_STRIDE); + iowrite32(pd->width, pd->regs + ODD_DMA_STRIDE); + /* enable interrupts, clear all irq flags */ + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | + FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN | CAP_CONT_EVEN | CAP_CONT_ODD, + pd->regs + CSR1); + wait_i2c_reg(pd->regs); + write_i2c_reg(pd->regs, CONFIG, pd->config); + write_i2c_reg(pd->regs, EVEN_CSR, CSR_ERROR | CSR_DONE); + write_i2c_reg(pd->regs, ODD_CSR, CSR_ERROR | CSR_DONE); + + /* start the board */ + write_i2c_reg(pd->regs, CSR2, pd->csr2 | BUSY_EVEN | BUSY_ODD); + return 0; +} + +static void dt3155_stop_streaming(struct vb2_queue *q) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(q); + struct vb2_buffer *vb; + + spin_lock_irq(&pd->lock); + /* stop the board */ + write_i2c_reg_nowait(pd->regs, CSR2, pd->csr2); + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1); + /* disable interrupts, clear all irq flags */ + iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, pd->regs + INT_CSR); + spin_unlock_irq(&pd->lock); + + /* + * It is not clear whether the DMA stops at once or whether it + * will finish the current frame or field first. To be on the + * safe side we wait a bit. + */ + msleep(45); + + spin_lock_irq(&pd->lock); + if (pd->curr_buf) { + vb2_buffer_done(pd->curr_buf, VB2_BUF_STATE_ERROR); + pd->curr_buf = NULL; + } + + while (!list_empty(&pd->dmaq)) { + vb = list_first_entry(&pd->dmaq, typeof(*vb), done_entry); + list_del(&vb->done_entry); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irq(&pd->lock); +} + +static void dt3155_buf_queue(struct vb2_buffer *vb) +{ + struct dt3155_priv *pd = vb2_get_drv_priv(vb->vb2_queue); + + /* pd->vidq.streaming = 1 when dt3155_buf_queue() is invoked */ + spin_lock_irq(&pd->lock); + if (pd->curr_buf) + list_add_tail(&vb->done_entry, &pd->dmaq); + else + pd->curr_buf = vb; + spin_unlock_irq(&pd->lock); +} + +static const struct vb2_ops q_ops = { + .queue_setup = dt3155_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = dt3155_buf_prepare, + .start_streaming = dt3155_start_streaming, + .stop_streaming = dt3155_stop_streaming, + .buf_queue = dt3155_buf_queue, +}; + +static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id) +{ + struct dt3155_priv *ipd = dev_id; + struct vb2_buffer *ivb; + dma_addr_t dma_addr; + u32 tmp; + + tmp = ioread32(ipd->regs + INT_CSR) & (FLD_START | FLD_END_ODD); + if (!tmp) + return IRQ_NONE; /* not our irq */ + if ((tmp & FLD_START) && !(tmp & FLD_END_ODD)) { + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START, + ipd->regs + INT_CSR); + return IRQ_HANDLED; /* start of field irq */ + } + tmp = ioread32(ipd->regs + CSR1) & (FLD_CRPT_EVEN | FLD_CRPT_ODD); + if (tmp) { + iowrite32(FIFO_EN | SRST | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN | + CAP_CONT_EVEN | CAP_CONT_ODD, + ipd->regs + CSR1); + mmiowb(); + } + + spin_lock(&ipd->lock); + if (ipd->curr_buf && !list_empty(&ipd->dmaq)) { + v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp); + ipd->curr_buf->v4l2_buf.sequence = ipd->sequence++; + ipd->curr_buf->v4l2_buf.field = V4L2_FIELD_NONE; + vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE); + + ivb = list_first_entry(&ipd->dmaq, typeof(*ivb), done_entry); + list_del(&ivb->done_entry); + ipd->curr_buf = ivb; + dma_addr = vb2_dma_contig_plane_dma_addr(ivb, 0); + iowrite32(dma_addr, ipd->regs + EVEN_DMA_START); + iowrite32(dma_addr + ipd->width, ipd->regs + ODD_DMA_START); + iowrite32(ipd->width, ipd->regs + EVEN_DMA_STRIDE); + iowrite32(ipd->width, ipd->regs + ODD_DMA_STRIDE); + mmiowb(); + } + + /* enable interrupts, clear all irq flags */ + iowrite32(FLD_START_EN | FLD_END_ODD_EN | FLD_START | + FLD_END_EVEN | FLD_END_ODD, ipd->regs + INT_CSR); + spin_unlock(&ipd->lock); + return IRQ_HANDLED; +} + +static const struct v4l2_file_operations dt3155_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll +}; + +static int dt3155_querycap(struct file *filp, void *p, + struct v4l2_capability *cap) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + strcpy(cap->driver, DT3155_NAME); + strcpy(cap->card, DT3155_NAME " frame grabber"); + sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int dt3155_enum_fmt_vid_cap(struct file *filp, + void *p, struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + f->pixelformat = V4L2_PIX_FMT_GREY; + strcpy(f->description, "8-bit Greyscale"); + return 0; +} + +static int dt3155_fmt_vid_cap(struct file *filp, void *p, struct v4l2_format *f) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + f->fmt.pix.width = pd->width; + f->fmt.pix.height = pd->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_GREY; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = f->fmt.pix.width; + f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + return 0; +} + +static int dt3155_g_std(struct file *filp, void *p, v4l2_std_id *norm) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + *norm = pd->std; + return 0; +} + +static int dt3155_s_std(struct file *filp, void *p, v4l2_std_id norm) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + if (pd->std == norm) + return 0; + if (vb2_is_busy(&pd->vidq)) + return -EBUSY; + pd->std = norm; + if (pd->std & V4L2_STD_525_60) { + pd->csr2 = VT_60HZ; + pd->width = 640; + pd->height = 480; + } else { + pd->csr2 = VT_50HZ; + pd->width = 768; + pd->height = 576; + } + return 0; +} + +static int dt3155_enum_input(struct file *filp, void *p, + struct v4l2_input *input) +{ + if (input->index > 3) + return -EINVAL; + if (input->index) + snprintf(input->name, sizeof(input->name), "VID%d", + input->index); + else + strlcpy(input->name, "J2/VID0", sizeof(input->name)); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = V4L2_STD_ALL; + input->status = 0; + return 0; +} + +static int dt3155_g_input(struct file *filp, void *p, unsigned int *i) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + *i = pd->input; + return 0; +} + +static int dt3155_s_input(struct file *filp, void *p, unsigned int i) +{ + struct dt3155_priv *pd = video_drvdata(filp); + + if (i > 3) + return -EINVAL; + pd->input = i; + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, (i << 6) | (i << 4) | SYNC_LVL_3); + return 0; +} + +static const struct v4l2_ioctl_ops dt3155_ioctl_ops = { + .vidioc_querycap = dt3155_querycap, + .vidioc_enum_fmt_vid_cap = dt3155_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = dt3155_fmt_vid_cap, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_g_std = dt3155_g_std, + .vidioc_s_std = dt3155_s_std, + .vidioc_enum_input = dt3155_enum_input, + .vidioc_g_input = dt3155_g_input, + .vidioc_s_input = dt3155_s_input, +}; + +static int dt3155_init_board(struct dt3155_priv *pd) +{ + struct pci_dev *pdev = pd->pdev; + int i; + u8 tmp = 0; + + pci_set_master(pdev); /* dt3155 needs it */ + + /* resetting the adapter */ + iowrite32(ADDR_ERR_ODD | ADDR_ERR_EVEN | FLD_CRPT_ODD | FLD_CRPT_EVEN | + FLD_DN_ODD | FLD_DN_EVEN, pd->regs + CSR1); + mmiowb(); + msleep(20); + + /* initializing adapter registers */ + iowrite32(FIFO_EN | SRST, pd->regs + CSR1); + mmiowb(); + iowrite32(0xEEEEEE01, pd->regs + EVEN_PIXEL_FMT); + iowrite32(0xEEEEEE01, pd->regs + ODD_PIXEL_FMT); + iowrite32(0x00000020, pd->regs + FIFO_TRIGER); + iowrite32(0x00000103, pd->regs + XFER_MODE); + iowrite32(0, pd->regs + RETRY_WAIT_CNT); + iowrite32(0, pd->regs + INT_CSR); + iowrite32(1, pd->regs + EVEN_FLD_MASK); + iowrite32(1, pd->regs + ODD_FLD_MASK); + iowrite32(0, pd->regs + MASK_LENGTH); + iowrite32(0x0005007C, pd->regs + FIFO_FLAG_CNT); + iowrite32(0x01010101, pd->regs + IIC_CLK_DUR); + mmiowb(); + + /* verifying that we have a DT3155 board (not just a SAA7116 chip) */ + read_i2c_reg(pd->regs, DT_ID, &tmp); + if (tmp != DT3155_ID) + return -ENODEV; + + /* initialize AD LUT */ + write_i2c_reg(pd->regs, AD_ADDR, 0); + for (i = 0; i < 256; i++) + write_i2c_reg(pd->regs, AD_LUT, i); + + /* initialize ADC references */ + /* FIXME: pos_ref & neg_ref depend on VT_50HZ */ + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); + write_i2c_reg(pd->regs, AD_ADDR, AD_POS_REF); + write_i2c_reg(pd->regs, AD_CMD, 34); + write_i2c_reg(pd->regs, AD_ADDR, AD_NEG_REF); + write_i2c_reg(pd->regs, AD_CMD, 0); + + /* initialize PM LUT */ + write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM); + for (i = 0; i < 256; i++) { + write_i2c_reg(pd->regs, PM_LUT_ADDR, i); + write_i2c_reg(pd->regs, PM_LUT_DATA, i); + } + write_i2c_reg(pd->regs, CONFIG, pd->config | PM_LUT_PGM | PM_LUT_SEL); + for (i = 0; i < 256; i++) { + write_i2c_reg(pd->regs, PM_LUT_ADDR, i); + write_i2c_reg(pd->regs, PM_LUT_DATA, i); + } + write_i2c_reg(pd->regs, CONFIG, pd->config); /* ACQ_MODE_EVEN */ + + /* select channel 1 for input and set sync level */ + write_i2c_reg(pd->regs, AD_ADDR, AD_CMD_REG); + write_i2c_reg(pd->regs, AD_CMD, VIDEO_CNL_1 | SYNC_CNL_1 | SYNC_LVL_3); + + /* disable all irqs, clear all irq flags */ + iowrite32(FLD_START | FLD_END_EVEN | FLD_END_ODD, + pd->regs + INT_CSR); + + return 0; +} + +static struct video_device dt3155_vdev = { + .name = DT3155_NAME, + .fops = &dt3155_fops, + .ioctl_ops = &dt3155_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, + .tvnorms = V4L2_STD_ALL, +}; + +static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct dt3155_priv *pd; + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (err) + return -ENODEV; + pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + err = v4l2_device_register(&pdev->dev, &pd->v4l2_dev); + if (err) + return err; + pd->vdev = dt3155_vdev; + pd->vdev.v4l2_dev = &pd->v4l2_dev; + video_set_drvdata(&pd->vdev, pd); /* for use in video_fops */ + pd->pdev = pdev; + pd->std = V4L2_STD_625_50; + pd->csr2 = VT_50HZ; + pd->width = 768; + pd->height = 576; + INIT_LIST_HEAD(&pd->dmaq); + mutex_init(&pd->mux); + pd->vdev.lock = &pd->mux; /* for locking v4l2_file_operations */ + pd->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pd->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + pd->vidq.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + pd->vidq.ops = &q_ops; + pd->vidq.mem_ops = &vb2_dma_contig_memops; + pd->vidq.drv_priv = pd; + pd->vidq.min_buffers_needed = 2; + pd->vidq.gfp_flags = GFP_DMA32; + pd->vidq.lock = &pd->mux; /* for locking v4l2_file_operations */ + pd->vdev.queue = &pd->vidq; + err = vb2_queue_init(&pd->vidq); + if (err < 0) + goto err_v4l2_dev_unreg; + pd->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(pd->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + err = PTR_ERR(pd->alloc_ctx); + goto err_v4l2_dev_unreg; + } + spin_lock_init(&pd->lock); + pd->config = ACQ_MODE_EVEN; + err = pci_enable_device(pdev); + if (err) + goto err_free_ctx; + err = pci_request_region(pdev, 0, pci_name(pdev)); + if (err) + goto err_pci_disable; + pd->regs = pci_iomap(pdev, 0, pci_resource_len(pd->pdev, 0)); + if (!pd->regs) { + err = -ENOMEM; + goto err_free_reg; + } + err = dt3155_init_board(pd); + if (err) + goto err_iounmap; + err = request_irq(pd->pdev->irq, dt3155_irq_handler_even, + IRQF_SHARED, DT3155_NAME, pd); + if (err) + goto err_iounmap; + err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1); + if (err) + goto err_free_irq; + dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor); + return 0; /* success */ + +err_free_irq: + free_irq(pd->pdev->irq, pd); +err_iounmap: + pci_iounmap(pdev, pd->regs); +err_free_reg: + pci_release_region(pdev, 0); +err_pci_disable: + pci_disable_device(pdev); +err_free_ctx: + vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); +err_v4l2_dev_unreg: + v4l2_device_unregister(&pd->v4l2_dev); + return err; +} + +static void dt3155_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv, + v4l2_dev); + + video_unregister_device(&pd->vdev); + free_irq(pd->pdev->irq, pd); + vb2_queue_release(&pd->vidq); + v4l2_device_unregister(&pd->v4l2_dev); + pci_iounmap(pdev, pd->regs); + pci_release_region(pdev, 0); + pci_disable_device(pdev); + vb2_dma_contig_cleanup_ctx(pd->alloc_ctx); +} + +static const struct pci_device_id pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) }, + { 0, /* zero marks the end */ }, +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver pci_driver = { + .name = DT3155_NAME, + .id_table = pci_ids, + .probe = dt3155_probe, + .remove = dt3155_remove, +}; + +module_pci_driver(pci_driver); + +MODULE_DESCRIPTION("video4linux pci-driver for dt3155 frame grabber"); +MODULE_AUTHOR("Marin Mitov <mitov@issp.bas.bg>"); +MODULE_VERSION(DT3155_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/dt3155/dt3155.h b/drivers/media/pci/dt3155/dt3155.h new file mode 100644 index 000000000..4e1f4d598 --- /dev/null +++ b/drivers/media/pci/dt3155/dt3155.h @@ -0,0 +1,196 @@ +/*************************************************************************** + * Copyright (C) 2006-2010 by Marin Mitov * + * mitov@issp.bas.bg * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + ***************************************************************************/ + +/* DT3155 header file */ +#ifndef _DT3155_H_ +#define _DT3155_H_ + +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <media/v4l2-device.h> +#include <media/v4l2-dev.h> + +#define DT3155_NAME "dt3155" +#define DT3155_VER_MAJ 2 +#define DT3155_VER_MIN 0 +#define DT3155_VER_EXT 0 +#define DT3155_VERSION __stringify(DT3155_VER_MAJ) "." \ + __stringify(DT3155_VER_MIN) "." \ + __stringify(DT3155_VER_EXT) + +/* DT3155 Base Register offsets (memory mapped) */ +#define EVEN_DMA_START 0x00 +#define ODD_DMA_START 0x0C +#define EVEN_DMA_STRIDE 0x18 +#define ODD_DMA_STRIDE 0x24 +#define EVEN_PIXEL_FMT 0x30 +#define ODD_PIXEL_FMT 0x34 +#define FIFO_TRIGER 0x38 +#define XFER_MODE 0x3C +#define CSR1 0x40 +#define RETRY_WAIT_CNT 0x44 +#define INT_CSR 0x48 +#define EVEN_FLD_MASK 0x4C +#define ODD_FLD_MASK 0x50 +#define MASK_LENGTH 0x54 +#define FIFO_FLAG_CNT 0x58 +#define IIC_CLK_DUR 0x5C +#define IIC_CSR1 0x60 +#define IIC_CSR2 0x64 + +/* DT3155 Internal Registers indexes (i2c/IIC mapped) */ +#define CSR2 0x10 +#define EVEN_CSR 0x11 +#define ODD_CSR 0x12 +#define CONFIG 0x13 +#define DT_ID 0x1F +#define X_CLIP_START 0x20 +#define Y_CLIP_START 0x22 +#define X_CLIP_END 0x24 +#define Y_CLIP_END 0x26 +#define AD_ADDR 0x30 +#define AD_LUT 0x31 +#define AD_CMD 0x32 +#define DIG_OUT 0x40 +#define PM_LUT_ADDR 0x50 +#define PM_LUT_DATA 0x51 + +/* AD command register values */ +#define AD_CMD_REG 0x00 +#define AD_POS_REF 0x01 +#define AD_NEG_REF 0x02 + +/* CSR1 bit masks */ +#define RANGE_EN 0x00008000 +#define CRPT_DIS 0x00004000 +#define ADDR_ERR_ODD 0x00000800 +#define ADDR_ERR_EVEN 0x00000400 +#define FLD_CRPT_ODD 0x00000200 +#define FLD_CRPT_EVEN 0x00000100 +#define FIFO_EN 0x00000080 +#define SRST 0x00000040 +#define FLD_DN_ODD 0x00000020 +#define FLD_DN_EVEN 0x00000010 +/* These should not be used. + * Use CAP_CONT_ODD/EVEN instead +#define CAP_SNGL_ODD 0x00000008 +#define CAP_SNGL_EVEN 0x00000004 +*/ +#define CAP_CONT_ODD 0x00000002 +#define CAP_CONT_EVEN 0x00000001 + +/* INT_CSR bit masks */ +#define FLD_START_EN 0x00000400 +#define FLD_END_ODD_EN 0x00000200 +#define FLD_END_EVEN_EN 0x00000100 +#define FLD_START 0x00000004 +#define FLD_END_ODD 0x00000002 +#define FLD_END_EVEN 0x00000001 + +/* IIC_CSR1 bit masks */ +#define DIRECT_ABORT 0x00000200 + +/* IIC_CSR2 bit masks */ +#define NEW_CYCLE 0x01000000 +#define DIR_RD 0x00010000 +#define IIC_READ 0x01010000 +#define IIC_WRITE 0x01000000 + +/* CSR2 bit masks */ +#define DISP_PASS 0x40 +#define BUSY_ODD 0x20 +#define BUSY_EVEN 0x10 +#define SYNC_PRESENT 0x08 +#define VT_50HZ 0x04 +#define SYNC_SNTL 0x02 +#define CHROM_FILT 0x01 +#define VT_60HZ 0x00 + +/* CSR_EVEN/ODD bit masks */ +#define CSR_ERROR 0x04 +#define CSR_SNGL 0x02 +#define CSR_DONE 0x01 + +/* CONFIG bit masks */ +#define PM_LUT_PGM 0x80 +#define PM_LUT_SEL 0x40 +#define CLIP_EN 0x20 +#define HSCALE_EN 0x10 +#define EXT_TRIG_UP 0x0C +#define EXT_TRIG_DOWN 0x04 +#define ACQ_MODE_NEXT 0x02 +#define ACQ_MODE_ODD 0x01 +#define ACQ_MODE_EVEN 0x00 + +/* AD_CMD bit masks */ +#define VIDEO_CNL_1 0x00 +#define VIDEO_CNL_2 0x40 +#define VIDEO_CNL_3 0x80 +#define VIDEO_CNL_4 0xC0 +#define SYNC_CNL_1 0x00 +#define SYNC_CNL_2 0x10 +#define SYNC_CNL_3 0x20 +#define SYNC_CNL_4 0x30 +#define SYNC_LVL_1 0x00 +#define SYNC_LVL_2 0x04 +#define SYNC_LVL_3 0x08 +#define SYNC_LVL_4 0x0C + +/* DT3155 identificator */ +#define DT3155_ID 0x20 + +/* per board private data structure */ +/** + * struct dt3155_priv - private data structure + * + * @v4l2_dev: v4l2_device structure + * @vdev: video_device structure + * @pdev: pointer to pci_dev structure + * @vidq: vb2_queue structure + * @alloc_ctx: dma_contig allocation context + * @curr_buf: pointer to curren buffer + * @mux: mutex to protect the instance + * @dmaq: queue for dma buffers + * @lock: spinlock for dma queue + * @std: input standard + * @width: frame width + * @height: frame height + * @input: current input + * @sequence: frame counter + * @stats: statistics structure + * @regs: local copy of mmio base register + * @csr2: local copy of csr2 register + * @config: local copy of config register + */ +struct dt3155_priv { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pci_dev *pdev; + struct vb2_queue vidq; + struct vb2_alloc_ctx *alloc_ctx; + struct vb2_buffer *curr_buf; + struct mutex mux; + struct list_head dmaq; + spinlock_t lock; + v4l2_std_id std; + unsigned width, height; + unsigned input; + unsigned int sequence; + void __iomem *regs; + u8 csr2, config; +}; + +#endif /* _DT3155_H_ */ diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index dd6ee57e3..6e5867c57 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -57,5 +57,8 @@ config VIDEO_FB_IVTV This is used in the Hauppauge PVR-350 card. There is a driver homepage at <http://www.ivtvdriver.org>. + In order to use this module, you will need to boot with PAT disabled + on x86 systems, using the nopat kernel parameter. + To compile this driver as a module, choose M here: the module will be called ivtvfb. diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c index ccf548c25..8a55ccb8f 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.c +++ b/drivers/media/pci/ivtv/ivtv-controls.c @@ -64,13 +64,15 @@ static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); + format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + format.format.height = cxhdl->height; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index cb567aa60..5c5ba4b2f 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -805,11 +805,11 @@ static void ivtv_init_struct2(struct ivtv *itv) { int i; - for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++) + for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS - 1; i++) if (itv->card->video_inputs[i].video_type == 0) break; itv->nof_inputs = i; - for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++) + for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS - 1; i++) if (itv->card->audio_inputs[i].audio_type == 0) break; itv->nof_audio_inputs = i; diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index e8b6c7ad2..ee0ef6e48 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -830,7 +830,8 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv) do { \ struct v4l2_subdev *__sd; \ __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ + !(hw) ? true : (__sd->grp_id & (hw)), \ + o, f, ##args); \ } while (0) #define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args) diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 6fe6c4a0e..9a21c17fc 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -581,7 +581,9 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -599,10 +601,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f itv->cxhdl.height = h; if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) fmt->fmt.pix.width /= 2; - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); + format.format.width = fmt->fmt.pix.width; + format.format.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return ivtv_g_fmt_vid_cap(file, fh, fmt); } @@ -1529,7 +1531,8 @@ static int ivtv_log_status(struct file *file, void *fh) ivtv_get_audio_input(itv, itv->audio_input, &audin); IVTV_INFO("Video Input: %s\n", vidin.name); IVTV_INFO("Audio Input: %s%s\n", audin.name, - (itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : ""); + itv->dualwatch_stereo_mode == V4L2_MPEG_AUDIO_MODE_DUAL ? + " (Bilingual)" : ""); if (has_output) { struct v4l2_output vidout; struct v4l2_audioout audout; diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 9ff123019..8b95eefb6 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -38,14 +38,16 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/kernel.h> #include <linux/fb.h> #include <linux/ivtvfb.h> #include <linux/slab.h> -#ifdef CONFIG_MTRR -#include <asm/mtrr.h> +#ifdef CONFIG_X86_64 +#include <asm/pat.h> #endif #include "ivtv-driver.h" @@ -155,12 +157,11 @@ struct osd_info { /* Buffer size */ u32 video_buffer_size; -#ifdef CONFIG_MTRR /* video_base rounded down as required by hardware MTRRs */ unsigned long fb_start_aligned_physaddr; /* video_base rounded up as required by hardware MTRRs */ unsigned long fb_end_aligned_physaddr; -#endif + int wc_cookie; /* Store the buffer offset */ int set_osd_coords_x; @@ -1099,6 +1100,8 @@ static int ivtvfb_init_vidmode(struct ivtv *itv) static int ivtvfb_init_io(struct ivtv *itv) { struct osd_info *oi = itv->osd_info; + /* Find the largest power of two that maps the whole buffer */ + int size_shift = 31; mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { @@ -1132,29 +1135,16 @@ static int ivtvfb_init_io(struct ivtv *itv) oi->video_pbase, oi->video_vbase, oi->video_buffer_size / 1024); -#ifdef CONFIG_MTRR - { - /* Find the largest power of two that maps the whole buffer */ - int size_shift = 31; - - while (!(oi->video_buffer_size & (1 << size_shift))) { - size_shift--; - } - size_shift++; - oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); - oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; - oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; - oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); - if (mtrr_add(oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr, - MTRR_TYPE_WRCOMB, 1) < 0) { - IVTVFB_INFO("disabled mttr\n"); - oi->fb_start_aligned_physaddr = 0; - oi->fb_end_aligned_physaddr = 0; - } - } -#endif - + while (!(oi->video_buffer_size & (1 << size_shift))) + size_shift--; + size_shift++; + oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1); + oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size; + oi->fb_end_aligned_physaddr += (1 << size_shift) - 1; + oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1); + oi->wc_cookie = arch_phys_wc_add(oi->fb_start_aligned_physaddr, + oi->fb_end_aligned_physaddr - + oi->fb_start_aligned_physaddr); /* Blank the entire osd. */ memset_io(oi->video_vbase, 0, oi->video_buffer_size); @@ -1172,14 +1162,7 @@ static void ivtvfb_release_buffers (struct ivtv *itv) /* Release pseudo palette */ kfree(oi->ivtvfb_info.pseudo_palette); - -#ifdef CONFIG_MTRR - if (oi->fb_end_aligned_physaddr) { - mtrr_del(-1, oi->fb_start_aligned_physaddr, - oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr); - } -#endif - + arch_phys_wc_del(oi->wc_cookie); kfree(oi); itv->osd_info = NULL; } @@ -1190,6 +1173,13 @@ static int ivtvfb_init_card(struct ivtv *itv) { int rc; +#ifdef CONFIG_X86_64 + if (pat_enabled()) { + pr_warn("ivtvfb needs PAT disabled, boot with nopat kernel parameter\n"); + return -ENODEV; + } +#endif + if (itv->osd_info) { IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id); return -EBUSY; @@ -1284,6 +1274,7 @@ static int __init ivtvfb_init(void) int registered = 0; int err; + if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) { printk(KERN_ERR "ivtvfb: ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n", IVTV_MAX_CARDS - 1); diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 104914a5b..68b580003 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -106,6 +106,10 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_IRQ1) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + spin_lock(&mantis->intmask_lock); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, + MANTIS_INT_MASK); + spin_unlock(&mantis->intmask_lock); schedule_work(&mantis->uart_work); } if (stat & MANTIS_INT_OCERR) { @@ -154,6 +158,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) static int hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; int err = 0; @@ -165,12 +170,16 @@ static int hopper_pci_probe(struct pci_dev *pdev, goto fail0; } + drvdata = (void *)pci_id->driver_data; mantis->num = devs; mantis->verbose = verbose; mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; + config = drvdata->hwconfig; config->irq_handler = &hopper_irq_handler; mantis->hwconfig = config; + mantis->rc_map_name = drvdata->rc_map_name; + + spin_lock_init(&mantis->intmask_lock); err = mantis_pci_init(mantis); if (err) { @@ -247,7 +256,8 @@ static void hopper_pci_remove(struct pci_dev *pdev) } static struct pci_device_id hopper_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config, + NULL), { } }; diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index 801fc55b6..cdefffc16 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <asm/irq.h> #include <linux/interrupt.h> +#include <media/rc-map.h> #include "dmxdev.h" #include "dvbdev.h" @@ -49,6 +50,7 @@ #include "mantis_pci.h" #include "mantis_i2c.h" #include "mantis_reg.h" +#include "mantis_input.h" static unsigned int verbose; module_param(verbose, int, 0644); @@ -114,6 +116,10 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) } if (stat & MANTIS_INT_IRQ1) { dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + spin_lock(&mantis->intmask_lock); + mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ1, + MANTIS_INT_MASK); + spin_unlock(&mantis->intmask_lock); schedule_work(&mantis->uart_work); } if (stat & MANTIS_INT_OCERR) { @@ -162,6 +168,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) static int mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { + struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; int err = 0; @@ -169,84 +176,91 @@ static int mantis_pci_probe(struct pci_dev *pdev, mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (mantis == NULL) { printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); - err = -ENOMEM; - goto fail0; + return -ENOMEM; } + drvdata = (void *)pci_id->driver_data; mantis->num = devs; mantis->verbose = verbose; mantis->pdev = pdev; - config = (struct mantis_hwconfig *) pci_id->driver_data; + config = drvdata->hwconfig; config->irq_handler = &mantis_irq_handler; mantis->hwconfig = config; + mantis->rc_map_name = drvdata->rc_map_name; + + spin_lock_init(&mantis->intmask_lock); err = mantis_pci_init(mantis); if (err) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); - goto fail1; + goto err_free_mantis; } err = mantis_stream_control(mantis, STREAM_TO_HIF); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); - goto fail1; + goto err_pci_exit; } err = mantis_i2c_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); - goto fail2; + goto err_pci_exit; } err = mantis_get_mac(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); - goto fail2; + goto err_i2c_exit; } err = mantis_dma_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); - goto fail3; + goto err_i2c_exit; } err = mantis_dvb_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); - goto fail4; + goto err_dma_exit; + } + + err = mantis_input_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, + "ERROR: Mantis DVB initialization failed <%d>", err); + goto err_dvb_exit; } + err = mantis_uart_init(mantis); if (err < 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); - goto fail6; + goto err_input_exit; } devs++; - return err; + return 0; +err_input_exit: + mantis_input_exit(mantis); - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); - mantis_uart_exit(mantis); +err_dvb_exit: + mantis_dvb_exit(mantis); -fail6: -fail4: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); +err_dma_exit: mantis_dma_exit(mantis); -fail3: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); +err_i2c_exit: mantis_i2c_exit(mantis); -fail2: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); +err_pci_exit: mantis_pci_exit(mantis); -fail1: - dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); +err_free_mantis: kfree(mantis); -fail0: return err; } @@ -257,6 +271,7 @@ static void mantis_pci_remove(struct pci_dev *pdev) if (mantis) { mantis_uart_exit(mantis); + mantis_input_exit(mantis); mantis_dvb_exit(mantis); mantis_dma_exit(mantis); mantis_i2c_exit(mantis); @@ -267,17 +282,28 @@ static void mantis_pci_remove(struct pci_dev *pdev) } static struct pci_device_id mantis_pci_table[] = { - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config), - MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config), - MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config), - MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config), - MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config), - MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), + MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config, + RC_MAP_TECHNISAT_TS35), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_10, &vp1041_config, + NULL), + MAKE_ENTRY(TECHNISAT, SKYSTAR_HD2_20, &vp1041_config, + NULL), + MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config, + RC_MAP_TERRATEC_CINERGY_C_PCI), + MAKE_ENTRY(TERRATEC, CINERGY_S2_PCI_HD, &vp1041_config, + RC_MAP_TERRATEC_CINERGY_S2_HD), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1033_DVB_S, &vp1033_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1034_DVB_S, &vp1034_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_1041_DVB_S2, &vp1041_config, + RC_MAP_TWINHAN_DTV_CAB_CI), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config, + RC_MAP_TWINHAN_DTV_CAB_CI), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config, + NULL), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config, + NULL), { } }; diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index 8ff448bb7..d48778a36 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -25,6 +25,7 @@ #include <linux/mutex.h> #include <linux/workqueue.h> +#include "mantis_reg.h" #include "mantis_uart.h" #include "mantis_link.h" @@ -68,12 +69,13 @@ #define TECHNISAT 0x1ae4 #define TERRATEC 0x153b -#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ +#define MAKE_ENTRY(__subven, __subdev, __configptr, __rc) { \ .vendor = TWINHAN_TECHNOLOGIES, \ .device = MANTIS, \ .subvendor = (__subven), \ .subdevice = (__subdev), \ - .driver_data = (unsigned long) (__configptr) \ + .driver_data = (unsigned long) \ + &(struct mantis_pci_drvdata){__configptr, __rc} \ } enum mantis_i2c_mode { @@ -101,6 +103,11 @@ struct mantis_hwconfig { enum mantis_i2c_mode i2c_mode; }; +struct mantis_pci_drvdata { + struct mantis_hwconfig *hwconfig; + char *rc_map_name; +}; + struct mantis_pci { unsigned int verbose; @@ -131,6 +138,7 @@ struct mantis_pci { dma_addr_t risc_dma; struct tasklet_struct tasklet; + spinlock_t intmask_lock; struct i2c_adapter adapter; int i2c_rc; @@ -165,15 +173,32 @@ struct mantis_pci { struct mantis_ca *mantis_ca; - wait_queue_head_t uart_wq; struct work_struct uart_work; - spinlock_t uart_lock; struct rc_dev *rc; char input_name[80]; char input_phys[80]; + char *rc_map_name; }; #define MANTIS_HIF_STATUS (mantis->gpio_status) +static inline void mantis_mask_ints(struct mantis_pci *mantis, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&mantis->intmask_lock, flags); + mmwrite(mmread(MANTIS_INT_MASK) & ~mask, MANTIS_INT_MASK); + spin_unlock_irqrestore(&mantis->intmask_lock, flags); +} + +static inline void mantis_unmask_ints(struct mantis_pci *mantis, u32 mask) +{ + unsigned long flags; + + spin_lock_irqsave(&mantis->intmask_lock, flags); + mmwrite(mmread(MANTIS_INT_MASK) | mask, MANTIS_INT_MASK); + spin_unlock_irqrestore(&mantis->intmask_lock, flags); +} + #endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c index 566c40717..87990ece5 100644 --- a/drivers/media/pci/mantis/mantis_dma.c +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -130,10 +130,11 @@ err: int mantis_dma_init(struct mantis_pci *mantis) { - int err = 0; + int err; dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); - if (mantis_alloc_buffers(mantis) < 0) { + err = mantis_alloc_buffers(mantis); + if (err < 0) { dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); /* Stop RISC Engine */ @@ -190,7 +191,7 @@ void mantis_dma_start(struct mantis_pci *mantis) mmwrite(0, MANTIS_DMA_CTL); mantis->last_block = mantis->busy_block = 0; - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + mantis_unmask_ints(mantis, MANTIS_INT_RISCI); mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN | MANTIS_RISC_EN, MANTIS_DMA_CTL); @@ -209,8 +210,7 @@ void mantis_dma_stop(struct mantis_pci *mantis) mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); - mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | - MANTIS_INT_RISCEN), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_RISCI | MANTIS_INT_RISCEN); } diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index 895ddba3c..d72ee47dc 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -219,7 +219,7 @@ static struct i2c_algorithm mantis_algo = { int mantis_i2c_init(struct mantis_pci *mantis) { - u32 intstat, intmask; + u32 intstat; struct i2c_adapter *i2c_adapter = &mantis->adapter; struct pci_dev *pdev = mantis->pdev; @@ -242,11 +242,10 @@ int mantis_i2c_init(struct mantis_pci *mantis) dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); intstat = mmread(MANTIS_INT_STAT); - intmask = mmread(MANTIS_INT_MASK); + mmread(MANTIS_INT_MASK); mmwrite(intstat, MANTIS_INT_STAT); dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); return 0; } @@ -254,11 +253,8 @@ EXPORT_SYMBOL_GPL(mantis_i2c_init); int mantis_i2c_exit(struct mantis_pci *mantis) { - u32 intmask; - dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt"); - intmask = mmread(MANTIS_INT_MASK); - mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_I2CDONE); dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); i2c_del_adapter(&mantis->adapter); diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c index 0e5252e5c..7f7f1d4d7 100644 --- a/drivers/media/pci/mantis/mantis_input.c +++ b/drivers/media/pci/mantis/mantis_input.c @@ -12,14 +12,8 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if 0 /* Currently unused */ - #include <media/rc-core.h> #include <linux/pci.h> @@ -30,100 +24,32 @@ #include "dvb_net.h" #include "mantis_common.h" -#include "mantis_reg.h" -#include "mantis_uart.h" +#include "mantis_input.h" #define MODULE_NAME "mantis_core" -#define RC_MAP_MANTIS "rc-mantis" - -static struct rc_map_table mantis_ir_table[] = { - { 0x29, KEY_POWER }, - { 0x28, KEY_FAVORITES }, - { 0x30, KEY_TEXT }, - { 0x17, KEY_INFO }, /* Preview */ - { 0x23, KEY_EPG }, - { 0x3b, KEY_F22 }, /* Record List */ - { 0x3c, KEY_1 }, - { 0x3e, KEY_2 }, - { 0x39, KEY_3 }, - { 0x36, KEY_4 }, - { 0x22, KEY_5 }, - { 0x20, KEY_6 }, - { 0x32, KEY_7 }, - { 0x26, KEY_8 }, - { 0x24, KEY_9 }, - { 0x2a, KEY_0 }, - - { 0x33, KEY_CANCEL }, - { 0x2c, KEY_BACK }, - { 0x15, KEY_CLEAR }, - { 0x3f, KEY_TAB }, - { 0x10, KEY_ENTER }, - { 0x14, KEY_UP }, - { 0x0d, KEY_RIGHT }, - { 0x0e, KEY_DOWN }, - { 0x11, KEY_LEFT }, - - { 0x21, KEY_VOLUMEUP }, - { 0x35, KEY_VOLUMEDOWN }, - { 0x3d, KEY_CHANNELDOWN }, - { 0x3a, KEY_CHANNELUP }, - { 0x2e, KEY_RECORD }, - { 0x2b, KEY_PLAY }, - { 0x13, KEY_PAUSE }, - { 0x25, KEY_STOP }, - - { 0x1f, KEY_REWIND }, - { 0x2d, KEY_FASTFORWARD }, - { 0x1e, KEY_PREVIOUS }, /* Replay |< */ - { 0x1d, KEY_NEXT }, /* Skip >| */ - - { 0x0b, KEY_CAMERA }, /* Capture */ - { 0x0f, KEY_LANGUAGE }, /* SAP */ - { 0x18, KEY_MODE }, /* PIP */ - { 0x12, KEY_ZOOM }, /* Full screen */ - { 0x1c, KEY_SUBTITLE }, - { 0x2f, KEY_MUTE }, - { 0x16, KEY_F20 }, /* L/R */ - { 0x38, KEY_F21 }, /* Hibernate */ - - { 0x37, KEY_SWITCHVIDEOMODE }, /* A/V */ - { 0x31, KEY_AGAIN }, /* Recall */ - { 0x1a, KEY_KPPLUS }, /* Zoom+ */ - { 0x19, KEY_KPMINUS }, /* Zoom- */ - { 0x27, KEY_RED }, - { 0x0C, KEY_GREEN }, - { 0x01, KEY_YELLOW }, - { 0x00, KEY_BLUE }, -}; - -static struct rc_map_list ir_mantis_map = { - .map = { - .scan = mantis_ir_table, - .size = ARRAY_SIZE(mantis_ir_table), - .rc_type = RC_TYPE_UNKNOWN, - .name = RC_MAP_MANTIS, - } -}; + +void mantis_input_process(struct mantis_pci *mantis, int scancode) +{ + if (mantis->rc) + rc_keydown(mantis->rc, RC_TYPE_UNKNOWN, scancode, 0); +} int mantis_input_init(struct mantis_pci *mantis) { struct rc_dev *dev; int err; - err = rc_map_register(&ir_mantis_map); - if (err) - goto out; - dev = rc_allocate_device(); if (!dev) { dprintk(MANTIS_ERROR, 1, "Remote device allocation failed"); err = -ENOMEM; - goto out_map; + goto out; } - sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name); - sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev)); + snprintf(mantis->input_name, sizeof(mantis->input_name), + "Mantis %s IR receiver", mantis->hwconfig->model_name); + snprintf(mantis->input_phys, sizeof(mantis->input_phys), + "pci-%s/ir0", pci_name(mantis->pdev)); dev->input_name = mantis->input_name; dev->input_phys = mantis->input_phys; @@ -132,7 +58,7 @@ int mantis_input_init(struct mantis_pci *mantis) dev->input_id.product = mantis->device_id; dev->input_id.version = 1; dev->driver_name = MODULE_NAME; - dev->map_name = RC_MAP_MANTIS; + dev->map_name = mantis->rc_map_name ? : RC_MAP_EMPTY; dev->dev.parent = &mantis->pdev->dev; err = rc_register_device(dev); @@ -146,17 +72,13 @@ int mantis_input_init(struct mantis_pci *mantis) out_dev: rc_free_device(dev); -out_map: - rc_map_unregister(&ir_mantis_map); out: return err; } +EXPORT_SYMBOL_GPL(mantis_input_init); -int mantis_init_exit(struct mantis_pci *mantis) +void mantis_input_exit(struct mantis_pci *mantis) { rc_unregister_device(mantis->rc); - rc_map_unregister(&ir_mantis_map); - return 0; } - -#endif +EXPORT_SYMBOL_GPL(mantis_input_exit); diff --git a/drivers/media/pci/mantis/mantis_input.h b/drivers/media/pci/mantis/mantis_input.h new file mode 100644 index 000000000..0fbd92987 --- /dev/null +++ b/drivers/media/pci/mantis/mantis_input.h @@ -0,0 +1,24 @@ +/* + Mantis PCI bridge driver + + Copyright (C) Manu Abraham (abraham.manu@gmail.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#ifndef __MANTIS_INPUT_H +#define __MANTIS_INPUT_H + +int mantis_input_init(struct mantis_pci *mantis); +void mantis_input_exit(struct mantis_pci *mantis); +void mantis_input_process(struct mantis_pci *mantis, int scancode); + +#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/pci/mantis/mantis_pcmcia.c b/drivers/media/pci/mantis/mantis_pcmcia.c index 2f188c089..b2dbc7b2e 100644 --- a/drivers/media/pci/mantis/mantis_pcmcia.c +++ b/drivers/media/pci/mantis/mantis_pcmcia.c @@ -89,7 +89,7 @@ int mantis_pcmcia_init(struct mantis_ca *ca) u32 gpif_stat, card_stat; - mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); + mantis_unmask_ints(mantis, MANTIS_INT_IRQ0); gpif_stat = mmread(MANTIS_GPIF_STATUS); card_stat = mmread(MANTIS_GPIF_IRQCFG); @@ -117,5 +117,5 @@ void mantis_pcmcia_exit(struct mantis_ca *ca) struct mantis_pci *mantis = ca->ca_priv; mmwrite(mmread(MANTIS_GPIF_STATUS) & (~MANTIS_CARD_PLUGOUT | ~MANTIS_CARD_PLUGIN), MANTIS_GPIF_STATUS); - mmwrite(mmread(MANTIS_INT_MASK) & ~MANTIS_INT_IRQ0, MANTIS_INT_MASK); + mantis_mask_ints(mantis, MANTIS_INT_IRQ0); } diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c index a70719218..f1c96aec8 100644 --- a/drivers/media/pci/mantis/mantis_uart.c +++ b/drivers/media/pci/mantis/mantis_uart.c @@ -25,6 +25,7 @@ #include <linux/signal.h> #include <linux/sched.h> #include <linux/interrupt.h> +#include <linux/pci.h> #include "dmxdev.h" #include "dvbdev.h" @@ -35,6 +36,7 @@ #include "mantis_common.h" #include "mantis_reg.h" #include "mantis_uart.h" +#include "mantis_input.h" struct mantis_uart_params { enum mantis_baud baud_rate; @@ -59,51 +61,54 @@ static struct { { "EVEN" } }; -#define UART_MAX_BUF 16 - -static int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +static void mantis_uart_read(struct mantis_pci *mantis) { struct mantis_hwconfig *config = mantis->hwconfig; - u32 stat = 0, i; + int i, scancode = 0, err = 0; /* get data */ + dprintk(MANTIS_DEBUG, 1, "UART Reading ..."); for (i = 0; i < (config->bytes + 1); i++) { + int data = mmread(MANTIS_UART_RXD); - stat = mmread(MANTIS_UART_STAT); - - if (stat & MANTIS_UART_RXFIFO_FULL) { - dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - } - data[i] = mmread(MANTIS_UART_RXD) & 0x3f; + dprintk(MANTIS_DEBUG, 0, " <%02x>", data); - dprintk(MANTIS_DEBUG, 1, "Reading ... <%02x>", data[i] & 0x3f); + scancode = (scancode << 8) | (data & 0x3f); + err |= data; - if (data[i] & (1 << 7)) { + if (data & (1 << 7)) dprintk(MANTIS_ERROR, 1, "UART framing error"); - return -EINVAL; - } - if (data[i] & (1 << 6)) { + + if (data & (1 << 6)) dprintk(MANTIS_ERROR, 1, "UART parity error"); - return -EINVAL; - } } + dprintk(MANTIS_DEBUG, 0, "\n"); - return 0; + if ((err & 0xC0) == 0) + mantis_input_process(mantis, scancode); } static void mantis_uart_work(struct work_struct *work) { struct mantis_pci *mantis = container_of(work, struct mantis_pci, uart_work); - struct mantis_hwconfig *config = mantis->hwconfig; - u8 buf[16]; - int i; + u32 stat; - mantis_uart_read(mantis, buf); + stat = mmread(MANTIS_UART_STAT); - for (i = 0; i < (config->bytes + 1); i++) - dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + if (stat & MANTIS_UART_RXFIFO_FULL) + dprintk(MANTIS_ERROR, 1, "RX Fifo FULL"); - dprintk(MANTIS_DEBUG, 0, "\n"); + /* + * MANTIS_UART_RXFIFO_DATA is only set if at least + * config->bytes + 1 bytes are in the FIFO. + */ + while (stat & MANTIS_UART_RXFIFO_DATA) { + mantis_uart_read(mantis); + stat = mmread(MANTIS_UART_STAT); + } + + /* re-enable UART (RX) interrupt */ + mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); } static int mantis_uart_setup(struct mantis_pci *mantis, @@ -152,9 +157,6 @@ int mantis_uart_init(struct mantis_pci *mantis) rates[params.baud_rate].string, parity[params.parity].string); - init_waitqueue_head(&mantis->uart_wq); - spin_lock_init(&mantis->uart_lock); - INIT_WORK(&mantis->uart_work, mantis_uart_work); /* disable interrupt */ @@ -169,8 +171,8 @@ int mantis_uart_init(struct mantis_pci *mantis) mmwrite((mmread(MANTIS_UART_CTL) | MANTIS_UART_RXFLUSH), MANTIS_UART_CTL); /* enable interrupt */ - mmwrite(mmread(MANTIS_INT_MASK) | 0x800, MANTIS_INT_MASK); mmwrite(mmread(MANTIS_UART_CTL) | MANTIS_UART_RXINT, MANTIS_UART_CTL); + mantis_unmask_ints(mantis, MANTIS_INT_IRQ1); schedule_work(&mantis->uart_work); dprintk(MANTIS_DEBUG, 1, "UART successfully initialized"); @@ -182,6 +184,7 @@ EXPORT_SYMBOL_GPL(mantis_uart_init); void mantis_uart_exit(struct mantis_pci *mantis) { /* disable interrupt */ + mantis_mask_ints(mantis, MANTIS_INT_IRQ1); mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); flush_work(&mantis->uart_work); } diff --git a/drivers/media/pci/mantis/mantis_vp1034.c b/drivers/media/pci/mantis/mantis_vp1034.c index 7c1bd1672..3b1928594 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.c +++ b/drivers/media/pci/mantis/mantis_vp1034.c @@ -44,7 +44,7 @@ static struct mb86a16_config vp1034_mb86a16_config = { #define MANTIS_MODEL_NAME "VP-1034" #define MANTIS_DEV_TYPE "DVB-S/DSS" -int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +int vp1034_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { struct mantis_pci *mantis = fe->dvb->priv; diff --git a/drivers/media/pci/mantis/mantis_vp1034.h b/drivers/media/pci/mantis/mantis_vp1034.h index 323f38ef8..764b1c66e 100644 --- a/drivers/media/pci/mantis/mantis_vp1034.h +++ b/drivers/media/pci/mantis/mantis_vp1034.h @@ -28,6 +28,7 @@ #define MANTIS_VP_1034_DVB_S 0x0014 extern struct mantis_hwconfig vp1034_config; -extern int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +extern int vp1034_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); #endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 4c494a490..4c3774af2 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1526,10 +1526,12 @@ static int init_channel(struct ngene_channel *chan) if (chan->fe2) { if (dvb_register_frontend(adapter, chan->fe2) < 0) goto err; - chan->fe2->tuner_priv = chan->fe->tuner_priv; - memcpy(&chan->fe2->ops.tuner_ops, - &chan->fe->ops.tuner_ops, - sizeof(struct dvb_tuner_ops)); + if (chan->fe) { + chan->fe2->tuner_priv = chan->fe->tuner_priv; + memcpy(&chan->fe2->ops.tuner_ops, + &chan->fe->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + } } if (chan->has_demux) { diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 51e2fbd18..fa30930d7 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -682,7 +682,7 @@ struct ngene_channel { int AudioDTOUpdated; u32 AudioDTOValue; - int (*set_tone)(struct dvb_frontend *, fe_sec_tone_mode_t); + int (*set_tone)(struct dvb_frontend *, enum fe_sec_tone_mode); u8 lnbh; /* stuff from analog driver */ diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index acc35b42e..e7e442810 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -101,11 +101,11 @@ struct pt1_adapter { struct dmxdev dmxdev; struct dvb_frontend *fe; int (*orig_set_voltage)(struct dvb_frontend *fe, - fe_sec_voltage_t voltage); + enum fe_sec_voltage voltage); int (*orig_sleep)(struct dvb_frontend *fe); int (*orig_init)(struct dvb_frontend *fe); - fe_sec_voltage_t voltage; + enum fe_sec_voltage voltage; int sleep; }; @@ -575,7 +575,7 @@ pt1_update_power(struct pt1 *pt1) mutex_unlock(&pt1->lock); } -static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int pt1_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { struct pt1_adapter *adap; diff --git a/drivers/media/pci/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c index 1b637b74e..d0e70dc0e 100644 --- a/drivers/media/pci/pt1/va1j5jf8007s.c +++ b/drivers/media/pci/pt1/va1j5jf8007s.c @@ -108,7 +108,7 @@ static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe) } static int -va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status) +va1j5jf8007s_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct va1j5jf8007s_state *state; @@ -387,7 +387,7 @@ static int va1j5jf8007s_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct va1j5jf8007s_state *state; int ret; diff --git a/drivers/media/pci/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c index 2db15159d..0268f20b8 100644 --- a/drivers/media/pci/pt1/va1j5jf8007t.c +++ b/drivers/media/pci/pt1/va1j5jf8007t.c @@ -98,7 +98,7 @@ static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe) } static int -va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status) +va1j5jf8007t_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct va1j5jf8007t_state *state; @@ -266,7 +266,7 @@ static int va1j5jf8007t_tune(struct dvb_frontend *fe, bool re_tune, unsigned int mode_flags, unsigned int *delay, - fe_status_t *status) + enum fe_status *status) { struct va1j5jf8007t_state *state; int ret; diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c index 7a37e8fe2..0d2e2b217 100644 --- a/drivers/media/pci/pt3/pt3.c +++ b/drivers/media/pci/pt3/pt3.c @@ -188,7 +188,7 @@ static int pt3_set_lna(struct dvb_frontend *fe) return ret; } -static int pt3_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) +static int pt3_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage volt) { struct pt3_adapter *adap; struct pt3_board *pt3; diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index ac3cd74e8..1d2c310ce 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -16,6 +16,9 @@ * */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/slab.h> #include <linux/time.h> @@ -29,13 +32,6 @@ #include <linux/interrupt.h> #include <linux/vmalloc.h> -#include "saa7134.h" -#include "saa7134-reg.h" - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [alsa]"); - /* * Configuration macros */ @@ -57,11 +53,6 @@ module_param_array(enable, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s)."); -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ##arg) - - - /* * Main chip structure */ @@ -149,11 +140,11 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, spin_lock(&dev->slock); if (UNSET == dev->dmasound.dma_blk) { - dprintk("irq: recording stopped\n"); + pr_debug("irq: recording stopped\n"); goto done; } if (0 != (status & 0x0f000000)) - dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); + pr_debug("irq: lost %ld\n", (status >> 24) & 0x0f); if (0 == (status & 0x10000000)) { /* odd */ if (0 == (dev->dmasound.dma_blk & 0x01)) @@ -164,13 +155,14 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, reg = SAA7134_RS_BA2(6); } if (0 == reg) { - dprintk("irq: field oops [%s]\n", + pr_debug("irq: field oops [%s]\n", (status & 0x10000000) ? "even" : "odd"); goto done; } if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { - dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, + pr_debug("irq: overrun [full=%d/%d] - Blocks in %d\n", + dev->dmasound.read_count, dev->dmasound.bufsize, dev->dmasound.blocks); spin_unlock(&dev->slock); snd_pcm_stop_xrun(dev->dmasound.substream); @@ -180,10 +172,10 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev, /* next block addr */ next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; saa_writel(reg,next_blk * dev->dmasound.blksize); - if (debug > 2) - dprintk("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", - (status & 0x10000000) ? "even" : "odd ", next_blk, - next_blk * dev->dmasound.blksize, dev->dmasound.blocks, dev->dmasound.blksize, dev->dmasound.read_count); + pr_debug("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n", + (status & 0x10000000) ? "even" : "odd ", next_blk, + next_blk * dev->dmasound.blksize, dev->dmasound.blocks, + dev->dmasound.blksize, dev->dmasound.read_count); /* update status & wake waiting readers */ dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; @@ -233,7 +225,7 @@ static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id) } if (loop == 10) { - dprintk("error! looping IRQ!"); + pr_debug("error! looping IRQ!"); } out: @@ -281,11 +273,11 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages) dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); if (NULL == dma->vaddr) { - dprintk("vmalloc_32(%d pages) failed\n", nr_pages); + pr_debug("vmalloc_32(%d pages) failed\n", nr_pages); return -ENOMEM; } - dprintk("vmalloc is at addr 0x%08lx, size=%d\n", + pr_debug("vmalloc is at addr 0x%08lx, size=%d\n", (unsigned long)dma->vaddr, nr_pages << PAGE_SHIFT); @@ -572,7 +564,7 @@ static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream break; } - dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", + pr_debug("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", runtime->format, runtime->channels, fmt, bswap ? 'b' : '-'); /* dma: setup channel 6 (= AUDIO) */ @@ -821,7 +813,7 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) int amux, err; if (!saa7134) { - printk(KERN_ERR "BUG: saa7134 can't find device struct." + pr_err("BUG: saa7134 can't find device struct." " Can't proceed with open\n"); return -ENODEV; } @@ -1175,7 +1167,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) (void*) &dev->dmasound); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", + pr_err("%s: can't get IRQ %d for ALSA\n", dev->name, dev->pci->irq); goto __nodev; } @@ -1196,7 +1188,8 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) sprintf(card->longname, "%s at 0x%lx irq %d", chip->dev->name, chip->iobase, chip->irq); - printk(KERN_INFO "%s/alsa: %s registered as card %d\n",dev->name,card->longname,index[devnum]); + pr_info("%s/alsa: %s registered as card %d\n", + dev->name, card->longname, index[devnum]); if ((err = snd_card_register(card)) == 0) { snd_saa7134_cards[devnum] = card; @@ -1240,19 +1233,19 @@ static int saa7134_alsa_init(void) saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); + pr_info("saa7134 ALSA driver for DMA sound loaded\n"); list_for_each(list,&saa7134_devlist) { dev = list_entry(list, struct saa7134_dev, devlist); if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) - printk(KERN_INFO "%s/alsa: %s doesn't support digital audio\n", + pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); else alsa_device_init(dev); } if (dev == NULL) - printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); + pr_info("saa7134 ALSA: no saa7134 cards found\n"); return 0; @@ -1272,7 +1265,7 @@ static void saa7134_alsa_exit(void) saa7134_dmasound_init = NULL; saa7134_dmasound_exit = NULL; - printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n"); + pr_info("saa7134 ALSA driver for DMA sound unloaded\n"); return; } diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 4a9b4f330..deda0be26 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -20,13 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include "tuner-xc2028.h" #include <media/v4l2-common.h> #include <media/tveeprom.h> @@ -5850,6 +5851,39 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, } }, }, + [SAA7134_BOARD_AVERMEDIA_505] = { + /* much like the "studio" version but without radio + * and another tuner (dbaryshkov@gmail.com) */ + .name = "AverMedia AverTV/505", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FQ1216ME, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, }; @@ -7109,6 +7143,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x7007, .driver_data = SAA7134_BOARD_WIS_VOYAGER, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa10a, + .driver_data = SAA7134_BOARD_AVERMEDIA_505, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -7158,10 +7198,10 @@ MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); static void board_flyvideo(struct saa7134_dev *dev) { - printk("%s: there are different flyvideo cards with different tuners\n" - "%s: out there, you might have to use the tuner=<nr> insmod\n" - "%s: option to override the default value.\n", - dev->name, dev->name, dev->name); + pr_warn("%s: there are different flyvideo cards with different tuners\n" + "%s: out there, you might have to use the tuner=<nr> insmod\n" + "%s: option to override the default value.\n", + dev->name, dev->name, dev->name); } static int saa7134_xc2028_callback(struct saa7134_dev *dev, @@ -7194,7 +7234,7 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, saa7134_set_gpio(dev, 20, 1); break; } - return 0; + return 0; } return -EINVAL; } @@ -7380,7 +7420,7 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg) return saa7134_xc5000_callback(dev, command, arg); } } else { - printk(KERN_ERR "saa7134: Error - device struct undefined.\n"); + pr_err("saa7134: Error - device struct undefined.\n"); return -EINVAL; } return -EINVAL; @@ -7411,12 +7451,12 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: - printk(KERN_WARNING "%s: warning: " + pr_warn("%s: warning: " "unknown hauppauge model #%d\n", dev->name, tv.model); break; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", + pr_info("%s: hauppauge eeprom: model=%d\n", dev->name, tv.model); } @@ -7427,7 +7467,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) /* Always print gpio, often manufacturers encode tuner type and other info. */ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); - printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); + pr_info("%s: board init: gpio is %x\n", dev->name, dev->gpio_value); switch (dev->board) { case SAA7134_BOARD_FLYVIDEO2000: @@ -7448,8 +7488,9 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: - case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_305: + case SAA7134_BOARD_AVERMEDIA_STUDIO_505: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: @@ -7512,10 +7553,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_MD5044: - printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + pr_warn("%s: seems there are two different versions of the MD5044\n" + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name, dev->name, dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -7640,10 +7681,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: - printk("%s: %s: dual saa713x broadcast decoders\n" - "%s: Sorry, none of the inputs to this chip are supported yet.\n" - "%s: Dual decoder functionality is disabled for now, use the other chip.\n", - dev->name,card(dev).name,dev->name,dev->name); + pr_warn("%s: %s: dual saa713x broadcast decoders\n" + "%s: Sorry, none of the inputs to this chip are supported yet.\n" + "%s: Dual decoder functionality is disabled for now, use the other chip.\n", + dev->name, card(dev).name, dev->name, dev->name); break; case SAA7134_BOARD_AVERMEDIA_M102: /* enable tuner */ @@ -7789,7 +7830,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) if (board == dev->board) break; dev->board = board; - printk("%s: board type fixup: %s\n", dev->name, + pr_warn("%s: board type fixup: %s\n", dev->name, saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; @@ -7797,10 +7838,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_MD7134: { u8 subaddr; - u8 data[3]; + u8 data[3], data1[] = { 0x09, 0x9f, 0x86, 0x11}; int ret, tuner_t; - struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1}, - {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}}; + struct i2c_msg msg[] = {{.addr = 0x50, .flags = 0, .buf = &subaddr, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = 3}}, + msg1 = {.addr = 0x61, .flags = 0, .buf = data1, .len = sizeof(data1)}; subaddr= 0x14; tuner_t = 0; @@ -7810,7 +7852,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) */ ret = i2c_transfer(&dev->i2c_adap, msg, 2); if (ret != 2) { - printk(KERN_ERR "EEPROM read failure\n"); + pr_err("EEPROM read failure\n"); } else if ((data[0] != 0) && (data[0] != 0xff)) { /* old config structure */ subaddr = data[0] + 2; @@ -7825,7 +7867,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3; break; default: - printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); + pr_err("%s Can't determine tuner type %x from EEPROM\n", + dev->name, tuner_t); } } else if ((data[1] != 0) && (data[1] != 0xff)) { /* new config structure */ @@ -7842,16 +7885,28 @@ int saa7134_board_init2(struct saa7134_dev *dev) break; case 0x001d: dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3; - printk(KERN_INFO "%s Board has DVB-T\n", dev->name); + pr_info("%s Board has DVB-T\n", + dev->name); break; default: - printk(KERN_ERR "%s Can't determine tuner type %x from EEPROM\n", dev->name, tuner_t); + pr_err("%s Can't determine tuner type %x from EEPROM\n", + dev->name, tuner_t); } } else { - printk(KERN_ERR "%s unexpected config structure\n", dev->name); + pr_err("%s unexpected config structure\n", dev->name); } - printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); + pr_info("%s Tuner type is %d\n", dev->name, dev->tuner_type); + + /* The tuner TUNER_PHILIPS_FMD1216ME_MK3 after hardware */ + /* start has disabled IF and enabled DVB-T. When saa7134 */ + /* scan I2C devices it will not detect IF tda9887 and can`t*/ + /* watch TV without software reboot. To solve this problem */ + /* switch the tuner to analog TV mode manually. */ + if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { + if (i2c_transfer(&dev->i2c_adap, &msg1, 1) != 1) + printk(KERN_WARNING "%s: Unable to enable IF of the tuner.\n", dev->name); + } break; } case SAA7134_BOARD_PHILIPS_EUROPA: @@ -7859,7 +7914,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) /* Reconfigure board as Snake reference design */ dev->board = SAA7134_BOARD_PHILIPS_SNAKE; dev->tuner_type = saa7134_boards[dev->board].tuner_type; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); break; } @@ -7887,7 +7942,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { @@ -7903,13 +7958,14 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_TVFM7135: /* The card below is detected as card=53, but is different */ if (dev->autodetected && (dev->eedata[0x27] == 0x03)) { - dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; - printk(KERN_INFO "%s: P7131 analog only, using " - "entry of %s\n", - dev->name, saa7134_boards[dev->board].name); + dev->board = SAA7134_BOARD_ASUSTeK_P7131_ANALOG; + pr_info("%s: P7131 analog only, using entry of %s\n", + dev->name, saa7134_boards[dev->board].name); - /* IR init has already happened for other cards, so - * we have to catch up. */ + /* + * IR init has already happened for other cards, so + * we have to catch up. + */ dev->has_remote = SAA7134_REMOTE_GPIO; saa7134_input_init1(dev); } @@ -7972,12 +8028,12 @@ int saa7134_board_init2(struct saa7134_dev *dev) msg.addr = 0x0b; msg.len = 1; if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) { - printk(KERN_WARNING "%s: send wake up byte to pic16C505" + pr_warn("%s: send wake up byte to pic16C505" "(IR chip) failed\n", dev->name); } else { msg.flags = I2C_M_RD; rc = i2c_transfer(&dev->i2c_adap, &msg, 1); - printk(KERN_INFO "%s: probe IR chip @ i2c 0x%02x: %s\n", + pr_info("%s: probe IR chip @ i2c 0x%02x: %s\n", dev->name, msg.addr, (1 == rc) ? "yes" : "no"); if (rc == 1) @@ -8018,10 +8074,10 @@ int saa7134_board_init2(struct saa7134_dev *dev) dev->board = SAA7134_BOARD_VIDEOMATE_DVBT_200A; dev->tuner_type = saa7134_boards[dev->board].tuner_type; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; - printk(KERN_INFO "%s: Reconfigured board as %s\n", + pr_info("%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } else { - printk(KERN_WARNING "%s: Unexpected tuner type info: %x in eeprom\n", + pr_warn("%s: Unexpected tuner type info: %x in eeprom\n", dev->name, dev->eedata[0x41]); break; } @@ -8043,9 +8099,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) msg.buf = &buffer[i][0]; msg.len = ARRAY_SIZE(buffer[0]); if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable tuner(%i).\n", - dev->name, i); + pr_warn("%s: Unable to enable tuner(%i).\n", + dev->name, i); } break; } @@ -8061,9 +8116,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) /* watch TV without software reboot. For solve this problem */ /* switch the tuner to analog TV mode manually. */ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) - printk(KERN_WARNING - "%s: Unable to enable IF of the tuner.\n", - dev->name); + pr_warn("%s: Unable to enable IF of the tuner.\n", + dev->name); break; } case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG: diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index a349e964e..72d7f9923 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -33,9 +36,6 @@ #include <linux/dma-mapping.h> #include <linux/pm.h> -#include "saa7134-reg.h" -#include "saa7134.h" - MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -102,8 +102,15 @@ static unsigned int saa7134_devcount; int (*saa7134_dmasound_init)(struct saa7134_dev *dev); int (*saa7134_dmasound_exit)(struct saa7134_dev *dev); -#define dprintk(fmt, arg...) if (core_debug) \ - printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) +#define core_dbg(fmt, arg...) do { \ + if (core_debug) \ + printk(KERN_DEBUG pr_fmt("core: " fmt), ## arg); \ + } while (0) + +#define irq_dbg(level, fmt, arg...) do {\ + if (irq_debug > level) \ + printk(KERN_DEBUG pr_fmt("irq: " fmt), ## arg); \ + } while (0) void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) { @@ -116,8 +123,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; - printk(KERN_DEBUG - "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", + core_dbg("%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", dev->name, mode, (~mode) & status, mode & status, msg); } @@ -128,7 +134,8 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) index = 1 << bit_no; switch (value) { case 0: /* static value */ - case 1: dprintk("setting GPIO%d to static %d\n", bit_no, value); + case 1: + core_dbg("setting GPIO%d to static %d\n", bit_no, value); /* turn sync mode off if necessary */ if (index & 0x00c00000) saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00); @@ -140,7 +147,7 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value) saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval); break; case 3: /* tristate */ - dprintk("setting GPIO%d to tristate\n", bit_no); + core_dbg("setting GPIO%d to tristate\n", bit_no); saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0); break; } @@ -274,7 +281,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, unsigned long flags; spin_lock_irqsave(&dev->slock, flags); - dprintk("buffer_queue %p\n", buf); + core_dbg("buffer_queue %p\n", buf); if (NULL == q->curr) { if (!q->need_two) { q->curr = buf; @@ -298,7 +305,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, unsigned int state) { - dprintk("buffer_finish %p\n", q->curr); + core_dbg("buffer_finish %p\n", q->curr); /* finish current buffer */ v4l2_get_timestamp(&q->curr->vb2.v4l2_buf.timestamp); @@ -318,18 +325,18 @@ void saa7134_buffer_next(struct saa7134_dev *dev, if (!list_empty(&q->queue)) { /* activate next one from queue */ buf = list_entry(q->queue.next, struct saa7134_buf, entry); - dprintk("buffer_next %p [prev=%p/next=%p]\n", + core_dbg("buffer_next %p [prev=%p/next=%p]\n", buf, q->queue.prev, q->queue.next); list_del(&buf->entry); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, entry); q->curr = buf; buf->activate(dev, buf, next); - dprintk("buffer_next #2 prev=%p/next=%p\n", + core_dbg("buffer_next #2 prev=%p/next=%p\n", q->queue.prev, q->queue.next); } else { /* nothing to do -- just stop DMA */ - dprintk("buffer_next %p\n", NULL); + core_dbg("buffer_next %p\n", NULL); saa7134_set_dmabits(dev); del_timer(&q->timeout); } @@ -351,7 +358,7 @@ void saa7134_buffer_timeout(unsigned long data) /* flag current buffer as failed, try to start over with the next one. */ if (q->curr) { - dprintk("timeout on %p\n", q->curr); + core_dbg("timeout on %p\n", q->curr); saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR); } saa7134_buffer_next(dev, q); @@ -474,7 +481,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_TE5 | SAA7134_MAIN_CTRL_TE6, ctrl); - dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", + core_dbg("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", task, ctrl, irq, split ? "no" : "yes"); return 0; @@ -496,21 +503,21 @@ static void print_irqstatus(struct saa7134_dev *dev, int loop, { unsigned int i; - printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", - dev->name,loop,jiffies,report,status); + irq_dbg(1, "[%d,%ld]: r=0x%lx s=0x%02lx", + loop, jiffies, report, status); for (i = 0; i < IRQBITS; i++) { if (!(report & (1 << i))) continue; - printk(" %s",irqbits[i]); + pr_cont(" %s", irqbits[i]); } if (report & SAA7134_IRQ_REPORT_DONE_RA0) { - printk(" | RA0=%s,%s,%s,%ld", - (status & 0x40) ? "vbi" : "video", - (status & 0x20) ? "b" : "a", - (status & 0x10) ? "odd" : "even", - (status & 0x0f)); + pr_cont(" | RA0=%s,%s,%s,%ld", + (status & 0x40) ? "vbi" : "video", + (status & 0x20) ? "b" : "a", + (status & 0x10) ? "odd" : "even", + (status & 0x0f)); } - printk("\n"); + pr_cont("\n"); } static irqreturn_t saa7134_irq(int irq, void *dev_id) @@ -532,16 +539,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && (dev->dmasound.priv_data != NULL) ) { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: preserving DMA sound interrupt\n", - dev->name); + irq_dbg(2, "preserving DMA sound interrupt\n"); report &= ~SAA7134_IRQ_REPORT_DONE_RA3; } if (0 == report) { - if (irq_debug > 1) - printk(KERN_DEBUG "%s/irq: no (more) work\n", - dev->name); + irq_dbg(2, "no (more) work\n"); goto out; } @@ -614,24 +617,24 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); if (report & SAA7134_IRQ_REPORT_PE) { /* disable all parity error */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing PE (parity error!) enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); } else if (report & SAA7134_IRQ_REPORT_GPIO16) { /* disable gpio16 IRQ */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing GPIO16 enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N); } else if (report & SAA7134_IRQ_REPORT_GPIO18) { /* disable gpio18 IRQs */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing GPIO18 enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N); } else { /* disable all irqs */ - printk(KERN_WARNING "%s/irq: looping -- " + pr_warn("%s/irq: looping -- " "clearing all enable bits\n",dev->name); saa_writel(SAA7134_IRQ1,0); saa_writel(SAA7134_IRQ2,0); @@ -680,7 +683,7 @@ static int saa7134_hw_enable1(struct saa7134_dev *dev) static int saa7134_hwinit1(struct saa7134_dev *dev) { - dprintk("hwinit1\n"); + core_dbg("hwinit1\n"); saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); @@ -742,7 +745,7 @@ static int saa7134_hw_enable2(struct saa7134_dev *dev) static int saa7134_hwinit2(struct saa7134_dev *dev) { - dprintk("hwinit2\n"); + core_dbg("hwinit2\n"); saa7134_video_init2(dev); saa7134_tvaudio_init2(dev); @@ -756,7 +759,7 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) /* shutdown */ static int saa7134_hwfini(struct saa7134_dev *dev) { - dprintk("hwfini\n"); + core_dbg("hwfini\n"); if (card_has_mpeg(dev)) saa7134_ts_fini(dev); @@ -772,34 +775,32 @@ static void must_configure_manually(int has_eeprom) unsigned int i,p; if (!has_eeprom) - printk(KERN_WARNING - "saa7134: <rant>\n" - "saa7134: Congratulations! Your TV card vendor saved a few\n" - "saa7134: cents for a eeprom, thus your pci board has no\n" - "saa7134: subsystem ID and I can't identify it automatically\n" - "saa7134: </rant>\n" - "saa7134: I feel better now. Ok, here are the good news:\n" - "saa7134: You can use the card=<nr> insmod option to specify\n" - "saa7134: which board do you have. The list:\n"); + pr_warn("saa7134: <rant>\n" + "saa7134: Congratulations! Your TV card vendor saved a few\n" + "saa7134: cents for a eeprom, thus your pci board has no\n" + "saa7134: subsystem ID and I can't identify it automatically\n" + "saa7134: </rant>\n" + "saa7134: I feel better now. Ok, here are the good news:\n" + "saa7134: You can use the card=<nr> insmod option to specify\n" + "saa7134: which board do you have. The list:\n"); else - printk(KERN_WARNING - "saa7134: Board is currently unknown. You might try to use the card=<nr>\n" - "saa7134: insmod option to specify which board do you have, but this is\n" - "saa7134: somewhat risky, as might damage your card. It is better to ask\n" - "saa7134: for support at linux-media@vger.kernel.org.\n" - "saa7134: The supported cards are:\n"); + pr_warn("saa7134: Board is currently unknown. You might try to use the card=<nr>\n" + "saa7134: insmod option to specify which board do you have, but this is\n" + "saa7134: somewhat risky, as might damage your card. It is better to ask\n" + "saa7134: for support at linux-media@vger.kernel.org.\n" + "saa7134: The supported cards are:\n"); for (i = 0; i < saa7134_bcount; i++) { - printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", + pr_warn("saa7134: card=%d -> %-40.40s", i,saa7134_boards[i].name); for (p = 0; saa7134_pci_tbl[p].driver_data; p++) { if (saa7134_pci_tbl[p].driver_data != i) continue; - printk(" %04x:%04x", + pr_cont(" %04x:%04x", saa7134_pci_tbl[p].subvendor, saa7134_pci_tbl[p].subdevice); } - printk("\n"); + pr_cont("\n"); } } @@ -903,31 +904,31 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* pci quirks */ if (pci_pci_problems) { if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name); + pr_info("%s: quirk: PCIPCI_TRITON\n", dev->name); if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name); + pr_info("%s: quirk: PCIPCI_NATOMA\n", dev->name); if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name); + pr_info("%s: quirk: PCIPCI_VIAETBF\n", dev->name); if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name); + pr_info("%s: quirk: PCIPCI_VSFX\n", dev->name); #ifdef PCIPCI_ALIMAGIK if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", + pr_info("%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", dev->name); latency = 0x0A; } #endif if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) { - printk(KERN_INFO "%s: quirk: this driver and your " + pr_info("%s: quirk: this driver and your " "chipset may not work together" " in overlay mode.\n",dev->name); if (!saa7134_no_overlay) { - printk(KERN_INFO "%s: quirk: overlay " + pr_info("%s: quirk: overlay " "mode will be disabled.\n", dev->name); saa7134_no_overlay = 1; } else { - printk(KERN_INFO "%s: quirk: overlay " + pr_info("%s: quirk: overlay " "mode will be forced. Use this" " option at your own risk.\n", dev->name); @@ -935,7 +936,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, } } if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", + pr_info("%s: setting pci latency timer to %d\n", dev->name,latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } @@ -943,13 +944,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " + pr_info("%s: found at %s, rev: %d, irq: %d, " "latency: %d, mmio: 0x%llx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); + pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail1; } @@ -972,7 +973,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + pr_info("%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,saa7134_boards[dev->board].name, dev->board, dev->autodetected ? @@ -983,7 +984,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, pci_resource_len(pci_dev,0), dev->name)) { err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + pr_err("%s: can't get MMIO memory @ 0x%llx\n", dev->name,(unsigned long long)pci_resource_start(pci_dev,0)); goto fail1; } @@ -992,7 +993,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + pr_err("%s: can't ioremap() MMIO memory\n", dev->name); goto fail2; } @@ -1010,7 +1011,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, saa7134_irq, IRQF_SHARED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name,pci_dev->irq); goto fail4; } @@ -1040,7 +1041,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, &dev->i2c_adap, "saa6588", 0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr)); if (sd) { - printk(KERN_INFO "%s: found RDS decoder\n", dev->name); + pr_info("%s: found RDS decoder\n", dev->name); dev->has_rds = 1; } } @@ -1059,7 +1060,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* register v4l devices */ if (saa7134_no_overlay > 0) - printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); + pr_info("%s: Overlay support disabled.\n", dev->name); dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); dev->video_dev->ctrl_handler = &dev->ctrl_handler; @@ -1068,11 +1069,11 @@ static int saa7134_initdev(struct pci_dev *pci_dev, err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_info("%s: can't register video device\n", dev->name); goto fail5; } - printk(KERN_INFO "%s: registered device %s [v4l2]\n", + pr_info("%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); @@ -1084,7 +1085,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, vbi_nr[dev->nr]); if (err < 0) goto fail5; - printk(KERN_INFO "%s: registered device %s\n", + pr_info("%s: registered device %s\n", dev->name, video_device_node_name(dev->vbi_dev)); if (card_has_radio(dev)) { @@ -1095,7 +1096,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, radio_nr[dev->nr]); if (err < 0) goto fail5; - printk(KERN_INFO "%s: registered device %s\n", + pr_info("%s: registered device %s\n", dev->name, video_device_node_name(dev->radio_dev)); } @@ -1204,12 +1205,12 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev, buf = q->curr; next = buf; - dprintk("buffer_requeue\n"); + core_dbg("buffer_requeue\n"); if (!buf) return 0; - dprintk("buffer_requeue : resending active buffers \n"); + core_dbg("buffer_requeue : resending active buffer\n"); if (!list_empty(&q->queue)) next = list_entry(q->queue.next, struct saa7134_buf, @@ -1358,7 +1359,7 @@ static struct pci_driver saa7134_pci_driver = { static int __init saa7134_init(void) { INIT_LIST_HEAD(&saa7134_devlist); - printk(KERN_INFO "saa7130/34: v4l2 driver version %s loaded\n", + pr_info("saa7130/34: v4l2 driver version %s loaded\n", SAA7134_VERSION); return pci_register_driver(&saa7134_pci_driver); } diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index 76b802407..f32661433 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -28,8 +31,6 @@ #include <linux/kthread.h> #include <linux/suspend.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include <media/v4l2-common.h> #include "dvb-pll.h" #include <dvb_frontend.h> @@ -75,19 +76,8 @@ static int use_frontend; module_param(use_frontend, int, 0644); MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)"); -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off)."); - DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0) - -/* Print a warning */ -#define wprintk(fmt, arg...) \ - printk(KERN_WARNING "%s/dvb: " fmt, dev->name, ## arg) - /* ------------------------------------------------------------------ * mt352 based DVB-T cards */ @@ -112,7 +102,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); udelay(10); ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); - dprintk("%s %s\n", __func__, ok ? "on" : "off"); + pr_debug("%s %s\n", __func__, ok ? "on" : "off"); if (!ok) saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); @@ -130,9 +120,8 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f }; static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d }; static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; - struct saa7134_dev *dev= fe->dvb->priv; - dprintk("%s called\n", __func__); + pr_debug("%s called\n", __func__); mt352_write(fe, clock_config, sizeof(clock_config)); udelay(200); @@ -258,7 +247,7 @@ static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2}; if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); + pr_warn("could not access the I2C gate\n"); return -EIO; } if (enable) @@ -266,7 +255,7 @@ static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable) else msg.buf = msg_disable; if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) { - wprintk("could not access the I2C gate\n"); + pr_warn("could not access the I2C gate\n"); return -EIO; } msleep(20); @@ -369,7 +358,7 @@ static int philips_tda6651_pll_set(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) { - wprintk("could not write to tuner at addr: 0x%02x\n", + pr_warn("could not write to tuner at addr: 0x%02x\n", addr << 1); return -EIO; } @@ -556,8 +545,7 @@ static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable) tda8290_msg.buf = tda8290_open; } if (i2c_transfer(state->i2c, &tda8290_msg, 1) != 1) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("could not access tda8290 I2C gate\n"); + pr_warn("could not access tda8290 I2C gate\n"); return -EIO; } msleep(20); @@ -570,11 +558,14 @@ static int philips_tda827x_tuner_init(struct dvb_frontend *fe) struct tda1004x_state *state = fe->demodulator_priv; switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); + case 0: + break; + case 1: + pr_debug("setting GPIO21 to 0 (TV antenna?)\n"); saa7134_set_gpio(dev, 21, 0); break; - case 2: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); + case 2: + pr_debug("setting GPIO21 to 1 (Radio antenna?)\n"); saa7134_set_gpio(dev, 21, 1); break; } @@ -587,11 +578,14 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe) struct tda1004x_state *state = fe->demodulator_priv; switch (state->config->antenna_switch) { - case 0: break; - case 1: dprintk("setting GPIO21 to 1 (Radio antenna?)\n"); + case 0: + break; + case 1: + pr_debug("setting GPIO21 to 1 (Radio antenna?)\n"); saa7134_set_gpio(dev, 21, 1); break; - case 2: dprintk("setting GPIO21 to 0 (TV antenna?)\n"); + case 2: + pr_debug("setting GPIO21 to 0 (TV antenna?)\n"); saa7134_set_gpio(dev, 21, 0); break; } @@ -619,7 +613,7 @@ static int configure_tda827x_fe(struct saa7134_dev *dev, &dev->i2c_adap, tuner_conf)) return 0; - wprintk("no tda827x tuner found at addr: %02x\n", + pr_warn("no tda827x tuner found at addr: %02x\n", cdec_conf->tuner_address); } return -EINVAL; @@ -993,7 +987,8 @@ static struct tda10086_config sd1878_4m = { * special case: lnb supply is connected to the gated i2c */ -static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int md8800_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { int res = -EIO; struct saa7134_dev *dev = fe->dvb->priv; @@ -1019,7 +1014,8 @@ static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg) return res; }; -static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +static int md8800_set_voltage2(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct saa7134_dev *dev = fe->dvb->priv; u8 wbuf[2] = { 0x1f, 00 }; @@ -1041,8 +1037,8 @@ static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg) { - struct saa7134_dev *dev = fe->dvb->priv; - wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__); + pr_warn("%s: sorry can't set high LNB supply voltage from here\n", + __func__); return -EIO; } @@ -1222,10 +1218,10 @@ static int dvb_init(struct saa7134_dev *dev) mutex_init(&dev->frontends.lock); INIT_LIST_HEAD(&dev->frontends.felist); - printk(KERN_INFO "%s() allocating 1 frontend\n", __func__); + pr_info("%s() allocating 1 frontend\n", __func__); fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1); if (!fe0) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); + pr_err("%s() failed to alloc\n", __func__); return -ENOMEM; } @@ -1250,7 +1246,7 @@ static int dvb_init(struct saa7134_dev *dev) switch (dev->board) { case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: - dprintk("pinnacle 300i dvb setup\n"); + pr_debug("pinnacle 300i dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i, &dev->i2c_adap); if (fe0->dvb.frontend) { @@ -1259,7 +1255,7 @@ static int dvb_init(struct saa7134_dev *dev) break; case SAA7134_BOARD_AVERMEDIA_777: case SAA7134_BOARD_AVERMEDIA_A16AR: - dprintk("avertv 777 dvb setup\n"); + pr_debug("avertv 777 dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777, &dev->i2c_adap); if (fe0->dvb.frontend) { @@ -1269,7 +1265,7 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_AVERMEDIA_A16D: - dprintk("AverMedia A16D dvb setup\n"); + pr_debug("AverMedia A16D dvb setup\n"); fe0->dvb.frontend = dvb_attach(mt352_attach, &avermedia_xc3028_mt352_dev, &dev->i2c_adap); @@ -1401,13 +1397,15 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x63, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); + pr_warn("%s: Lifeview Trio, No tda826x found!\n", + __func__); goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0, false) == NULL) { - wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); + pr_warn("%s: Lifeview Trio, No ISL6421 found!\n", + __func__); goto detach_frontend; } } @@ -1422,12 +1420,12 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda827x_attach,fe0->dvb.frontend, ads_tech_duo_config.tuner_address, &dev->i2c_adap, &ads_duo_cfg) == NULL) { - wprintk("no tda827x tuner found at addr: %02x\n", + pr_warn("no tda827x tuner found at addr: %02x\n", ads_tech_duo_config.tuner_address); goto detach_frontend; } } else - wprintk("failed to attach tda10046\n"); + pr_warn("failed to attach tda10046\n"); break; case SAA7134_BOARD_TEVION_DVBT_220RF: if (configure_tda827x_fe(dev, &tevion_dvbt220rf_config, @@ -1450,7 +1448,7 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Medion Quadro, no tda826x " + pr_warn("%s: Medion Quadro, no tda826x " "found !\n", __func__); goto detach_frontend; } @@ -1459,7 +1457,7 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: Medion Quadro, no ISL6405 " + pr_warn("%s: Medion Quadro, no ISL6405 " "found !\n", __func__); goto detach_frontend; } @@ -1519,13 +1517,13 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); + pr_warn("%s: No tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, 0x08, 0, 0, false) == NULL) { - wprintk("%s: No ISL6421 found!\n", __func__); + pr_warn("%s: No ISL6421 found!\n", __func__); goto detach_frontend; } } @@ -1593,12 +1591,12 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: No tda826x found!\n", __func__); + pr_warn("%s: No tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: No lnbp21 found!\n", __func__); + pr_warn("%s: No lnbp21 found!\n", __func__); goto detach_frontend; } } @@ -1614,7 +1612,7 @@ static int dvb_init(struct saa7134_dev *dev) goto detach_frontend; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: - dprintk("AverMedia E506R dvb setup\n"); + pr_debug("AverMedia E506R dvb setup\n"); saa7134_set_gpio(dev, 25, 0); msleep(10); saa7134_set_gpio(dev, 25, 1); @@ -1630,7 +1628,7 @@ static int dvb_init(struct saa7134_dev *dev) struct dvb_frontend *fe; if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { - wprintk("%s: MD7134 DVB-S, no SD1878 " + pr_warn("%s: MD7134 DVB-S, no SD1878 " "found !\n", __func__); goto detach_frontend; } @@ -1639,7 +1637,7 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - wprintk("%s: MD7134 DVB-S, no ISL6405 " + pr_warn("%s: MD7134 DVB-S, no ISL6405 " "found !\n", __func__); goto detach_frontend; } @@ -1671,15 +1669,15 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no " + pr_warn("%s: Asus Tiger 3in1, no " "tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: Asus Tiger 3in1, no lnbp21" + pr_warn("%s: Asus Tiger 3in1, no lnbp21" " found!\n", __func__); - goto detach_frontend; + goto detach_frontend; } } } @@ -1696,13 +1694,13 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - wprintk("%s: Asus My Cinema PS3-100, no " + pr_warn("%s: Asus My Cinema PS3-100, no " "tda826x found!\n", __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - wprintk("%s: Asus My Cinema PS3-100, no lnbp21" + pr_warn("%s: Asus My Cinema PS3-100, no lnbp21" " found!\n", __func__); goto detach_frontend; } @@ -1750,7 +1748,7 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) { if (dvb_attach(zl10036_attach, fe0->dvb.frontend, &avertv_a700_tuner, &dev->i2c_adap) == NULL) { - wprintk("%s: No zl10036 found!\n", + pr_warn("%s: No zl10036 found!\n", __func__); } } @@ -1761,7 +1759,7 @@ static int dvb_init(struct saa7134_dev *dev) if (fe0->dvb.frontend) if (dvb_attach(zl10039_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap) == NULL) - wprintk("%s: No zl10039 found!\n", + pr_warn("%s: No zl10039 found!\n", __func__); break; @@ -1774,7 +1772,7 @@ static int dvb_init(struct saa7134_dev *dev) fe0->dvb.frontend, &dev->i2c_adap, &videomate_t750_qt1010_config) == NULL) - wprintk("error attaching QT1010\n"); + pr_warn("error attaching QT1010\n"); } break; case SAA7134_BOARD_ZOLID_HYBRID_PCI: @@ -1850,12 +1848,12 @@ static int dvb_init(struct saa7134_dev *dev) fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (dvb_attach(zl10039_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap) == NULL) - wprintk("%s: No zl10039 found!\n", + pr_warn("%s: No zl10039 found!\n", __func__); } break; default: - wprintk("Huh? unknown DVB card?\n"); + pr_warn("Huh? unknown DVB card?\n"); break; } @@ -1871,14 +1869,14 @@ static int dvb_init(struct saa7134_dev *dev) fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", + pr_err("%s/2: xc3028 attach failed\n", dev->name); goto detach_frontend; } } if (NULL == fe0->dvb.frontend) { - printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name); + pr_err("%s/dvb: frontend initialization failed\n", dev->name); goto detach_frontend; } /* define general-purpose callback pointer */ diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 594dc3ad4..56b932c97 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -17,6 +17,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -26,9 +29,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-event.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -39,13 +39,6 @@ static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; module_param_array(empress_nr, int, NULL, 0444); MODULE_PARM_DESC(empress_nr,"ts device number"); -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages"); - -#define dprintk(fmt, arg...) if (debug) \ - printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg) - /* ------------------------------------------------------------------ */ static int start_streaming(struct vb2_queue *vq, unsigned int count) @@ -121,11 +114,14 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; - saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); + saa_call_all(dev, pad, get_fmt, NULL, &fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; f->fmt.pix.bytesperline = 0; @@ -137,11 +133,13 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -154,11 +152,14 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; @@ -221,9 +222,9 @@ static void empress_signal_update(struct work_struct *work) container_of(work, struct saa7134_dev, empress_workqueue); if (dev->nosignal) { - dprintk("no video signal\n"); + pr_debug("no video signal\n"); } else { - dprintk("video signal acquired\n"); + pr_debug("video signal acquired\n"); } } @@ -255,7 +256,7 @@ static int empress_init(struct saa7134_dev *dev) struct vb2_queue *q; int err; - dprintk("%s: %s\n",dev->name,__func__); + pr_debug("%s: %s\n", dev->name, __func__); dev->empress_dev = video_device_alloc(); if (NULL == dev->empress_dev) return -ENOMEM; @@ -302,13 +303,13 @@ static int empress_init(struct saa7134_dev *dev) err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_info("%s: can't register video device\n", dev->name); video_device_release(dev->empress_dev); dev->empress_dev = NULL; return err; } - printk(KERN_INFO "%s: registered device %s [mpeg]\n", + pr_info("%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->empress_dev)); empress_signal_update(&dev->empress_workqueue); @@ -317,7 +318,7 @@ static int empress_init(struct saa7134_dev *dev) static int empress_fini(struct saa7134_dev *dev) { - dprintk("%s: %s\n",dev->name,__func__); + pr_debug("%s: %s\n", dev->name, __func__); if (NULL == dev->empress_dev) return 0; diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 0b5525e90..78ed2718e 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -11,6 +11,9 @@ * GNU General Public License for more details. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -27,8 +30,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#include "saa7134.h" -#include "saa7134-reg.h" #include "go7007-priv.h" /*#define GO7007_HPI_DEBUG*/ @@ -288,9 +289,9 @@ static int saa7134_go7007_stream_start(struct go7007 *go) /* Set up transfer block size */ saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 128 - 1); - saa_writeb(SAA7134_TS_DMA0, (PAGE_SIZE >> 7) - 1); - saa_writeb(SAA7134_TS_DMA1, 0); - saa_writeb(SAA7134_TS_DMA2, 0); + saa_writeb(SAA7134_TS_DMA0, ((PAGE_SIZE >> 7) - 1) & 0xff); + saa_writeb(SAA7134_TS_DMA1, (PAGE_SIZE >> 15) & 0xff); + saa_writeb(SAA7134_TS_DMA2, (PAGE_SIZE >> 31) & 0x3f); /* Enable video streaming mode */ saa_writeb(SAA7134_GPIO_GPSTATUS2, GPIO_COMMAND_VIDEO); diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index f4da674e7..8ef6399d7 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -20,14 +20,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> -#include "saa7134-reg.h" -#include "saa7134.h" #include <media/v4l2-common.h> /* ----------------------------------------------------------- */ @@ -40,8 +41,15 @@ static unsigned int i2c_scan; module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); -#define d1printk if (1 == i2c_debug) printk -#define d2printk if (2 == i2c_debug) printk +#define i2c_dbg(level, fmt, arg...) do { \ + if (i2c_debug == level) \ + printk(KERN_DEBUG pr_fmt("i2c: " fmt), ## arg); \ + } while (0) + +#define i2c_cont(level, fmt, arg...) do { \ + if (i2c_debug == level) \ + pr_cont(fmt, ## arg); \ + } while (0) #define I2C_WAIT_DELAY 32 #define I2C_WAIT_RETRY 16 @@ -89,23 +97,20 @@ static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) enum i2c_status status; status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; - d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, - str_i2c_status[status]); + i2c_dbg(2, "i2c stat <= %s\n", str_i2c_status[status]); return status; } static inline void i2c_set_status(struct saa7134_dev *dev, enum i2c_status status) { - d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, - str_i2c_status[status]); + i2c_dbg(2, "i2c stat => %s\n", str_i2c_status[status]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); } static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) { - d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, - str_i2c_attr[attr]); + i2c_dbg(2, "i2c attr => %s\n", str_i2c_attr[attr]); saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); } @@ -168,7 +173,7 @@ static int i2c_reset(struct saa7134_dev *dev) enum i2c_status status; int count; - d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); + i2c_dbg(2, "i2c reset\n"); status = i2c_get_status(dev); if (!i2c_is_error(status)) return true; @@ -206,7 +211,7 @@ static inline int i2c_send_byte(struct saa7134_dev *dev, // dword |= 0x40 << 16; /* 400 kHz */ dword |= 0xf0 << 24; saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); - d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); + i2c_dbg(2, "i2c data => 0x%x\n", data); if (!i2c_is_busy_wait(dev)) return -EIO; @@ -228,7 +233,7 @@ static inline int i2c_recv_byte(struct saa7134_dev *dev) if (i2c_is_error(status)) return -EIO; data = saa_readb(SAA7134_I2C_DATA); - d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); + i2c_dbg(2, "i2c data <= 0x%x\n", data); return data; } @@ -245,12 +250,12 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, if (!i2c_reset(dev)) return -EIO; - d2printk("start xfer\n"); - d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); + i2c_dbg(2, "start xfer\n"); + i2c_dbg(1, "i2c xfer:"); for (i = 0; i < num; i++) { if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { /* send address */ - d2printk("send address\n"); + i2c_dbg(2, "send address\n"); addr = msgs[i].addr << 1; if (msgs[i].flags & I2C_M_RD) addr |= 1; @@ -262,50 +267,50 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, * needed to talk to the mt352 demux * thanks to pinnacle for the hint */ int quirk = 0xfe; - d1printk(" [%02x quirk]",quirk); + i2c_cont(1, " [%02x quirk]", quirk); i2c_send_byte(dev,START,quirk); i2c_recv_byte(dev); } - d1printk(" < %02x", addr); + i2c_cont(1, " < %02x", addr); rc = i2c_send_byte(dev,START,addr); if (rc < 0) goto err; } if (msgs[i].flags & I2C_M_RD) { /* read bytes */ - d2printk("read bytes\n"); + i2c_dbg(2, "read bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { - d1printk(" ="); + i2c_cont(1, " ="); rc = i2c_recv_byte(dev); if (rc < 0) goto err; - d1printk("%02x", rc); + i2c_cont(1, "%02x", rc); msgs[i].buf[byte] = rc; } /* discard mysterious extra byte when reading from Samsung S5H1411. i2c bus gets error if we do not. */ if (0x19 == msgs[i].addr) { - d1printk(" ?"); + i2c_cont(1, " ?"); rc = i2c_recv_byte(dev); if (rc < 0) goto err; - d1printk("%02x", rc); + i2c_cont(1, "%02x", rc); } } else { /* write bytes */ - d2printk("write bytes\n"); + i2c_dbg(2, "write bytes\n"); for (byte = 0; byte < msgs[i].len; byte++) { data = msgs[i].buf[byte]; - d1printk(" %02x", data); + i2c_cont(1, " %02x", data); rc = i2c_send_byte(dev,CONTINUE,data); if (rc < 0) goto err; } } } - d2printk("xfer done\n"); - d1printk(" >"); + i2c_dbg(2, "xfer done\n"); + i2c_cont(1, " >"); i2c_set_attr(dev,STOP); rc = -EIO; if (!i2c_is_busy_wait(dev)) @@ -316,12 +321,12 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, /* ensure that the bus is idle for at least one bit slot */ msleep(1); - d1printk("\n"); + i2c_cont(1, "\n"); return num; err: if (1 == i2c_debug) { status = i2c_get_status(dev); - printk(" ERROR: %s\n",str_i2c_status[status]); + i2c_cont(1, " ERROR: %s\n", str_i2c_status[status]); } return rc; } @@ -359,22 +364,22 @@ saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) dev->i2c_client.addr = 0xa0 >> 1; buf = 0; if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", + pr_info("%s: Huh, no eeprom present (err=%d)?\n", dev->name,err); return -1; } if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { - printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", + pr_warn("%s: i2c eeprom read error (err=%d)\n", dev->name,err); return -1; } - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); - printk(" %02x",eedata[i]); - if (15 == (i % 16)) - printk("\n"); + + for (i = 0; i < len; i += 16) { + int size = (len - i) > 16 ? 16 : len - i; + + pr_info("i2c eeprom %02x: %*ph\n", i, size, &eedata[i]); } + return 0; } @@ -386,7 +391,7 @@ static char *i2c_devs[128] = { [ 0x5a >> 1 ] = "remote control", }; -static void do_i2c_scan(char *name, struct i2c_client *c) +static void do_i2c_scan(struct i2c_client *c) { unsigned char buf; int i,rc; @@ -396,8 +401,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c) rc = i2c_master_recv(c,&buf,0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + pr_info("i2c scan: found device @ 0x%x [%s]\n", + i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -415,7 +420,7 @@ int saa7134_i2c_register(struct saa7134_dev *dev) saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); if (i2c_scan) - do_i2c_scan(dev->name,&dev->i2c_client); + do_i2c_scan(&dev->i2c_client); /* Instantiate the IR receiver device, if present */ saa7134_probe_i2c_ir(dev); diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index dc3d6516e..11a172000 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -18,15 +18,15 @@ * */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> -#include "saa7134-reg.h" -#include "saa7134.h" - #define MODULE_NAME "saa7134" static unsigned int disable_ir; @@ -41,10 +41,14 @@ static int pinnacle_remote; module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */ MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)"); -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) -#define i2cdprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg) +#define input_dbg(fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG pr_fmt("input: " fmt), ## arg); \ + } while (0) +#define ir_dbg(ir, fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG pr_fmt("ir %s: " fmt), ir->name, ## arg); \ + } while (0) /* Helper function for raw decoding at GPIO16 or GPIO18 */ static int saa7134_raw_decode_irq(struct saa7134_dev *dev); @@ -75,7 +79,7 @@ static int build_key(struct saa7134_dev *dev) } data = ir_extract_bits(gpio, ir->mask_keycode); - dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", + input_dbg("build_key gpio=0x%x mask=0x%x data=%d\n", gpio, ir->mask_keycode, data); switch (dev->board) { @@ -119,7 +123,7 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_flydvb_trio: " + ir_dbg(ir, "get_key_flydvb_trio: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -146,12 +150,12 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, msleep(10); continue; } - i2cdprintk("send wake up byte to pic16C505 (IR chip)" + ir_dbg(ir, "send wake up byte to pic16C505 (IR chip)" "failed %dx\n", attempt); return -EIO; } if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -170,7 +174,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_msi_tvanywhere_plus: " + ir_dbg(ir, "get_key_msi_tvanywhere_plus: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -191,7 +195,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* GPIO says there is a button press. Get it. */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -202,7 +206,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* Button pressed */ - dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); + input_dbg("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b); *protocol = RC_TYPE_UNKNOWN; *scancode = b; *toggle = 0; @@ -219,7 +223,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* <dev> is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - i2cdprintk("get_key_kworld_pc150u: " + ir_dbg(ir, "get_key_kworld_pc150u: " "ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -240,7 +244,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* GPIO says there is a button press. Get it. */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -251,7 +255,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* Button pressed */ - dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b); + input_dbg("get_key_kworld_pc150u: Key = 0x%02X\n", b); *protocol = RC_TYPE_UNKNOWN; *scancode = b; *toggle = 0; @@ -265,7 +269,7 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -334,7 +338,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol, ir->c->addr = 0x5a >> 1; if (12 != i2c_master_recv(ir->c, data, 12)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -359,7 +363,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, /* poll IR chip */ if (4 != i2c_master_recv(ir->c, b, 4)) { - i2cdprintk("read error\n"); + ir_dbg(ir, "read error\n"); return -EIO; } @@ -391,7 +395,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol, *scancode = code; *toggle = 0; - i2cdprintk("Pinnacle PCTV key %02x\n", code); + ir_dbg(ir, "Pinnacle PCTV key %02x\n", code); return 1; } @@ -481,6 +485,7 @@ static int __saa7134_ir_start(void *priv) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: @@ -629,6 +634,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: + case SAA7134_BOARD_AVERMEDIA_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: @@ -831,8 +837,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) break; } if (NULL == ir_codes) { - printk("%s: Oops: IR config error [card=%d]\n", - dev->name, dev->board); + pr_err("Oops: IR config error [card=%d]\n", dev->board); return -ENODEV; } @@ -916,7 +921,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) int rc; if (disable_ir) { - dprintk("IR has been disabled, not probing for i2c remote\n"); + input_dbg("IR has been disabled, not probing for i2c remote\n"); return; } @@ -959,7 +964,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) an existing device. Weird... REVISIT: might no longer be needed */ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); - dprintk("probe 0x%02x @ %s: %s\n", + input_dbg("probe 0x%02x @ %s: %s\n", msg_msi.addr, dev->i2c_adap.name, (1 == rc) ? "yes" : "no"); break; @@ -974,7 +979,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) an existing device. Weird... REVISIT: might no longer be needed */ rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1); - dprintk("probe 0x%02x @ %s: %s\n", + input_dbg("probe 0x%02x @ %s: %s\n", msg_msi.addr, dev->i2c_adap.name, (1 == rc) ? "yes" : "no"); break; @@ -1019,7 +1024,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) info.addr = 0x0b; break; default: - dprintk("No I2C IR support for board %x\n", dev->board); + input_dbg("No I2C IR support for board %x\n", dev->board); return; } diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 2709b83d5..4b202fa5f 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -20,23 +20,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int ts_debug; module_param(ts_debug, int, 0644); MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]"); -#define dprintk(fmt, arg...) if (ts_debug) \ - printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg) +#define ts_dbg(fmt, arg...) do { \ + if (ts_debug) \ + printk(KERN_DEBUG pr_fmt("ts: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ static int buffer_activate(struct saa7134_dev *dev, @@ -44,7 +46,7 @@ static int buffer_activate(struct saa7134_dev *dev, struct saa7134_buf *next) { - dprintk("buffer_activate [%p]",buf); + ts_dbg("buffer_activate [%p]", buf); buf->top_seen = 0; if (!dev->ts_started) @@ -53,12 +55,12 @@ static int buffer_activate(struct saa7134_dev *dev, if (NULL == next) next = buf; if (V4L2_FIELD_TOP == dev->ts_field) { - dprintk("- [top] buf=%p next=%p\n",buf,next); + ts_dbg("- [top] buf=%p next=%p\n", buf, next); saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf)); saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next)); dev->ts_field = V4L2_FIELD_BOTTOM; } else { - dprintk("- [bottom] buf=%p next=%p\n",buf,next); + ts_dbg("- [bottom] buf=%p next=%p\n", buf, next); saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); dev->ts_field = V4L2_FIELD_TOP; @@ -95,7 +97,7 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2) struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0); unsigned int lines, llength, size; - dprintk("buffer_prepare [%p]\n", buf); + ts_dbg("buffer_prepare [%p]\n", buf); llength = TS_PACKET_SIZE; lines = dev->ts.nr_packets; @@ -239,7 +241,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) /* Function for stop TS */ int saa7134_ts_stop(struct saa7134_dev *dev) { - dprintk("TS stop\n"); + ts_dbg("TS stop\n"); if (!dev->ts_started) return 0; @@ -261,7 +263,7 @@ int saa7134_ts_stop(struct saa7134_dev *dev) /* Function for start TS */ int saa7134_ts_start(struct saa7134_dev *dev) { - dprintk("TS start\n"); + ts_dbg("TS start\n"); if (WARN_ON(dev->ts_started)) return 0; diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c index 3afbcb70b..21a579309 100644 --- a/drivers/media/pci/saa7134/saa7134-tvaudio.c +++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -29,9 +32,6 @@ #include <linux/freezer.h> #include <asm/div64.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int audio_debug; @@ -49,13 +49,10 @@ static int audio_clock_tweak; module_param(audio_clock_tweak, int, 0644); MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])"); -#define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) -#define d2printk(fmt, arg...) if (audio_debug > 1) \ - printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) - -#define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ - dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) +#define audio_dbg(level, fmt, arg...) do { \ + if (audio_debug >= level) \ + printk(KERN_DEBUG pr_fmt("audio: " fmt), ## arg); \ + } while (0) /* msecs */ #define SCAN_INITIAL_DELAY 1000 @@ -206,13 +203,14 @@ static void mute_input_7134(struct saa7134_dev *dev) if (dev->hw_mute == mute && dev->hw_input == in && !dev->insuspend) { - dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", - mute,in->name); + audio_dbg(1, "mute/input: nothing to do [mute=%d,input=%s]\n", + mute, in->name); return; } - dprintk("ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", - dev->ctl_mute,dev->automute,dev->input->name,mute,in->name); + audio_dbg(1, "ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", + dev->ctl_mute, dev->automute, + dev->input->name, mute, in->name); dev->hw_mute = mute; dev->hw_input = in; @@ -265,8 +263,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev, tweak = audio_clock_tweak; if (note) - dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", - note,audio->name, + audio_dbg(1, "tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", + note, audio->name, audio->carr1 / 1000, audio->carr1 % 1000, audio->carr2 / 1000, audio->carr2 % 1000, acpf, tweak); @@ -334,14 +332,14 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) if (!(dev->tvnorm->id & scan->std)) { value = 0; - dprintk("skipping %d.%03d MHz [%4s]\n", - scan->carr / 1000, scan->carr % 1000, scan->name); + audio_dbg(1, "skipping %d.%03d MHz [%4s]\n", + scan->carr / 1000, scan->carr % 1000, scan->name); return 0; } if (audio_debug > 1) { int i; - dprintk("debug %d:",scan->carr); + audio_dbg(1, "debug %d:", scan->carr); for (i = -150; i <= 150; i += 30) { tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i); saa_readl(SAA7134_LEVEL_READOUT1 >> 2); @@ -349,11 +347,11 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) return -1; value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); if (0 == i) - printk(" # %6d # ",value >> 16); + pr_cont(" # %6d # ", value >> 16); else - printk(" %6d",value >> 16); + pr_cont(" %6d", value >> 16); } - printk("\n"); + pr_cont("\n"); } tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); @@ -371,9 +369,9 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) left >>= 16; right >>= 16; value = left > right ? left - right : right - left; - dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", - scan->carr / 1000, scan->carr % 1000, - scan->name, value, left, right); + audio_dbg(1, "scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", + scan->carr / 1000, scan->carr % 1000, + scan->name, value, left, right); return value; } @@ -389,7 +387,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5; - dprintk("getstereo: fm/stereo: idp=0x%x\n",idp); + audio_dbg(1, "getstereo: fm/stereo: idp=0x%x\n", idp); if (0x03 == (idp & 0x03)) retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; else if (0x05 == (idp & 0x05)) @@ -403,10 +401,11 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_NICAM_FM: case TVAUDIO_NICAM_AM: nicam = saa_readb(SAA7134_AUDIO_STATUS); - dprintk("getstereo: nicam=0x%x\n",nicam); + audio_dbg(1, "getstereo: nicam=0x%x\n", nicam); if (nicam & 0x1) { nicam_status = saa_readb(SAA7134_NICAM_STATUS); - dprintk("getstereo: nicam_status=0x%x\n", nicam_status); + audio_dbg(1, "getstereo: nicam_status=0x%x\n", + nicam_status); switch (nicam_status & 0x03) { case 0x01: @@ -424,7 +423,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au break; } if (retval != -1) - dprintk("found audio subchannels:%s%s%s%s\n", + audio_dbg(1, "found audio subchannels:%s%s%s%s\n", (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "", (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "", @@ -459,8 +458,8 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au case TVAUDIO_FM_BG_STEREO: case TVAUDIO_NICAM_AM: case TVAUDIO_NICAM_FM: - dprintk("setstereo [fm] => %s\n", - name[ mode % ARRAY_SIZE(name) ]); + audio_dbg(1, "setstereo [fm] => %s\n", + name[mode % ARRAY_SIZE(name)]); reg = fm[ mode % ARRAY_SIZE(fm) ]; saa_writeb(SAA7134_FM_DEMATRIX, reg); break; @@ -489,7 +488,8 @@ static int tvaudio_thread(void *data) try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); + audio_dbg(1, "tvaudio thread scan start [%d]\n", + dev->thread.scan1); dev->tvaudio = NULL; saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); @@ -519,7 +519,7 @@ static int tvaudio_thread(void *data) if (1 == nscan) { /* only one candidate -- skip scan ;) */ - dprintk("only one main carrier candidate - skipping scan\n"); + audio_dbg(1, "only one main carrier candidate - skipping scan\n"); max1 = 12345; carrier = default_carrier; } else { @@ -544,26 +544,24 @@ static int tvaudio_thread(void *data) if (0 != carrier && max1 > 2000 && max1 > max2*3) { /* found good carrier */ - dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", - dev->tvnorm->name, carrier/1000, carrier%1000, - max1, max2); + audio_dbg(1, "found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", + dev->tvnorm->name, carrier/1000, carrier%1000, + max1, max2); dev->last_carrier = carrier; dev->automute = 0; } else if (0 != dev->last_carrier) { /* no carrier -- try last detected one as fallback */ carrier = dev->last_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [last detected]\n", - carrier/1000, carrier%1000); + audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [last detected]\n", + carrier/1000, carrier%1000); dev->automute = 1; } else { /* no carrier + no fallback -- use default */ carrier = default_carrier; - dprintk("audio carrier scan failed, " - "using %d.%03d MHz [default]\n", - carrier/1000, carrier%1000); + audio_dbg(1, "audio carrier scan failed, using %d.%03d MHz [default]\n", + carrier/1000, carrier%1000); dev->automute = 1; } tvaudio_setcarrier(dev,carrier,carrier); @@ -661,7 +659,7 @@ static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev) { int state = saa_readb(SAA7135_DSP_RWSTATE); if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - d2printk("%s: resetting error bit\n", dev->name); + audio_dbg(2, "%s: resetting error bit\n", dev->name); saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR); } return 0; @@ -673,18 +671,17 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) state = saa_readb(SAA7135_DSP_RWSTATE); if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { - printk(KERN_WARNING "%s: dsp access error\n", dev->name); + pr_warn("%s: dsp access error\n", dev->name); saa_dsp_reset_error_bit(dev); return -EIO; } while (0 == (state & bit)) { if (unlikely(0 == count)) { - printk("%s: dsp access wait timeout [bit=%s]\n", - dev->name, - (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : - (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : - (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : - "???"); + pr_err("dsp access wait timeout [bit=%s]\n", + (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : + (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : + (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : + "???"); return -EIO; } saa_wait(DSP_DELAY); @@ -699,7 +696,7 @@ int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) { int err; - d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value); + audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n", reg << 2, value); err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); if (err < 0) return err; @@ -786,14 +783,16 @@ static int tvaudio_thread_ddep(void *data) try_to_freeze(); dev->thread.scan1 = dev->thread.scan2; - dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); + audio_dbg(1, "tvaudio thread scan start [%d]\n", + dev->thread.scan1); if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) { /* insmod option override */ norms = (audio_ddep << 2) | 0x01; - dprintk("ddep override: %s\n",stdres[audio_ddep]); + audio_dbg(1, "ddep override: %s\n", + stdres[audio_ddep]); } else if (&card(dev).radio == dev->input) { - dprintk("FM Radio\n"); + audio_dbg(1, "FM Radio\n"); if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { norms = (0x11 << 2) | 0x01; /* set IF frequency to 5.5 MHz */ @@ -816,12 +815,12 @@ static int tvaudio_thread_ddep(void *data) norms |= 0x10; if (0 == norms) norms = 0x7c; /* all */ - dprintk("scanning:%s%s%s%s%s\n", - (norms & 0x04) ? " B/G" : "", - (norms & 0x08) ? " D/K" : "", - (norms & 0x10) ? " L/L'" : "", - (norms & 0x20) ? " I" : "", - (norms & 0x40) ? " M" : ""); + audio_dbg(1, "scanning:%s%s%s%s%s\n", + (norms & 0x04) ? " B/G" : "", + (norms & 0x08) ? " D/K" : "", + (norms & 0x10) ? " L/L'" : "", + (norms & 0x20) ? " I" : "", + (norms & 0x40) ? " M" : ""); } /* kick automatic standard detection */ @@ -836,29 +835,28 @@ static int tvaudio_thread_ddep(void *data) goto restart; value = saa_readl(0x528 >> 2) & 0xffffff; - dprintk("tvaudio thread status: 0x%x [%s%s%s]\n", - value, stdres[value & 0x1f], - (value & 0x000020) ? ",stereo" : "", - (value & 0x000040) ? ",dual" : ""); - dprintk("detailed status: " - "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", - (value & 0x000080) ? " A2/EIAJ pilot tone " : "", - (value & 0x000100) ? " A2/EIAJ dual " : "", - (value & 0x000200) ? " A2/EIAJ stereo " : "", - (value & 0x000400) ? " A2/EIAJ noise mute " : "", - - (value & 0x000800) ? " BTSC/FM radio pilot " : "", - (value & 0x001000) ? " SAP carrier " : "", - (value & 0x002000) ? " BTSC stereo noise mute " : "", - (value & 0x004000) ? " SAP noise mute " : "", - (value & 0x008000) ? " VDSP " : "", - - (value & 0x010000) ? " NICST " : "", - (value & 0x020000) ? " NICDU " : "", - (value & 0x040000) ? " NICAM muted " : "", - (value & 0x080000) ? " NICAM reserve sound " : "", - - (value & 0x100000) ? " init done " : ""); + audio_dbg(1, "tvaudio thread status: 0x%x [%s%s%s]\n", + value, stdres[value & 0x1f], + (value & 0x000020) ? ",stereo" : "", + (value & 0x000040) ? ",dual" : ""); + audio_dbg(1, "detailed status: %s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", + (value & 0x000080) ? " A2/EIAJ pilot tone " : "", + (value & 0x000100) ? " A2/EIAJ dual " : "", + (value & 0x000200) ? " A2/EIAJ stereo " : "", + (value & 0x000400) ? " A2/EIAJ noise mute " : "", + + (value & 0x000800) ? " BTSC/FM radio pilot " : "", + (value & 0x001000) ? " SAP carrier " : "", + (value & 0x002000) ? " BTSC stereo noise mute " : "", + (value & 0x004000) ? " SAP noise mute " : "", + (value & 0x008000) ? " VDSP " : "", + + (value & 0x010000) ? " NICST " : "", + (value & 0x020000) ? " NICDU " : "", + (value & 0x040000) ? " NICAM muted " : "", + (value & 0x080000) ? " NICAM reserve sound " : "", + + (value & 0x100000) ? " init done " : ""); } done: @@ -1031,7 +1029,7 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev) /* start tvaudio thread */ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name); if (IS_ERR(dev->thread.thread)) { - printk(KERN_WARNING "%s: kernel_thread() failed\n", + pr_warn("%s: kernel_thread() failed\n", dev->name); /* XXX: missing error handling here */ } @@ -1061,7 +1059,7 @@ int saa7134_tvaudio_fini(struct saa7134_dev *dev) int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) { if (dev->input->amux != TV) { - dprintk("sound IF not in use, skipping scan\n"); + audio_dbg(1, "sound IF not in use, skipping scan\n"); dev->automute = 0; saa7134_tvaudio_setmute(dev); } else if (dev->thread.thread) { diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 5306e549e..4d36586ad 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -20,14 +20,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ static unsigned int vbi_debug; @@ -38,8 +38,10 @@ static unsigned int vbibufs = 4; module_param(vbibufs, int, 0444); MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); -#define dprintk(fmt, arg...) if (vbi_debug) \ - printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg) +#define vbi_dbg(fmt, arg...) do { \ + if (vbi_debug) \ + printk(KERN_DEBUG pr_fmt("vbi: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ @@ -84,7 +86,7 @@ static int buffer_activate(struct saa7134_dev *dev, struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv; unsigned long control, base; - dprintk("buffer_activate [%p]\n", buf); + vbi_dbg("buffer_activate [%p]\n", buf); buf->top_seen = 0; task_init(dev, buf, TASK_A); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 99d09a756..035039cfa 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "saa7134.h" +#include "saa7134-reg.h" + #include <linux/init.h> #include <linux/list.h> #include <linux/module.h> @@ -31,9 +34,6 @@ #include <media/v4l2-event.h> #include <media/saa6588.h> -#include "saa7134-reg.h" -#include "saa7134.h" - /* ------------------------------------------------------------------ */ unsigned int video_debug; @@ -52,8 +52,10 @@ module_param_string(secam, secam, sizeof(secam), 0644); MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc"); -#define dprintk(fmt, arg...) if (video_debug&0x04) \ - printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) +#define video_dbg(fmt, arg...) do { \ + if (video_debug & 0x04) \ + printk(KERN_DEBUG pr_fmt("video: " fmt), ## arg); \ + } while (0) /* ------------------------------------------------------------------ */ /* Defines for Video Output Port Register at address 0x191 */ @@ -385,7 +387,7 @@ static struct saa7134_format* format_by_fourcc(unsigned int fourcc) static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) { - dprintk("set tv norm = %s\n",norm->name); + video_dbg("set tv norm = %s\n", norm->name); dev->tvnorm = norm; /* setup cropping */ @@ -407,7 +409,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) static void video_mux(struct saa7134_dev *dev, int input) { - dprintk("video input = %d [%s]\n", input, card_in(dev, input).name); + video_dbg("video input = %d [%s]\n", input, card_in(dev, input).name); dev->ctl_input = input; set_tvnorm(dev, dev->tvnorm); saa7134_tvaudio_setinput(dev, &card_in(dev, input)); @@ -531,14 +533,14 @@ static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) mirror = (dev->ctl_mirror) ? 0x02 : 0x00; if (yscale < 2048) { /* LPI */ - dprintk("yscale LPI yscale=%d\n",yscale); + video_dbg("yscale LPI yscale=%d\n", yscale); saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); } else { /* ACM */ val = 0x40 * 1024 / yscale; - dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); + video_dbg("yscale ACM yscale=%d val=0x%x\n", yscale, val); saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); saa_writeb(SAA7134_LUMA_CONTRAST(task), val); saa_writeb(SAA7134_CHROMA_SATURATION(task), val); @@ -573,7 +575,8 @@ static void set_size(struct saa7134_dev *dev, int task, prescale = 1; xscale = 1024 * dev->crop_current.width / prescale / width; yscale = 512 * div * dev->crop_current.height / height; - dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); + video_dbg("prescale=%d xscale=%d yscale=%d\n", + prescale, xscale, yscale); set_h_prescale(dev,task,prescale); saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); @@ -615,7 +618,7 @@ static void set_cliplist(struct saa7134_dev *dev, int reg, saa_writeb(reg + 0, winbits); saa_writeb(reg + 2, cl[i].position & 0xff); saa_writeb(reg + 3, cl[i].position >> 8); - dprintk("clip: %s winbits=%02x pos=%d\n", + video_dbg("clip: %s winbits=%02x pos=%d\n", name,winbits,cl[i].position); reg += 8; } @@ -730,7 +733,7 @@ static int start_preview(struct saa7134_dev *dev) return err; dev->ovfield = dev->win.field; - dprintk("start_preview %dx%d+%d+%d %s field=%s\n", + video_dbg("start_preview %dx%d+%d+%d %s field=%s\n", dev->win.w.width, dev->win.w.height, dev->win.w.left, dev->win.w.top, dev->ovfmt->name, v4l2_field_names[dev->ovfield]); @@ -792,7 +795,7 @@ static int buffer_activate(struct saa7134_dev *dev, unsigned long base,control,bpl; unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ - dprintk("buffer_activate buf=%p\n",buf); + video_dbg("buffer_activate buf=%p\n", buf); buf->top_seen = 0; set_size(dev, TASK_A, dev->width, dev->height, @@ -837,7 +840,7 @@ static int buffer_activate(struct saa7134_dev *dev, base3 = base2 + bpl_uv * lines_uv; if (dev->fmt->uvswap) tmp = base2, base2 = base3, base3 = tmp; - dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", + video_dbg("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", bpl_uv,lines_uv,base2,base3); if (V4L2_FIELD_HAS_BOTH(dev->field)) { /* interlaced */ @@ -1229,7 +1232,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv, int i; if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } f->fmt.win = dev->win; @@ -1305,7 +1308,7 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv, struct saa7134_dev *dev = video_drvdata(file); if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -1339,7 +1342,7 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv, unsigned long flags; if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } if (f->fmt.win.clips == NULL) @@ -1738,7 +1741,7 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (saa7134_no_overlay > 0) { - printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + pr_err("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); return -EINVAL; } @@ -1795,7 +1798,7 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on) if (on) { if (saa7134_no_overlay > 0) { - dprintk("no_overlay\n"); + video_dbg("no_overlay\n"); return -EINVAL; } @@ -2184,7 +2187,7 @@ void saa7134_irq_video_signalchange(struct saa7134_dev *dev) st1 = saa_readb(SAA7134_STATUS_VIDEO1); st2 = saa_readb(SAA7134_STATUS_VIDEO2); - dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", + video_dbg("DCSDT: pll: %s, sync: %s, norm: %s\n", (st1 & 0x40) ? "not locked" : "locked", (st2 & 0x40) ? "no" : "yes", st[st1 & 0x03]); diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 8bf0553b8..6b5f6f45d 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -21,6 +21,8 @@ #define SAA7134_VERSION "0, 2, 17" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/pci.h> #include <linux/i2c.h> #include <linux/videodev2.h> @@ -339,6 +341,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_HAWELL_HW_9004V1 191 #define SAA7134_BOARD_AVERMEDIA_A706 192 #define SAA7134_BOARD_WIS_VOYAGER 193 +#define SAA7134_BOARD_AVERMEDIA_505 194 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 @@ -654,7 +657,8 @@ struct saa7134_dev { /* SAA7134_MPEG_DVB only */ struct vb2_dvb_frontends frontends; int (*original_demod_sleep)(struct dvb_frontend *fe); - int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); + int (*original_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg); #endif void (*gate_ctrl)(struct saa7134_dev *dev, int open); diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index 4f3b1dd18..e7e586c1b 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1373,7 +1373,8 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg, u8 buf[256]; int ret; - dprintk(DBGLVL_API, "%s()\n", __func__); + dprintk(DBGLVL_API, "%s() addr=%x reglen=%d datalen=%d\n", + __func__, addr, reglen, datalen); if (reglen > 4) return -EIO; @@ -1434,7 +1435,8 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, u8 buf[256]; int ret; - dprintk(DBGLVL_API, "%s()\n", __func__); + dprintk(DBGLVL_API, "%s() addr=0x%2x len=0x%x\n", + __func__, addr, datalen); if ((datalen == 0) || (datalen > 232)) return -EIO; @@ -1464,7 +1466,8 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, return -EIO; } - dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len); + dprintk(DBGLVL_API, "%s() len = %d bytes unitid=0x%x\n", __func__, + len, unitid); /* Prepare the send buffer */ /* Bytes 00-03 dest register length diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index 9bd1f73f8..f30758e24 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c index 6c73f5b15..a18fe5d47 100644 --- a/drivers/media/pci/saa7164/saa7164-bus.c +++ b/drivers/media/pci/saa7164/saa7164-bus.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c index 5b72da5ce..c2b738227 100644 --- a/drivers/media/pci/saa7164/saa7164-cards.c +++ b/drivers/media/pci/saa7164/saa7164-cards.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ * attached I2C devices, so we can simplify the virtual i2c mechansms * and keep the -i2c.c implementation clean. */ +#define REGLEN_0bit 0 #define REGLEN_8bit 1 #define REGLEN_16bit 2 @@ -499,6 +500,144 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2255proto] = { + .name = "Hauppauge WinTV-HVR2255(proto)", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x27, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xb2 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x24, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x26, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x1c >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, + [SAA7164_BOARD_HAUPPAUGE_HVR2255] = { + .name = "Hauppauge WinTV-HVR2255", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x28, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-1", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xb2 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x27, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "LGDT3306-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x1c >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, + [SAA7164_BOARD_HAUPPAUGE_HVR2205] = { + .name = "Hauppauge WinTV-HVR2205", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x28, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-1", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x06, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "SI2168-1", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc8 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x25, + .type = SAA7164_UNIT_TUNER, + .name = "SI2157-2", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_0bit, + }, { + .id = 0x27, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "SI2168-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xcc >> 1, + .i2c_reg_len = REGLEN_0bit, + } }, + }, }; const unsigned int saa7164_bcount = ARRAY_SIZE(saa7164_boards); @@ -546,6 +685,21 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8953, .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_5, + }, { + .subvendor = 0x0070, + .subdevice = 0xf111, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2255, + /* Prototype card left here for documenation purposes. + .card = SAA7164_BOARD_HAUPPAUGE_HVR2255proto, + */ + }, { + .subvendor = 0x0070, + .subdevice = 0xf123, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, + }, { + .subvendor = 0x0070, + .subdevice = 0xf120, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2205, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -594,12 +748,26 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + case SAA7164_BOARD_HAUPPAUGE_HVR2205: /* + HVR2200 / HVR2250 GPIO 2: s5h1411 / tda10048-1 demod reset GPIO 3: s5h1411 / tda10048-2 demod reset GPIO 7: IRBlaster Zilog reset */ + /* HVR2255 + * GPIO 2: lgdg3306-1 demod reset + * GPIO 3: lgdt3306-2 demod reset + */ + + /* HVR2205 + * GPIO 2: si2168-1 demod reset + * GPIO 3: si2168-2 demod reset + */ + /* Reset parts by going in and out of reset */ saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2); saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3); @@ -647,6 +815,21 @@ static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data) /* WinTV-HVR2200 (PCIe, Retail, half-height) * DVB-T (TDA18271/TDA10048) and basic analog, no IR */ break; + case 151009: + /* First production board rev B2I6 */ + /* WinTV-HVR2205 (PCIe, Retail, full-height bracket) + * DVB-T/T2/C (SI2157/SI2168) and basic analog, FM */ + break; + case 151609: + /* First production board rev B2I6 */ + /* WinTV-HVR2205 (PCIe, Retail, half-height bracket) + * DVB-T/T2/C (SI2157/SI2168) and basic analog, FM */ + break; + case 151061: + /* First production board rev B1I6 */ + /* WinTV-HVR2255 (PCIe, Retail, full-height bracket) + * ATSC/QAM (SI2157/LGDT3306) and basic analog, FM */ + break; default: printk(KERN_ERR "%s: Warning: Unknown Hauppauge model #%d\n", dev->name, tv.model); @@ -676,6 +859,9 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + case SAA7164_BOARD_HAUPPAUGE_HVR2205: hauppauge_eeprom(dev, &eeprom[0]); break; } diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index cfabcbacc..3285c37b4 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 9cf3c6cba..3206a826b 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -85,6 +85,11 @@ module_param(guard_checking, int, 0644); MODULE_PARM_DESC(guard_checking, "enable dma sanity checking for buffer overruns"); +static bool enable_msi = true; +module_param(enable_msi, bool, 0444); +MODULE_PARM_DESC(enable_msi, + "enable the use of an msi interrupt if available"); + static unsigned int saa7164_devcount; static DEFINE_MUTEX(devlist); @@ -618,12 +623,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_port *port) static irqreturn_t saa7164_irq(int irq, void *dev_id) { struct saa7164_dev *dev = dev_id; - struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1]; - struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2]; - struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1]; - struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2]; - struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1]; - struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2]; + struct saa7164_port *porta, *portb, *portc, *portd, *porte, *portf; u32 intid, intstat[INT_SIZE/4]; int i, handled = 0, bit; @@ -634,6 +634,13 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) goto out; } + porta = &dev->ports[SAA7164_PORT_TS1]; + portb = &dev->ports[SAA7164_PORT_TS2]; + portc = &dev->ports[SAA7164_PORT_ENC1]; + portd = &dev->ports[SAA7164_PORT_ENC2]; + porte = &dev->ports[SAA7164_PORT_VBI1]; + portf = &dev->ports[SAA7164_PORT_VBI2]; + /* Check that the hardware is accessible. If the status bytes are * 0xFF then the device is not accessible, the the IRQ belongs * to another driver. @@ -1184,6 +1191,39 @@ static int saa7164_thread_function(void *data) return 0; } +static bool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev) +{ + int err; + + if (!enable_msi) { + printk(KERN_WARNING "%s() MSI disabled by module parameter 'enable_msi'" + , __func__); + return false; + } + + err = pci_enable_msi(pci_dev); + + if (err) { + printk(KERN_ERR "%s() Failed to enable MSI interrupt." + " Falling back to a shared IRQ\n", __func__); + return false; + } + + /* no error - so request an msi interrupt */ + err = request_irq(pci_dev->irq, saa7164_irq, 0, + dev->name, dev); + + if (err) { + /* fall back to legacy interrupt */ + printk(KERN_ERR "%s() Failed to get an MSI interrupt." + " Falling back to a shared IRQ\n", __func__); + pci_disable_msi(pci_dev); + return false; + } + + return true; +} + static int saa7164_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { @@ -1230,13 +1270,22 @@ static int saa7164_initdev(struct pci_dev *pci_dev, goto fail_irq; } - err = request_irq(pci_dev->irq, saa7164_irq, - IRQF_SHARED, dev->name, dev); - if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, - pci_dev->irq); - err = -EIO; - goto fail_irq; + /* irq bit */ + if (saa7164_enable_msi(pci_dev, dev)) { + dev->msi = true; + } else { + /* if we have an error (i.e. we don't have an interrupt) + or msi is not enabled - fallback to shared interrupt */ + + err = request_irq(pci_dev->irq, saa7164_irq, + IRQF_SHARED, dev->name, dev); + + if (err < 0) { + printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name, + pci_dev->irq); + err = -EIO; + goto fail_irq; + } } pci_set_drvdata(pci_dev, dev); @@ -1439,6 +1488,11 @@ static void saa7164_finidev(struct pci_dev *pci_dev) /* unregister stuff */ free_irq(pci_dev->irq, dev); + if (dev->msi) { + pci_disable_msi(pci_dev); + dev->msi = false; + } + pci_disable_device(pci_dev); mutex_lock(&devlist); diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index 16ae71592..e9a783b71 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,9 @@ #include "tda10048.h" #include "tda18271.h" #include "s5h1411.h" +#include "si2157.h" +#include "si2168.h" +#include "lgdt3306a.h" #define DRIVER_NAME "saa7164" @@ -82,6 +85,65 @@ static struct s5h1411_config hauppauge_s5h1411_config = { .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, }; +static struct lgdt3306a_config hauppauge_hvr2255a_config = { + .i2c_addr = 0xb2 >> 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + +static struct lgdt3306a_config hauppauge_hvr2255b_config = { + .i2c_addr = 0x1c >> 1, + .qam_if_khz = 4000, + .vsb_if_khz = 3250, + .deny_i2c_rptr = 1, /* Disabled */ + .spectral_inversion = 0, /* Disabled */ + .mpeg_mode = LGDT3306A_MPEG_SERIAL, + .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, + .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, + .xtalMHz = 25, /* 24 or 25 */ +}; + +static struct si2157_config hauppauge_hvr2255_tuner_config = { + .inversion = 1, + .if_port = 1, +}; + +static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter, + struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg) +{ + struct i2c_board_info bi; + struct i2c_client *tuner; + + cfg->fe = fe; + + memset(&bi, 0, sizeof(bi)); + + strlcpy(bi.type, "si2157", I2C_NAME_SIZE); + bi.platform_data = cfg; + bi.addr = addr8bit >> 1; + + request_module(bi.type); + + tuner = i2c_new_device(adapter, &bi); + if (tuner == NULL || tuner->dev.driver == NULL) + return -ENODEV; + + if (!try_module_get(tuner->dev.driver->owner)) { + i2c_unregister_device(tuner); + return -ENODEV; + } + + port->i2c_client_tuner = tuner; + + return 0; +} + static int saa7164_dvb_stop_port(struct saa7164_port *port) { struct saa7164_dev *dev = port->dev; @@ -242,14 +304,16 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - mutex_lock(&dvb->lock); - if (dvb->feeding++ == 0) { - /* Start transport */ - ret = saa7164_dvb_start_port(port); + if (dvb) { + mutex_lock(&dvb->lock); + if (dvb->feeding++ == 0) { + /* Start transport */ + ret = saa7164_dvb_start_port(port); + } + mutex_unlock(&dvb->lock); + dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", + __func__, port->nr, dvb->feeding); } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); return ret; } @@ -264,14 +328,16 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed) dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr); - mutex_lock(&dvb->lock); - if (--dvb->feeding == 0) { - /* Stop transport */ - ret = saa7164_dvb_stop_streaming(port); + if (dvb) { + mutex_lock(&dvb->lock); + if (--dvb->feeding == 0) { + /* Stop transport */ + ret = saa7164_dvb_stop_streaming(port); + } + mutex_unlock(&dvb->lock); + dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", + __func__, port->nr, dvb->feeding); } - mutex_unlock(&dvb->lock); - dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n", - __func__, port->nr, dvb->feeding); return ret; } @@ -425,6 +491,7 @@ int saa7164_dvb_unregister(struct saa7164_port *port) struct saa7164_dev *dev = port->dev; struct saa7164_buffer *b; struct list_head *c, *n; + struct i2c_client *client; dprintk(DBGLVL_DVB, "%s()\n", __func__); @@ -443,6 +510,20 @@ int saa7164_dvb_unregister(struct saa7164_port *port) if (dvb->frontend == NULL) return 0; + /* remove I2C client for tuner */ + client = port->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = port->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); @@ -462,6 +543,12 @@ int saa7164_dvb_register(struct saa7164_port *port) struct saa7164_dev *dev = port->dev; struct saa7164_dvb *dvb = &port->dvb; struct saa7164_i2c *i2c_bus = NULL; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + struct i2c_adapter *adapter; + struct i2c_board_info info; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; int ret; dprintk(DBGLVL_DVB, "%s()\n", __func__); @@ -528,6 +615,126 @@ int saa7164_dvb_register(struct saa7164_port *port) } break; + case SAA7164_BOARD_HAUPPAUGE_HVR2255proto: + case SAA7164_BOARD_HAUPPAUGE_HVR2255: + i2c_bus = &dev->i2c_bus[2]; + + if (port->nr == 0) { + port->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr2255a_config, &i2c_bus->i2c_adap); + } else { + port->dvb.frontend = dvb_attach(lgdt3306a_attach, + &hauppauge_hvr2255b_config, &i2c_bus->i2c_adap); + } + + if (port->dvb.frontend != NULL) { + + if (port->nr == 0) { + si2157_attach(port, &dev->i2c_bus[0].i2c_adap, + port->dvb.frontend, 0xc0, + &hauppauge_hvr2255_tuner_config); + } else { + si2157_attach(port, &dev->i2c_bus[1].i2c_adap, + port->dvb.frontend, 0xc0, + &hauppauge_hvr2255_tuner_config); + } + } + break; + case SAA7164_BOARD_HAUPPAUGE_HVR2205: + + if (port->nr == 0) { + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &port->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0xc8 >> 1; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&dev->i2c_bus[2].i2c_adap, + &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.if_port = 1; + si2157_config.fe = port->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0xc0 >> 1; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[0].i2c_adap, + &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + } else { + /* attach frontend */ + memset(&si2168_config, 0, sizeof(si2168_config)); + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &port->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0xcc >> 1; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&dev->i2c_bus[2].i2c_adap, + &info); + if (!client_demod || !client_demod->dev.driver) + goto frontend_detach; + + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = port->dvb.frontend; + si2157_config.if_port = 1; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0xc0 >> 1; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, + &info); + if (!client_tuner || !client_tuner->dev.driver) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + } + + break; default: printk(KERN_ERR "%s: The frontend isn't supported\n", dev->name); @@ -548,5 +755,9 @@ int saa7164_dvb_register(struct saa7164_port *port) } return 0; + +frontend_detach: + printk(KERN_ERR "%s() Frontend/I2C initialization failed\n", __func__); + return -1; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 7a0a65146..4434e0f28 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index 95c5d7034..19662cdd2 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 4f7e3b422..0342d8491 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,9 +39,10 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n", __func__, num, msgs[i].addr, msgs[i].len); if (msgs[i].flags & I2C_M_RD) { - /* Unsupported - Yet*/ - printk(KERN_ERR "%s() Unsupported - Yet\n", __func__); - continue; + retval = saa7164_api_i2c_read(bus, + msgs[i].addr, + 0 /* reglen */, + NULL /* reg */, msgs[i].len, msgs[i].buf); } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr) { /* write then read from same address */ diff --git a/drivers/media/pci/saa7164/saa7164-reg.h b/drivers/media/pci/saa7164/saa7164-reg.h index 2bbf81583..37521a2ee 100644 --- a/drivers/media/pci/saa7164/saa7164-reg.h +++ b/drivers/media/pci/saa7164/saa7164-reg.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h index f48ba978f..1efba6c64 100644 --- a/drivers/media/pci/saa7164/saa7164-types.h +++ b/drivers/media/pci/saa7164/saa7164-types.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 06117e6c0..859fd03d8 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h index cd1a07ce2..18906e0c8 100644 --- a/drivers/media/pci/saa7164/saa7164.h +++ b/drivers/media/pci/saa7164/saa7164.h @@ -1,7 +1,7 @@ /* * Driver for the NXP SAA7164 PCIe bridge * - * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com> + * Copyright (c) 2010-2015 Steven Toth <stoth@kernellabs.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -83,6 +83,9 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 #define SAA7164_BOARD_HAUPPAUGE_HVR2200_5 10 +#define SAA7164_BOARD_HAUPPAUGE_HVR2255proto 11 +#define SAA7164_BOARD_HAUPPAUGE_HVR2255 12 +#define SAA7164_BOARD_HAUPPAUGE_HVR2205 13 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 @@ -371,6 +374,8 @@ struct saa7164_port { /* --- DVB Transport Specific --- */ struct saa7164_dvb dvb; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; /* --- Encoder/V4L related attributes --- */ /* Encoder */ @@ -459,6 +464,7 @@ struct saa7164_dev { /* Interrupt status and ack registers */ u32 int_status; u32 int_ack; + bool msi; struct cmd cmds[SAA_CMD_MAX_MSG_UNITS]; struct mutex lock; diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c index 411592524..143fd7899 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie.c @@ -657,6 +657,7 @@ static int smi_dvbsky_sit2_fe_attach(struct smi_port *port) /* attach tuner */ memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = port->fe; + si2157_config.if_port = 1; memset(&client_info, 0, sizeof(struct i2c_board_info)); strlcpy(client_info.type, "si2157", I2C_NAME_SIZE); diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index d384a6b0b..59b3a36a3 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -813,7 +813,7 @@ static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip) /* Disable acquisition */ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA); /* Remove the active buffer from the list */ - do_gettimeofday(&vip->active->vb.v4l2_buf.timestamp); + v4l2_get_timestamp(&vip->active->vb.v4l2_buf.timestamp); vip->active->vb.v4l2_buf.sequence = vip->sequence++; vb2_buffer_done(&vip->active->vb, VB2_BUF_STATE_DONE); } @@ -864,6 +864,7 @@ static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip) vip->vb_vidq.buf_struct_size = sizeof(struct vip_buffer); vip->vb_vidq.ops = &vip_video_qops; vip->vb_vidq.mem_ops = &vb2_dma_contig_memops; + vip->vb_vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; err = vb2_queue_init(&vip->vb_vidq); if (err) return err; diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 2a270a00e..3bfbf8e0f 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1172,7 +1172,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num, ******************************************************************************/ -static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int av7110_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { struct av7110* av7110 = fe->dvb->priv; @@ -1197,7 +1197,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe, } static int av7110_diseqc_send_burst(struct dvb_frontend* fe, - fe_sec_mini_cmd_t minicmd) + enum fe_sec_mini_cmd minicmd) { struct av7110* av7110 = fe->dvb->priv; @@ -1946,7 +1946,7 @@ static struct l64781_config grundig_29504_401_config = { -static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status) +static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status) { int ret = 0; int synced = (status & FE_HAS_LOCK) ? 1 : 0; @@ -2008,7 +2008,8 @@ static int av7110_fe_init(struct dvb_frontend* fe) return ret; } -static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status) +static int av7110_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) { struct av7110* av7110 = fe->dvb->priv; @@ -2043,7 +2044,8 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe, return ret; } -static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int av7110_fe_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct av7110* av7110 = fe->dvb->priv; @@ -2055,7 +2057,8 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_ return ret; } -static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int av7110_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct av7110* av7110 = fe->dvb->priv; @@ -2067,7 +2070,8 @@ static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return ret; } -static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int av7110_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct av7110* av7110 = fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 835635b0c..3a55927ed 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -269,25 +269,30 @@ struct av7110 { unsigned long size_root; struct dvb_frontend* fe; - fe_status_t fe_status; + enum fe_status fe_status; struct mutex ioctl_mutex; /* crash recovery */ void (*recover)(struct av7110* av7110); - fe_sec_voltage_t saved_voltage; - fe_sec_tone_mode_t saved_tone; + enum fe_sec_voltage saved_voltage; + enum fe_sec_tone_mode saved_tone; struct dvb_diseqc_master_cmd saved_master_cmd; - fe_sec_mini_cmd_t saved_minicmd; + enum fe_sec_mini_cmd saved_minicmd; int (*fe_init)(struct dvb_frontend* fe); - int (*fe_read_status)(struct dvb_frontend* fe, fe_status_t* status); - int (*fe_diseqc_reset_overload)(struct dvb_frontend* fe); - int (*fe_diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); - int (*fe_diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); - int (*fe_set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); - int (*fe_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); - int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); + int (*fe_read_status)(struct dvb_frontend *fe, enum fe_status *status); + int (*fe_diseqc_reset_overload)(struct dvb_frontend *fe); + int (*fe_diseqc_send_master_cmd)(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd); + int (*fe_diseqc_send_burst)(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd); + int (*fe_set_tone)(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone); + int (*fe_set_voltage)(struct dvb_frontend *fe, + enum fe_sec_voltage voltage); + int (*fe_dishnetwork_send_legacy_command)(struct dvb_frontend *fe, + unsigned long cmd); int (*fe_set_frontend)(struct dvb_frontend *fe); }; diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 23e05499b..e9674b400 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -161,7 +161,8 @@ static int start_ts_capture(struct budget *budget) return 0; } -static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status) +static int budget_read_fe_status(struct dvb_frontend *fe, + enum fe_status *status) { struct budget *budget = (struct budget *) fe->dvb->priv; int synced; diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index a4d8867e1..b5b65962c 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -128,9 +128,9 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long return 0; } -/* shamelessly copy/pasted from budget.c -*/ -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +/* shamelessly copy/pasted from budget.c */ +static int budget_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -159,7 +159,8 @@ static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_dis return 0; } -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -223,7 +224,8 @@ static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, return 0; } -static int budget_patch_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int budget_patch_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; @@ -252,7 +254,8 @@ static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct d return 0; } -static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_patch_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 449c09eae..2eaf748b5 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -132,7 +132,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long * Voltage must be set here. * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL */ -static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) +static int SetVoltage_Activy(struct budget *budget, + enum fe_sec_voltage voltage) { struct saa7146_dev *dev=budget->dev; @@ -157,14 +158,16 @@ static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) return 0; } -static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +static int siemens_budget_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) { struct budget* budget = (struct budget*) fe->dvb->priv; return SetVoltage_Activy (budget, voltage); } -static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +static int budget_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) { struct budget* budget = (struct budget*) fe->dvb->priv; @@ -193,7 +196,8 @@ static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_dis return 0; } -static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) +static int budget_diseqc_send_burst(struct dvb_frontend *fe, + enum fe_sec_mini_cmd minicmd) { struct budget* budget = (struct budget*) fe->dvb->priv; diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h index 3d8a806c2..1ccbe1a49 100644 --- a/drivers/media/pci/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -72,7 +72,7 @@ struct budget { struct dvb_adapter dvb_adapter; struct dvb_frontend *dvb_frontend; - int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status); + int (*read_fe_status)(struct dvb_frontend *fe, enum fe_status *status); int fe_synced; void *priv; diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index b6801e035..40119b3c5 100644 --- a/drivers/media/pci/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -1584,14 +1584,11 @@ zoran_init_hardware (struct zoran *zr) jpeg_codec_sleep(zr, 1); jpeg_codec_sleep(zr, 0); - /* set individual interrupt enables (without GIRQ1) - * but don't global enable until zoran_open() */ - - //btwrite(IRQ_MASK & ~ZR36057_ISR_GIRQ1, ZR36057_ICR); // SW - // It looks like using only JPEGRepIRQEn is not always reliable, - // may be when JPEG codec crashes it won't generate IRQ? So, - /*CP*/ // btwrite(IRQ_MASK, ZR36057_ICR); // Enable Vsync interrupts too. SM WHY ? LP - zr36057_init_vfe(zr); + /* + * set individual interrupt enables (without GIRQ1) + * but don't global enable until zoran_open() + */ + zr36057_init_vfe(zr); zr36057_enable_jpg(zr, BUZ_MODE_IDLE); |