diff options
author | David S. Miller <davem@davemloft.net> | 2010-01-23 07:45:46 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-01-23 07:45:46 +0100 |
commit | 6be325719b3e54624397e413efd4b33a997e55a3 (patch) | |
tree | 57f321a56794cab2222e179b16731e0d76a4a68a /drivers/media | |
parent | be2net: fix bug in rx page posting (diff) | |
parent | Linux 2.6.33-rc5 (diff) | |
download | linux-6be325719b3e54624397e413efd4b33a997e55a3.tar.xz linux-6be325719b3e54624397e413efd4b33a997e55a3.zip |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Diffstat (limited to 'drivers/media')
239 files changed, 16597 insertions, 3741 deletions
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig new file mode 100644 index 000000000000..4dde7d180a32 --- /dev/null +++ b/drivers/media/IR/Kconfig @@ -0,0 +1,9 @@ +config IR_CORE + tristate + depends on INPUT + default INPUT + +config VIDEO_IR + tristate + depends on IR_CORE + default IR_CORE diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile new file mode 100644 index 000000000000..df5ddb4bbbf7 --- /dev/null +++ b/drivers/media/IR/Makefile @@ -0,0 +1,5 @@ +ir-common-objs := ir-functions.o ir-keymaps.o +ir-core-objs := ir-keytable.o + +obj-$(CONFIG_IR_CORE) += ir-core.o +obj-$(CONFIG_VIDEO_IR) += ir-common.o diff --git a/drivers/media/common/ir-functions.c b/drivers/media/IR/ir-functions.c index e616f624ceaa..776a136616d6 100644 --- a/drivers/media/common/ir-functions.c +++ b/drivers/media/IR/ir-functions.c @@ -34,9 +34,6 @@ static int repeat = 1; module_param(repeat, int, 0444); MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)"); -int media_ir_debug; /* media_ir_debug level (0,1,2) */ -module_param_named(debug, media_ir_debug, int, 0644); - /* -------------------------------------------------------------------------- */ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) @@ -55,25 +52,10 @@ static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir) /* -------------------------------------------------------------------------- */ int ir_input_init(struct input_dev *dev, struct ir_input_state *ir, - int ir_type, struct ir_scancode_table *ir_codes) + int ir_type) { ir->ir_type = ir_type; - ir->keytable.size = ir_roundup_tablesize(ir_codes->size); - ir->keytable.scan = kzalloc(ir->keytable.size * - sizeof(struct ir_scancode), GFP_KERNEL); - if (!ir->keytable.scan) - return -ENOMEM; - - IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", - ir->keytable.size, - ir->keytable.size * sizeof(ir->keytable.scan)); - - ir_copy_table(&ir->keytable, ir_codes); - ir_set_keycode_table(dev, &ir->keytable); - - clear_bit(0, dev->keybit); - set_bit(EV_KEY, dev->evbit); if (repeat) set_bit(EV_REP, dev->evbit); diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/IR/ir-keymaps.c index 328c973a0838..9bbe6b1e9871 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/IR/ir-keymaps.c @@ -1847,76 +1847,6 @@ struct ir_scancode_table ir_codes_hauppauge_new_table = { }; EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new_table); -/* - * Hauppauge:the newer, gray remotes (seems there are multiple - * slightly different versions), shipped with cx88+ivtv cards. - * - * This table contains the complete RC5 code, instead of just the data part - */ -static struct ir_scancode ir_codes_rc5_hauppauge_new[] = { - /* Keys 0 to 9 */ - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, - - { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e0b, KEY_RED }, /* red button */ - { 0x1e0c, KEY_RADIO }, - { 0x1e0d, KEY_MENU }, - { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ - { 0x1e0f, KEY_MUTE }, - { 0x1e10, KEY_VOLUMEUP }, - { 0x1e11, KEY_VOLUMEDOWN }, - { 0x1e12, KEY_PREVIOUS }, /* previous channel */ - { 0x1e14, KEY_UP }, - { 0x1e15, KEY_DOWN }, - { 0x1e16, KEY_LEFT }, - { 0x1e17, KEY_RIGHT }, - { 0x1e18, KEY_VIDEO }, /* Videos */ - { 0x1e19, KEY_AUDIO }, /* Music */ - /* 0x1e1a: Pictures - presume this means - "Multimedia Home Platform" - - no "PICTURES" key in input.h - */ - { 0x1e1a, KEY_MHP }, - - { 0x1e1b, KEY_EPG }, /* Guide */ - { 0x1e1c, KEY_TV }, - { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1e1f, KEY_EXIT }, /* back/exit */ - { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ - { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ - { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ - { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ - { 0x1e25, KEY_ENTER }, /* OK */ - { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ - { 0x1e29, KEY_BLUE }, /* blue key */ - { 0x1e2e, KEY_GREEN }, /* green button */ - { 0x1e30, KEY_PAUSE }, /* pause */ - { 0x1e32, KEY_REWIND }, /* backward << */ - { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ - { 0x1e35, KEY_PLAY }, - { 0x1e36, KEY_STOP }, - { 0x1e37, KEY_RECORD }, /* recording */ - { 0x1e38, KEY_YELLOW }, /* yellow key */ - { 0x1e3b, KEY_SELECT }, /* top right button */ - { 0x1e3c, KEY_ZOOM }, /* full */ - { 0x1e3d, KEY_POWER }, /* system power (green button) */ -}; - -struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = { - .scan = ir_codes_rc5_hauppauge_new, - .size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new), -}; -EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table); - static struct ir_scancode ir_codes_npgtech[] = { { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ { 0x2a, KEY_FRONT }, @@ -3314,3 +3244,152 @@ struct ir_scancode_table ir_codes_gadmei_rm008z_table = { }; EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z_table); +/************************************************************* + * COMPLETE SCANCODE TABLES + * Instead of just a partial scancode, the tables bellow + * contains the complete scancode and the receiver protocol + *************************************************************/ + +/* + * Hauppauge:the newer, gray remotes (seems there are multiple + * slightly different versions), shipped with cx88+ivtv cards. + * + * This table contains the complete RC5 code, instead of just the data part + */ +static struct ir_scancode ir_codes_rc5_hauppauge_new[] = { + /* Keys 0 to 9 */ + { 0x1e00, KEY_0 }, + { 0x1e01, KEY_1 }, + { 0x1e02, KEY_2 }, + { 0x1e03, KEY_3 }, + { 0x1e04, KEY_4 }, + { 0x1e05, KEY_5 }, + { 0x1e06, KEY_6 }, + { 0x1e07, KEY_7 }, + { 0x1e08, KEY_8 }, + { 0x1e09, KEY_9 }, + + { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ + { 0x1e0b, KEY_RED }, /* red button */ + { 0x1e0c, KEY_RADIO }, + { 0x1e0d, KEY_MENU }, + { 0x1e0e, KEY_SUBTITLE }, /* also the # key */ + { 0x1e0f, KEY_MUTE }, + { 0x1e10, KEY_VOLUMEUP }, + { 0x1e11, KEY_VOLUMEDOWN }, + { 0x1e12, KEY_PREVIOUS }, /* previous channel */ + { 0x1e14, KEY_UP }, + { 0x1e15, KEY_DOWN }, + { 0x1e16, KEY_LEFT }, + { 0x1e17, KEY_RIGHT }, + { 0x1e18, KEY_VIDEO }, /* Videos */ + { 0x1e19, KEY_AUDIO }, /* Music */ + /* 0x1e1a: Pictures - presume this means + "Multimedia Home Platform" - + no "PICTURES" key in input.h + */ + { 0x1e1a, KEY_MHP }, + + { 0x1e1b, KEY_EPG }, /* Guide */ + { 0x1e1c, KEY_TV }, + { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ + { 0x1e1f, KEY_EXIT }, /* back/exit */ + { 0x1e20, KEY_CHANNELUP }, /* channel / program + */ + { 0x1e21, KEY_CHANNELDOWN }, /* channel / program - */ + { 0x1e22, KEY_CHANNEL }, /* source (old black remote) */ + { 0x1e24, KEY_PREVIOUSSONG }, /* replay |< */ + { 0x1e25, KEY_ENTER }, /* OK */ + { 0x1e26, KEY_SLEEP }, /* minimize (old black remote) */ + { 0x1e29, KEY_BLUE }, /* blue key */ + { 0x1e2e, KEY_GREEN }, /* green button */ + { 0x1e30, KEY_PAUSE }, /* pause */ + { 0x1e32, KEY_REWIND }, /* backward << */ + { 0x1e34, KEY_FASTFORWARD }, /* forward >> */ + { 0x1e35, KEY_PLAY }, + { 0x1e36, KEY_STOP }, + { 0x1e37, KEY_RECORD }, /* recording */ + { 0x1e38, KEY_YELLOW }, /* yellow key */ + { 0x1e3b, KEY_SELECT }, /* top right button */ + { 0x1e3c, KEY_ZOOM }, /* full */ + { 0x1e3d, KEY_POWER }, /* system power (green button) */ +}; + +struct ir_scancode_table ir_codes_rc5_hauppauge_new_table = { + .scan = ir_codes_rc5_hauppauge_new, + .size = ARRAY_SIZE(ir_codes_rc5_hauppauge_new), + .ir_type = IR_TYPE_RC5, +}; +EXPORT_SYMBOL_GPL(ir_codes_rc5_hauppauge_new_table); + +/* Terratec Cinergy Hybrid T USB XS FM + Mauro Carvalho Chehab <mchehab@redhat.com> + */ +static struct ir_scancode ir_codes_nec_terratec_cinergy_xs[] = { + { 0x1441, KEY_HOME}, + { 0x1401, KEY_POWER2}, + + { 0x1442, KEY_MENU}, /* DVD menu */ + { 0x1443, KEY_SUBTITLE}, + { 0x1444, KEY_TEXT}, /* Teletext */ + { 0x1445, KEY_DELETE}, + + { 0x1402, KEY_1}, + { 0x1403, KEY_2}, + { 0x1404, KEY_3}, + { 0x1405, KEY_4}, + { 0x1406, KEY_5}, + { 0x1407, KEY_6}, + { 0x1408, KEY_7}, + { 0x1409, KEY_8}, + { 0x140a, KEY_9}, + { 0x140c, KEY_0}, + + { 0x140b, KEY_TUNER}, /* AV */ + { 0x140d, KEY_MODE}, /* A.B */ + + { 0x1446, KEY_TV}, + { 0x1447, KEY_DVD}, + { 0x1449, KEY_VIDEO}, + { 0x144a, KEY_RADIO}, /* Music */ + { 0x144b, KEY_CAMERA}, /* PIC */ + + { 0x1410, KEY_UP}, + { 0x1411, KEY_LEFT}, + { 0x1412, KEY_OK}, + { 0x1413, KEY_RIGHT}, + { 0x1414, KEY_DOWN}, + + { 0x140f, KEY_EPG}, + { 0x1416, KEY_INFO}, + { 0x144d, KEY_BACKSPACE}, + + { 0x141c, KEY_VOLUMEUP}, + { 0x141e, KEY_VOLUMEDOWN}, + + { 0x144c, KEY_PLAY}, + { 0x141d, KEY_MUTE}, + + { 0x141b, KEY_CHANNELUP}, + { 0x141f, KEY_CHANNELDOWN}, + + { 0x1417, KEY_RED}, + { 0x1418, KEY_GREEN}, + { 0x1419, KEY_YELLOW}, + { 0x141a, KEY_BLUE}, + + { 0x1458, KEY_RECORD}, + { 0x1448, KEY_STOP}, + { 0x1440, KEY_PAUSE}, + + { 0x1454, KEY_LAST}, + { 0x144e, KEY_REWIND}, + { 0x144f, KEY_FASTFORWARD}, + { 0x145c, KEY_NEXT}, +}; +struct ir_scancode_table ir_codes_nec_terratec_cinergy_xs_table = { + .scan = ir_codes_nec_terratec_cinergy_xs, + .size = ARRAY_SIZE(ir_codes_nec_terratec_cinergy_xs), + .ir_type = IR_TYPE_NEC, +}; +EXPORT_SYMBOL_GPL(ir_codes_nec_terratec_cinergy_xs_table); + diff --git a/drivers/media/common/ir-keytable.c b/drivers/media/IR/ir-keytable.c index 26ce5bc2fdd5..b521ed9d6e2e 100644 --- a/drivers/media/common/ir-keytable.c +++ b/drivers/media/IR/ir-keytable.c @@ -1,10 +1,19 @@ /* ir-register.c - handle IR scancode->keycode tables * * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.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 version 2 of the License. + * + * 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/usb/input.h> +#include <linux/input.h> #include <media/ir-common.h> #define IR_TAB_MIN_SIZE 32 @@ -72,6 +81,7 @@ int ir_roundup_tablesize(int n_elems) return n_elems; } +EXPORT_SYMBOL_GPL(ir_roundup_tablesize); /** * ir_copy_table() - copies a keytable, discarding the unused entries @@ -100,6 +110,7 @@ int ir_copy_table(struct ir_scancode_table *destin, return 0; } +EXPORT_SYMBOL_GPL(ir_copy_table); /** * ir_getkeycode() - get a keycode at the evdev scancode ->keycode table @@ -114,7 +125,8 @@ static int ir_getkeycode(struct input_dev *dev, int scancode, int *keycode) { int elem; - struct ir_scancode_table *rc_tab = input_get_drvdata(dev); + struct ir_input_dev *ir_dev = input_get_drvdata(dev); + struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; elem = ir_seek_table(rc_tab, scancode); if (elem >= 0) { @@ -136,7 +148,6 @@ static int ir_getkeycode(struct input_dev *dev, return 0; } - /** * ir_is_resize_needed() - Check if the table needs rezise * @table: keycode table that may need to resize @@ -286,7 +297,8 @@ static int ir_setkeycode(struct input_dev *dev, int scancode, int keycode) { int rc = 0; - struct ir_scancode_table *rc_tab = input_get_drvdata(dev); + struct ir_input_dev *ir_dev = input_get_drvdata(dev); + struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; struct ir_scancode *keymap = rc_tab->scan; unsigned long flags; @@ -360,7 +372,8 @@ static int ir_setkeycode(struct input_dev *dev, */ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) { - struct ir_scancode_table *rc_tab = input_get_drvdata(dev); + struct ir_input_dev *ir_dev = input_get_drvdata(dev); + struct ir_scancode_table *rc_tab = &ir_dev->rc_tab; struct ir_scancode *keymap = rc_tab->scan; int elem; @@ -378,9 +391,10 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) /* Reports userspace that an unknown keycode were got */ return KEY_RESERVED; } +EXPORT_SYMBOL_GPL(ir_g_keycode_from_table); /** - * ir_set_keycode_table() - sets the IR keycode table and add the handlers + * ir_input_register() - sets the IR keycode table and add the handlers * for keymap table get/set * @input_dev: the struct input_dev descriptor of the device * @rc_tab: the struct ir_scancode_table table of scancode/keymap @@ -389,17 +403,34 @@ u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode) * an IR. * It should be called before registering the IR device. */ -int ir_set_keycode_table(struct input_dev *input_dev, - struct ir_scancode_table *rc_tab) +int ir_input_register(struct input_dev *input_dev, + struct ir_scancode_table *rc_tab) { - struct ir_scancode *keymap = rc_tab->scan; - int i; - - spin_lock_init(&rc_tab->lock); + struct ir_input_dev *ir_dev; + struct ir_scancode *keymap = rc_tab->scan; + int i, rc; if (rc_tab->scan == NULL || !rc_tab->size) return -EINVAL; + ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL); + if (!ir_dev) + return -ENOMEM; + + spin_lock_init(&rc_tab->lock); + + ir_dev->rc_tab.size = ir_roundup_tablesize(rc_tab->size); + ir_dev->rc_tab.scan = kzalloc(ir_dev->rc_tab.size * + sizeof(struct ir_scancode), GFP_KERNEL); + if (!ir_dev->rc_tab.scan) + return -ENOMEM; + + IR_dprintk(1, "Allocated space for %d keycode entries (%zd bytes)\n", + ir_dev->rc_tab.size, + ir_dev->rc_tab.size * sizeof(ir_dev->rc_tab.scan)); + + ir_copy_table(&ir_dev->rc_tab, rc_tab); + /* set the bits for the keys */ IR_dprintk(1, "key map size: %d\n", rc_tab->size); for (i = 0; i < rc_tab->size; i++) { @@ -407,23 +438,48 @@ int ir_set_keycode_table(struct input_dev *input_dev, i, keymap[i].keycode); set_bit(keymap[i].keycode, input_dev->keybit); } + clear_bit(0, input_dev->keybit); + + set_bit(EV_KEY, input_dev->evbit); input_dev->getkeycode = ir_getkeycode; input_dev->setkeycode = ir_setkeycode; - input_set_drvdata(input_dev, rc_tab); + input_set_drvdata(input_dev, ir_dev); - return 0; + rc = input_register_device(input_dev); + if (rc < 0) { + kfree(rc_tab->scan); + kfree(ir_dev); + input_set_drvdata(input_dev, NULL); + } + + return rc; } +EXPORT_SYMBOL_GPL(ir_input_register); -void ir_input_free(struct input_dev *dev) +void ir_input_unregister(struct input_dev *dev) { - struct ir_scancode_table *rc_tab = input_get_drvdata(dev); + struct ir_input_dev *ir_dev = input_get_drvdata(dev); + struct ir_scancode_table *rc_tab; + + if (!ir_dev) + return; IR_dprintk(1, "Freed keycode table\n"); + rc_tab = &ir_dev->rc_tab; rc_tab->size = 0; kfree(rc_tab->scan); rc_tab->scan = NULL; + + kfree(ir_dev); + input_unregister_device(dev); } -EXPORT_SYMBOL_GPL(ir_input_free); +EXPORT_SYMBOL_GPL(ir_input_unregister); + +int ir_core_debug; /* ir_debug level (0,1,2) */ +EXPORT_SYMBOL_GPL(ir_core_debug); +module_param_named(debug, ir_core_debug, int, 0644); +MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ba69beeb0e21..a28541b2b1a2 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -99,6 +99,7 @@ config VIDEO_MEDIA comment "Multimedia drivers" source "drivers/media/common/Kconfig" +source "drivers/media/IR/Kconfig" # # Tuner drivers for DVB and V4L diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 09a829d8a7e7..499b0810d019 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -obj-y += common/ video/ +obj-y += common/ IR/ video/ obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb/ diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 169b337b7c9d..e3ec9639321b 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,8 +1,6 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o -ir-common-objs := ir-functions.o ir-keymaps.o ir-keytable.o obj-y += tuners/ obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o -obj-$(CONFIG_VIDEO_IR) += ir-common.o diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index 620f655fa9c5..7364b9642d00 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c @@ -1,7 +1,5 @@ #include <media/saa7146_vv.h> -#define BOARD_CAN_DO_VBI(dev) (dev->revision != 0 && dev->vv_data->vbi_minor != -1) - /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ @@ -194,43 +192,24 @@ void saa7146_buffer_timeout(unsigned long data) static int fops_open(struct file *file) { - unsigned int minor = video_devdata(file)->minor; - struct saa7146_dev *h = NULL, *dev = NULL; - struct list_head *list; + struct video_device *vdev = video_devdata(file); + struct saa7146_dev *dev = video_drvdata(file); struct saa7146_fh *fh = NULL; int result = 0; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + enum v4l2_buf_type type; - DEB_EE(("file:%p, minor:%d\n", file, minor)); + DEB_EE(("file:%p, dev:%s\n", file, video_device_node_name(vdev))); if (mutex_lock_interruptible(&saa7146_devices_lock)) return -ERESTARTSYS; - list_for_each(list,&saa7146_devices) { - h = list_entry(list, struct saa7146_dev, item); - if( NULL == h->vv_data ) { - DEB_D(("device %p has not registered video devices.\n",h)); - continue; - } - DEB_D(("trying: %p @ major %d,%d\n",h,h->vv_data->video_minor,h->vv_data->vbi_minor)); - - if (h->vv_data->video_minor == minor) { - dev = h; - } - if (h->vv_data->vbi_minor == minor) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - dev = h; - } - } - if (NULL == dev) { - DEB_S(("no such video device.\n")); - result = -ENODEV; - goto out; - } - DEB_D(("using: %p\n",dev)); + type = vdev->vfl_type == VFL_TYPE_GRABBER + ? V4L2_BUF_TYPE_VIDEO_CAPTURE + : V4L2_BUF_TYPE_VBI_CAPTURE; + /* check if an extension is registered */ if( NULL == dev->ext ) { DEB_S(("no extension registered for this device.\n")); @@ -474,9 +453,6 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) configuration data) */ dev->ext_vv_data = ext_vv; - vv->video_minor = -1; - vv->vbi_minor = -1; - vv->d_clipping.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_CLIPPING_MEM, &vv->d_clipping.dma_handle); if( NULL == vv->d_clipping.cpu_addr ) { ERR(("out of memory. aborting.\n")); @@ -515,7 +491,6 @@ EXPORT_SYMBOL_GPL(saa7146_vv_release); int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, char *name, int type) { - struct saa7146_vv *vv = dev->vv_data; struct video_device *vfd; int err; int i; @@ -543,15 +518,8 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, return err; } - if( VFL_TYPE_GRABBER == type ) { - vv->video_minor = vfd->minor; - INFO(("%s: registered device video%d [v4l2]\n", - dev->name, vfd->num)); - } else { - vv->vbi_minor = vfd->minor; - INFO(("%s: registered device vbi%d [v4l2]\n", - dev->name, vfd->num)); - } + INFO(("%s: registered device %s [v4l2]\n", + dev->name, video_device_node_name(vfd))); *vid = vfd; return 0; @@ -560,16 +528,8 @@ EXPORT_SYMBOL_GPL(saa7146_register_device); int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev) { - struct saa7146_vv *vv = dev->vv_data; - DEB_EE(("dev:%p\n",dev)); - if ((*vid)->vfl_type == VFL_TYPE_GRABBER) { - vv->video_minor = -1; - } else { - vv->vbi_minor = -1; - } - video_unregister_device(*vid); *vid = NULL; diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c index c190b0dedee4..2833137fa819 100644 --- a/drivers/media/common/tuners/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -144,7 +144,8 @@ static void set_audio(struct dvb_frontend *fe, } if (params->mode == V4L2_TUNER_RADIO) { - priv->tda8290_easy_mode = 0x01; /* Start with MN values */ + /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ + priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; tuner_dbg("setting to radio FM\n"); } else { tuner_dbg("setting tda829x to system %s\n", mode); @@ -672,16 +673,19 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props) static int tda8295_probe(struct tuner_i2c_props *i2c_props) { #define TDA8295_ID 0x8a +#define TDA8295C2_ID 0x8b unsigned char tda8295_id[] = { 0x2f, 0x00 }; /* detect tda8295 */ tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1); tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1); - if (tda8295_id[1] == TDA8295_ID) { + if ((tda8295_id[1] & 0xfe) == TDA8295_ID) { if (debug) - printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n", - __func__, i2c_adapter_id(i2c_props->adap), + printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", + __func__, (tda8295_id[1] == TDA8295_ID) ? + "tda8295c1" : "tda8295c2", + i2c_adapter_id(i2c_props->adap), i2c_props->addr); return 0; } diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 35d0817126e9..cf8f65f309da 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -72,6 +72,10 @@ comment "Supported Earthsoft PT1 Adapters" depends on DVB_CORE && PCI && I2C source "drivers/media/dvb/pt1/Kconfig" +comment "Supported Mantis Adapters" + depends on DVB_CORE && PCI && I2C + source "drivers/media/dvb/mantis/Kconfig" + comment "Supported DVB Frontends" depends on DVB_CORE source "drivers/media/dvb/frontends/Kconfig" diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 16d262ddb45d..c12922c3659b 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,6 +2,18 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/ +obj-y := dvb-core/ \ + frontends/ \ + ttpci/ \ + ttusb-dec/ \ + ttusb-budget/ \ + b2c2/ \ + bt8xx/ \ + dvb-usb/ \ + pluto2/ \ + siano/ \ + dm1105/ \ + pt1/ \ + mantis/ obj-$(CONFIG_DVB_FIREDTV) += firewire/ diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 53e3f2a7d31a..f0f483ac8b89 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -589,7 +589,7 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys), "pci-%s/ir0", pci_name(dm1105->pdev)); - err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type, ir_codes); + err = ir_input_init(input_dev, &dm1105->ir.ir, ir_type); if (err < 0) { input_free_device(input_dev); return err; @@ -611,20 +611,14 @@ int __devinit dm1105_ir_init(struct dm1105dvb *dm1105) INIT_WORK(&dm1105->ir.work, dm1105_emit_key); - err = input_register_device(input_dev); - if (err) { - ir_input_free(input_dev); - input_free_device(input_dev); - return err; - } + err = ir_input_register(input_dev, ir_codes); - return 0; + return err; } void __devexit dm1105_ir_exit(struct dm1105dvb *dm1105) { - ir_input_free(dm1105->ir.input_dev); - input_unregister_device(dm1105->ir.input_dev); + ir_input_unregister(dm1105->ir.input_dev); } static int __devinit dm1105dvb_hw_init(struct dm1105dvb *dm1105dvb) diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 2dee1bf73577..1b249897c9fb 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -265,9 +265,13 @@ config DVB_USB_DW2102 select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_MT312 if !DVB_FE_CUSTOMISE select DVB_ZL10039 if !DVB_FE_CUSTOMISE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_STB6100 if !DVB_FE_CUSTOMISE + select DVB_STV6110 if !DVB_FE_CUSTOMISE + select DVB_STV0900 if !DVB_FE_CUSTOMISE help - Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers - and the TeVii S650, S630. + Say Y here to support the DvbWorld, TeVii, Prof DVB-S/S2 USB2.0 + receivers. config DVB_USB_CINERGY_T2 tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h index 8b544fe79b0d..495a90577c5f 100644 --- a/drivers/media/dvb/dvb-usb/dib0700.h +++ b/drivers/media/dvb/dvb-usb/dib0700.h @@ -20,20 +20,22 @@ extern int dvb_usb_dib0700_debug; #define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args) #define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args) -#define REQUEST_I2C_READ 0x2 -#define REQUEST_I2C_WRITE 0x3 -#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ -#define REQUEST_JUMPRAM 0x8 -#define REQUEST_SET_CLOCK 0xB -#define REQUEST_SET_GPIO 0xC -#define REQUEST_ENABLE_VIDEO 0xF +#define REQUEST_SET_USB_XFER_LEN 0x0 /* valid only for firmware version */ + /* higher than 1.21 */ +#define REQUEST_I2C_READ 0x2 +#define REQUEST_I2C_WRITE 0x3 +#define REQUEST_POLL_RC 0x4 /* deprecated in firmware v1.20 */ +#define REQUEST_JUMPRAM 0x8 +#define REQUEST_SET_CLOCK 0xB +#define REQUEST_SET_GPIO 0xC +#define REQUEST_ENABLE_VIDEO 0xF // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog) // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1) // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " ) -#define REQUEST_SET_RC 0x11 -#define REQUEST_NEW_I2C_READ 0x12 -#define REQUEST_NEW_I2C_WRITE 0x13 -#define REQUEST_GET_VERSION 0x15 +#define REQUEST_SET_RC 0x11 +#define REQUEST_NEW_I2C_READ 0x12 +#define REQUEST_NEW_I2C_WRITE 0x13 +#define REQUEST_GET_VERSION 0x15 struct dib0700_state { u8 channel_state; @@ -44,6 +46,8 @@ struct dib0700_state { u8 is_dib7000pc; u8 fw_use_new_i2c_api; u8 disable_streaming_master_mode; + u32 fw_version; + u32 nb_packet_buffer_size; }; extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index db7f7f79a66c..0d3c9a9a33be 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -17,6 +17,14 @@ int dvb_usb_dib0700_ir_proto = 1; module_param(dvb_usb_dib0700_ir_proto, int, 0644); MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6)."); +static int nb_packet_buffer_size = 21; +module_param(nb_packet_buffer_size, int, 0644); +MODULE_PARM_DESC(nb_packet_buffer_size, + "Set the dib0700 driver data buffer size. This parameter " + "corresponds to the number of TS packets. The actual size of " + "the data buffer corresponds to this parameter " + "multiplied by 188 (default: 21)"); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -28,10 +36,14 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, sizeof(b), USB_CTRL_GET_TIMEOUT); - *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; - *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; - *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; - *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; + if (hwversion != NULL) + *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; + if (romversion != NULL) + *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7]; + if (ramversion != NULL) + *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + if (fwtype != NULL) + *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15]; return ret; } @@ -97,6 +109,27 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ return dib0700_ctrl_wr(d,buf,3); } +static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) +{ + struct dib0700_state *st = d->priv; + u8 b[3]; + int ret; + + if (st->fw_version >= 0x10201) { + b[0] = REQUEST_SET_USB_XFER_LEN; + b[1] = (nb_ts_packets >> 8)&0xff; + b[2] = nb_ts_packets & 0xff; + + deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); + + ret = dib0700_ctrl_wr(d, b, 3); + } else { + deb_info("this firmware does not allow to change the USB xfer len\n"); + ret = -EIO; + } + return ret; +} + /* * I2C master xfer function (supported in 1.20 firmware) */ @@ -328,7 +361,9 @@ static int dib0700_jumpram(struct usb_device *udev, u32 address) int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw) { struct hexline hx; - int pos = 0, ret, act_len; + int pos = 0, ret, act_len, i, adap_num; + u8 b[16]; + u32 fw_version; u8 buf[260]; @@ -364,6 +399,34 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw } else ret = -EIO; + /* the number of ts packet has to be at least 1 */ + if (nb_packet_buffer_size < 1) + nb_packet_buffer_size = 1; + + /* get the fimware version */ + usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, + b, sizeof(b), USB_CTRL_GET_TIMEOUT); + fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11]; + + /* set the buffer size - DVB-USB is allocating URB buffers + * only after the firwmare download was successful */ + for (i = 0; i < dib0700_device_count; i++) { + for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters; + adap_num++) { + if (fw_version >= 0x10201) + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size; + else { + /* for fw version older than 1.20.1, + * the buffersize has to be n times 512 */ + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512; + if (dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize < 512) + dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 512; + } + } + } + return ret; } @@ -371,6 +434,18 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { struct dib0700_state *st = adap->dev->priv; u8 b[4]; + int ret; + + if ((onoff != 0) && (st->fw_version >= 0x10201)) { + /* for firmware later than 1.20.1, + * the USB xfer length can be set */ + ret = dib0700_set_usb_xfer_len(adap->dev, + st->nb_packet_buffer_size); + if (ret < 0) { + deb_info("can not set the USB xfer len\n"); + return ret; + } + } b[0] = REQUEST_ENABLE_VIDEO; b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */ @@ -415,9 +490,21 @@ static int dib0700_probe(struct usb_interface *intf, for (i = 0; i < dib0700_device_count; i++) if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, - &dev, adapter_nr) == 0) - { + &dev, adapter_nr) == 0) { + struct dib0700_state *st = dev->priv; + u32 hwversion, romversion, fw_version, fwtype; + + dib0700_get_version(dev, &hwversion, &romversion, + &fw_version, &fwtype); + + deb_info("Firmware version: %x, %d, 0x%x, %d\n", + hwversion, romversion, fw_version, fwtype); + + st->fw_version = fw_version; + st->nb_packet_buffer_size = (u32)nb_packet_buffer_size; + dib0700_rc_setup(dev); + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index 684146f98eb7..44972d01bbd0 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -18,6 +18,7 @@ #include "xc5000.h" #include "s5h1411.h" #include "dib0070.h" +#include "dib0090.h" #include "lgdt3305.h" #include "mxl5007t.h" @@ -130,93 +131,95 @@ static int bristol_tuner_attach(struct dvb_usb_adapter *adap) /* MT226x */ static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = { { - BAND_UHF, // band_caps + BAND_UHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - - 1130, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 33770, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - - 0, // agc1_pt1 - 62, // agc1_pt2 - 255, // agc1_pt3 - 64, // agc1_slope1 - 64, // agc1_slope2 - 132, // agc2_pt1 - 192, // agc2_pt2 - 80, // agc2_slope1 - 80, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 1, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 1130, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 33770, + 65535, + 23592, + + 0, + 62, + 255, + 64, + 64, + 132, + 192, + 80, + 80, + + 17, + 27, + 23, + 51, + + 1, }, { - BAND_VHF | BAND_LBAND, // band_caps + BAND_VHF | BAND_LBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup - - 2372, // inv_gain - 21, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 0, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - 65535, // agc2_max - 23592, // agc2_min - - 0, // agc1_pt1 - 128, // agc1_pt2 - 128, // agc1_pt3 - 128, // agc1_slope1 - 0, // agc1_slope2 - 128, // agc2_pt1 - 253, // agc2_pt2 - 81, // agc2_slope1 - 0, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 1, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 2372, + 21, + + 0, + 118, + + 0, + 3530, + 1, + 0, + + 65535, + 0, + 65535, + 23592, + + 0, + 128, + 128, + 128, + 0, + 128, + 253, + 81, + 0, + + 17, + 27, + 23, + 51, + + 1, } }; static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = { - 60000, 30000, // internal, sampling - 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - 0, // ifreq - 20452225, // timf + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + 0, + 20452225, }; static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = { @@ -605,17 +608,17 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, } break; default: - if (actlen != sizeof(buf)) { - /* We didn't get back the 6 byte message we expected */ - err("Unexpected RC response size [%d]", actlen); - return -1; - } + if (actlen != sizeof(buf)) { + /* We didn't get back the 6 byte message we expected */ + err("Unexpected RC response size [%d]", actlen); + return -1; + } - poll_reply.report_id = buf[0]; - poll_reply.data_state = buf[1]; + poll_reply.report_id = buf[0]; + poll_reply.data_state = buf[1]; poll_reply.system = (buf[2] << 8) | buf[3]; - poll_reply.data = buf[4]; - poll_reply.not_data = buf[5]; + poll_reply.data = buf[4]; + poll_reply.not_data = buf[5]; break; } @@ -632,7 +635,7 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, /* Find the key in the map */ for (i = 0; i < d->props.rc_key_map_size; i++) { if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) && - rc5_data(&keymap[i]) == poll_reply.data) { + rc5_data(&keymap[i]) == poll_reply.data) { *event = keymap[i].event; found = 1; break; @@ -641,8 +644,8 @@ static int dib0700_rc_query_v1_20(struct dvb_usb_device *d, u32 *event, if (found == 0) { err("Unknown remote controller key: %04x %02x %02x", - poll_reply.system, - poll_reply.data, poll_reply.not_data); + poll_reply.system, + poll_reply.data, poll_reply.not_data); d->last_event = 0; return 0; } @@ -933,47 +936,48 @@ static struct dvb_usb_rc_key dib0700_rc_keys[] = { /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */ static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = { - BAND_UHF | BAND_VHF, // band_caps + BAND_UHF | BAND_VHF, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup - - 712, // inv_gain - 41, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 4095, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha - - 42598, // agc1_max - 17694, // agc1_min - 45875, // agc2_max - 2621, // agc2_min - 0, // agc1_pt1 - 76, // agc1_pt2 - 139, // agc1_pt3 - 52, // agc1_slope1 - 59, // agc1_slope2 - 107, // agc2_pt1 - 172, // agc2_pt2 - 57, // agc2_slope1 - 70, // agc2_slope2 - - 21, // alpha_mant - 25, // alpha_exp - 28, // beta_mant - 48, // beta_exp - - 1, // perform_agc_softsplit - { 0, // split_min - 107, // split_max - 51800, // global_split_min - 24700 // global_split_max + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), + + 712, + 41, + + 0, + 118, + + 0, + 4095, + 0, + 0, + + 42598, + 17694, + 45875, + 2621, + 0, + 76, + 139, + 52, + 59, + 107, + 172, + 57, + 70, + + 21, + 25, + 28, + 48, + + 1, + { 0, + 107, + 51800, + 24700 }, }; @@ -982,54 +986,55 @@ static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = { /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), - 712, // inv_gain - 41, // time_stabiliz + 712, + 41, - 0, // alpha_level - 118, // thlock + 0, + 118, - 0, // wbd_inv - 4095, // wbd_ref - 0, // wbd_sel - 0, // wbd_alpha + 0, + 4095, + 0, + 0, - 42598, // agc1_max - 16384, // agc1_min - 42598, // agc2_max - 0, // agc2_min + 42598, + 16384, + 42598, + 0, - 0, // agc1_pt1 - 137, // agc1_pt2 - 255, // agc1_pt3 + 0, + 137, + 255, - 0, // agc1_slope1 - 255, // agc1_slope2 + 0, + 255, - 0, // agc2_pt1 - 0, // agc2_pt2 + 0, + 0, - 0, // agc2_slope1 - 41, // agc2_slope2 + 0, + 41, - 15, // alpha_mant - 25, // alpha_exp + 15, + 25, - 28, // beta_mant - 48, // beta_exp + 28, + 48, - 0, // perform_agc_softsplit + 0, }; static struct dibx000_bandwidth_config stk7700p_pll_config = { - 60000, 30000, // internal, sampling - 1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - 60258167, // ifreq - 20452225, // timf - 30000000, // xtal + 60000, 30000, + 1, 8, 3, 1, 0, + 0, 0, 1, 1, 0, + (3 << 14) | (1 << 12) | (524 << 0), + 60258167, + 20452225, + 30000000, }; static struct dib7000m_config stk7700p_dib7000m_config = { @@ -1115,41 +1120,42 @@ static struct dibx000_agc_config dib7070_agc_config = { BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup - - 600, // inv_gain - 10, // time_stabiliz - - 0, // alpha_level - 118, // thlock - - 0, // wbd_inv - 3530, // wbd_ref - 1, // wbd_sel - 5, // wbd_alpha - - 65535, // agc1_max - 0, // agc1_min - - 65535, // agc2_max - 0, // agc2_min - - 0, // agc1_pt1 - 40, // agc1_pt2 - 183, // agc1_pt3 - 206, // agc1_slope1 - 255, // agc1_slope2 - 72, // agc2_pt1 - 152, // agc2_pt2 - 88, // agc2_slope1 - 90, // agc2_slope2 - - 17, // alpha_mant - 27, // alpha_exp - 23, // beta_mant - 51, // beta_exp - - 0, // perform_agc_softsplit + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 600, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 40, + 183, + 206, + 255, + 72, + 152, + 88, + 90, + + 17, + 27, + 23, + 51, + + 0, }; static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -1276,13 +1282,13 @@ static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { - 60000, 15000, // internal, sampling - 1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass - 0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo - (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k - (0 << 25) | 0, // ifreq = 0.000000 MHz - 20452225, // timf - 12000000, // xtal_hz + 60000, 15000, + 1, 20, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (524 << 0), + (0 << 25) | 0, + 20452225, + 12000000, }; static struct dib7000p_config dib7070p_dib7000p_config = { @@ -1476,12 +1482,12 @@ static struct dib8000_config dib807x_dib8000_config[2] = { } }; -static int dib807x_tuner_reset(struct dvb_frontend *fe, int onoff) +static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) { return dib8000_set_gpio(fe, 5, 0, !onoff); } -static int dib807x_tuner_sleep(struct dvb_frontend *fe, int onoff) +static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) { return dib8000_set_gpio(fe, 0, 0, onoff); } @@ -1494,8 +1500,8 @@ static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { static struct dib0070_config dib807x_dib0070_config[2] = { { .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib807x_tuner_reset, - .sleep = dib807x_tuner_sleep, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, .clock_khz = 12000, .clock_pad_drive = 4, .vga_filter = 1, @@ -1508,8 +1514,8 @@ static struct dib0070_config dib807x_dib0070_config[2] = { .freq_offset_khz_vhf = -100, }, { .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, - .reset = dib807x_tuner_reset, - .sleep = dib807x_tuner_sleep, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, .clock_khz = 12000, .clock_pad_drive = 2, .vga_filter = 1, @@ -1566,12 +1572,14 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int stk807x_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) +static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, + u16 pid, int onoff) { return dib8000_pid_filter(adapter->fe, index, pid, onoff); } -static int stk807x_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) +static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, + int onoff) { return dib8000_pid_filter_ctrl(adapter->fe, onoff); } @@ -1624,7 +1632,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x80); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); @@ -1635,7 +1643,7 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) { /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x82); + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); @@ -1643,6 +1651,245 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) return adap->fe == NULL ? -ENODEV : 0; } +/* STK8096GP */ +struct dibx000_agc_config dib8090_agc_config[2] = { + { + BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 65535, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + }, + { + BAND_CBAND, + /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ + (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + + 787, + 10, + + 0, + 118, + + 0, + 3530, + 1, + 5, + + 0, + 0, + + 65535, + 0, + + 0, + 32, + 114, + 143, + 144, + 114, + 227, + 116, + 117, + + 28, + 26, + 31, + 51, + + 0, + } +}; + +static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { + 54000, 13500, + 1, 18, 3, 1, 0, + 0, 0, 1, 1, 2, + (3 << 14) | (1 << 12) | (599 << 0), + (0 << 25) | 0, + 20199727, + 12000000, +}; + +static int dib8090_get_adc_power(struct dvb_frontend *fe) +{ + return dib8000_get_adc_power(fe, 1); +} + +static struct dib8000_config dib809x_dib8000_config = { + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 2, + .agc = dib8090_agc_config, + .agc_control = dib0090_dcc_freq, + .pll = &dib8090_pll_config_12mhz, + .tuner_is_baseband = 1, + + .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS, + .gpio_val = DIB8000_GPIO_DEFAULT_VALUES, + .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, + .div_cfg = 0x31, + .output_mode = OUTMODE_MPEG2_FIFO, + .drives = 0x2d98, + .diversity_delay = 144, + .refclksel = 3, +}; + +static struct dib0090_config dib809x_dib0090_config = { + .io.pll_bypass = 1, + .io.pll_range = 1, + .io.pll_prediv = 1, + .io.pll_loopdiv = 20, + .io.adc_clock_ratio = 8, + .io.pll_int_loop_filt = 0, + .io.clock_khz = 12000, + .reset = dib80xx_tuner_reset, + .sleep = dib80xx_tuner_sleep, + .clkouttobamse = 1, + .analog_output = 1, + .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS, + .wbd_vhf_offset = 100, + .wbd_cband_offset = 450, + .use_pwm_agc = 1, + .clkoutdrive = 1, + .get_adc_power = dib8090_get_adc_power, + .freq_offset_khz_uhf = 0, + .freq_offset_khz_vhf = -143, +}; + +static int dib8096_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + u16 offset; + int ret = 0; + enum frontend_tune_state tune_state = CT_SHUTDOWN; + u16 ltgain, rf_gain_limit; + + ret = state->set_param_save(fe, fep); + if (ret < 0) + return ret; + + switch (band) { + case BAND_VHF: + offset = 100; + break; + case BAND_UHF: + offset = 550; + break; + default: + offset = 0; + break; + } + offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, offset); + + + if (band == BAND_CBAND) { + deb_info("tuning in CBAND - soft-AGC startup\n"); + /* TODO specific wbd target for dib0090 - needed for startup ? */ + dib0090_set_tune_state(fe, CT_AGC_START); + do { + ret = dib0090_gain_control(fe); + msleep(ret); + tune_state = dib0090_get_tune_state(fe); + if (tune_state == CT_AGC_STEP_0) + dib8000_set_gpio(fe, 6, 0, 1); + else if (tune_state == CT_AGC_STEP_1) { + dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); + if (rf_gain_limit == 0) + dib8000_set_gpio(fe, 6, 0, 0); + } + } while (tune_state < CT_AGC_STOP); + dib0090_pwm_gain_reset(fe); + dib8000_pwm_agc_reset(fe); + dib8000_set_tune_state(fe, CT_DEMOD_START); + } else { + deb_info("not tuning in CBAND - standard AGC startup\n"); + dib0090_pwm_gain_reset(fe); + } + + return 0; +} + +static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + return 0; +} + +static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) +{ + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); + + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); + + dib0700_ctrl_clock(adap->dev, 72, 1); + + msleep(10); + dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); + msleep(10); + dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); + + dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); + + adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config); + + return adap->fe == NULL ? -ENODEV : 0; +} /* STK7070PD */ static struct dib7000p_config stk7070pd_dib7000p_config[2] = { @@ -1929,14 +2176,17 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, /* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, /* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) }, { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, +/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, + { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -2238,11 +2488,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Pinnacle PCTV 73e SE", - { &dib0700_usb_id_table[57], NULL }, + { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, { NULL }, }, { "Pinnacle PCTV 282e", - { &dib0700_usb_id_table[58], NULL }, + { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, { NULL }, }, }, @@ -2471,8 +2721,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807x_frontend_attach, .tuner_attach = dib807x_tuner_attach, @@ -2510,8 +2760,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach0, .tuner_attach = dib807x_tuner_attach, @@ -2523,8 +2773,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { { .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, .pid_filter_count = 32, - .pid_filter = stk807x_pid_filter, - .pid_filter_ctrl = stk807x_pid_filter_ctrl, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, .frontend_attach = stk807xpvr_frontend_attach1, .tuner_attach = dib807x_tuner_attach, @@ -2547,6 +2797,37 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_key_map = dib0700_rc_keys, .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), .rc_query = dib0700_rc_query + }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, + .num_adapters = 1, + .adapter = { + { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + .pid_filter_count = 32, + .pid_filter = stk80xx_pid_filter, + .pid_filter_ctrl = stk80xx_pid_filter_ctrl, + .frontend_attach = stk809x_frontend_attach, + .tuner_attach = dib809x_tuner_attach, + + DIB0700_DEFAULT_STREAMING_CONFIG(0x02), + + .size_of_priv = + sizeof(struct dib0700_adapter_state), + }, + }, + + .num_device_descs = 1, + .devices = { + { "DiBcom STK8096GP reference design", + { &dib0700_usb_id_table[67], NULL }, + { NULL }, + }, + }, + + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_key_map = dib0700_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys), + .rc_query = dib0700_rc_query }, }; diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index da34979b5337..9143b5631e88 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -142,8 +142,13 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num } else if ((msg[i].flags & I2C_M_RD) == 0) { if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0) break; - } else - break; + } else if (msg[i].addr != 0x50) { + /* 0x50 is the address of the eeprom - we need to protect it + * from dibusb's bad i2c implementation: reads without + * writing the offset before are forbidden */ + if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0) + break; + } } mutex_unlock(&d->i2c_mutex); @@ -243,6 +248,12 @@ static struct dib3000mc_config mod3000p_dib3000p_config = { int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) { + if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON && + adap->dev->udev->descriptor.idProduct == + USB_PID_LITEON_DVB_T_WARM) { + msleep(1000); + } + if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { if (adap->priv != NULL) { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index f1602d4ace6d..bc3581d58ced 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -47,6 +47,7 @@ #define USB_VID_MSI_2 0x1462 #define USB_VID_OPERA1 0x695c #define USB_VID_PINNACLE 0x2304 +#define USB_VID_PCTV 0x2013 #define USB_VID_PIXELVIEW 0x1554 #define USB_VID_TECHNOTREND 0x0b48 #define USB_VID_TERRATEC 0x0ccd @@ -101,6 +102,7 @@ #define USB_PID_DIBCOM_STK7070PD 0x1ebe #define USB_PID_DIBCOM_STK807XP 0x1f90 #define USB_PID_DIBCOM_STK807XPVR 0x1f98 +#define USB_PID_DIBCOM_STK8096GP 0x1fa0 #define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131 #define USB_PID_DIBCOM_STK7770P 0x1e80 #define USB_PID_DPOSH_M9206_COLD 0x9206 @@ -211,6 +213,7 @@ #define USB_PID_PINNACLE_PCTV801E_SE 0x023b #define USB_PID_PINNACLE_PCTV73A 0x0243 #define USB_PID_PINNACLE_PCTV73ESE 0x0245 +#define USB_PID_PINNACLE_PCTV74E 0x0246 #define USB_PID_PINNACLE_PCTV282E 0x0248 #define USB_PID_PIXELVIEW_SBTVD 0x5010 #define USB_PID_PCTV_200E 0x020e diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 5bb9479d154e..64132c0cf80d 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -20,6 +20,11 @@ #include "tda1002x.h" #include "mt312.h" #include "zl10039.h" +#include "ds3000.h" +#include "stv0900.h" +#include "stv6110.h" +#include "stb6100.h" +#include "stb6100_proc.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 @@ -37,12 +42,20 @@ #define USB_PID_CINERGY_S 0x0064 #endif +#ifndef USB_PID_TEVII_S630 +#define USB_PID_TEVII_S630 0xd630 +#endif + #ifndef USB_PID_TEVII_S650 #define USB_PID_TEVII_S650 0xd650 #endif -#ifndef USB_PID_TEVII_S630 -#define USB_PID_TEVII_S630 0xd630 +#ifndef USB_PID_TEVII_S660 +#define USB_PID_TEVII_S660 0xd660 +#endif + +#ifndef USB_PID_PROF_1100 +#define USB_PID_PROF_1100 0xb012 #endif #define DW210X_READ_MSG 0 @@ -55,6 +68,10 @@ #define DW2102_VOLTAGE_CTRL (0x1800) #define DW2102_RC_QUERY (0x1a00) +#define err_str "did not find the firmware file. (%s) " \ + "Please see linux/Documentation/dvb/ for more details " \ + "on firmware-problems." + struct dvb_usb_rc_keys_table { struct dvb_usb_rc_key *rc_keys; int rc_keys_size; @@ -71,6 +88,12 @@ static int ir_keymap; module_param_named(keymap, ir_keymap, int, 0644); MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs ..."); +/* demod probe */ +static int demod_probe = 1; +module_param_named(demod, demod_probe, int, 0644); +MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " + "4=stv0903+stb6100(or-able))."); + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value, @@ -183,7 +206,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, switch (num) { case 2: /* read si2109 register by number */ - buf6[0] = 0xd0; + buf6[0] = msg[0].addr << 1; buf6[1] = msg[0].len; buf6[2] = msg[0].buf[0]; ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, @@ -198,7 +221,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap, switch (msg[0].addr) { case 0x68: /* write to si2109 register */ - buf6[0] = 0xd0; + buf6[0] = msg[0].addr << 1; buf6[1] = msg[0].len; memcpy(buf6 + 2, msg[0].buf, msg[0].len); ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6, @@ -239,7 +262,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms /* read */ /* first write first register number */ u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = 0xd0; + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; obuf[2] = msg[0].buf[0]; ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, @@ -256,7 +279,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 0x68: { /* write to register */ u8 obuf[msg[0].len + 2]; - obuf[0] = 0xd0; + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, @@ -266,7 +289,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms case 0x61: { /* write to tuner */ u8 obuf[msg[0].len + 2]; - obuf[0] = 0xc2; + obuf[0] = msg[0].addr << 1; obuf[1] = msg[0].len; memcpy(obuf + 2, msg[0].buf, msg[0].len); ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, @@ -301,78 +324,78 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i { struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret = 0; - int len, i; + int len, i, j; if (!d) return -ENODEV; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - switch (num) { - case 2: { - /* read */ - /* first write first register number */ - u8 ibuf[msg[1].len + 2], obuf[3]; - obuf[0] = 0xaa; - obuf[1] = msg[0].len; - obuf[2] = msg[0].buf[0]; - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - /* second read registers */ - ret = dw210x_op_rw(d->udev, 0xc3, 0xab , 0, - ibuf, msg[1].len + 2, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf + 2, msg[1].len); - - break; - } - case 1: - switch (msg[0].addr) { - case 0x55: { - if (msg[0].buf[0] == 0xf7) { - /* firmware */ - /* Write in small blocks */ - u8 obuf[19]; - obuf[0] = 0xaa; - obuf[1] = 0x11; - obuf[2] = 0xf7; - len = msg[0].len - 1; - i = 1; - do { - memcpy(obuf + 3, msg[0].buf + i, (len > 16 ? 16 : len)); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, (len > 16 ? 16 : len) + 3, DW210X_WRITE_MSG); - i += 16; - len -= 16; - } while (len > 0); - } else { - /* write to register */ - u8 obuf[msg[0].len + 2]; - obuf[0] = 0xaa; - obuf[1] = msg[0].len; - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - } - break; - } + for (j = 0; j < num; j++) { + switch (msg[j].addr) { case(DW2102_RC_QUERY): { u8 ibuf[2]; ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 2, DW210X_READ_MSG); - memcpy(msg[0].buf, ibuf , 2); + memcpy(msg[j].buf, ibuf , 2); break; } case(DW2102_VOLTAGE_CTRL): { u8 obuf[2]; obuf[0] = 0x30; - obuf[1] = msg[0].buf[0]; + obuf[1] = msg[j].buf[0]; ret = dw210x_op_rw(d->udev, 0xb2, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len + 2]; + ret = dw210x_op_rw(d->udev, 0xc3, + (msg[j].addr << 1) + 1, 0, + ibuf, msg[j].len + 2, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf + 2, msg[j].len); + mdelay(10); + } else if (((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) || + ((msg[j].buf[0] == 0xf7) && + (msg[j].addr == 0x55))) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = msg[j].addr << 1; + obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len); + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].addr << 1; + obuf[1] = msg[j].len; + memcpy(obuf + 2, msg[j].buf, msg[j].len); + ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + } + break; + } } - break; } mutex_unlock(&d->i2c_mutex); @@ -442,63 +465,85 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], return num; } -static int s630_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], +static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); int ret = 0; + int len, i, j; if (!d) return -ENODEV; if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; - switch (num) { - case 2: { /* read */ - u8 ibuf[msg[1].len], obuf[3]; - obuf[0] = msg[1].len; - obuf[1] = (msg[0].addr << 1); - obuf[2] = msg[0].buf[0]; - - ret = dw210x_op_rw(d->udev, 0x90, 0, 0, - obuf, 3, DW210X_WRITE_MSG); - msleep(5); - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, - ibuf, msg[1].len, DW210X_READ_MSG); - memcpy(msg[1].buf, ibuf, msg[1].len); - break; - } - case 1: - switch (msg[0].addr) { - case 0x60: - case 0x0e: { - /* write to zl10313, zl10039 register, */ - u8 obuf[msg[0].len + 2]; - obuf[0] = msg[0].len + 1; - obuf[1] = (msg[0].addr << 1); - memcpy(obuf + 2, msg[0].buf, msg[0].len); - ret = dw210x_op_rw(d->udev, 0x80, 0, 0, - obuf, msg[0].len + 2, DW210X_WRITE_MSG); - break; - } + for (j = 0; j < num; j++) { + switch (msg[j].addr) { case (DW2102_RC_QUERY): { u8 ibuf[4]; ret = dw210x_op_rw(d->udev, 0xb8, 0, 0, ibuf, 4, DW210X_READ_MSG); - msg[0].buf[0] = ibuf[3]; + memcpy(msg[j].buf, ibuf + 1, 2); break; } case (DW2102_VOLTAGE_CTRL): { u8 obuf[2]; - obuf[0] = 0x03; - obuf[1] = msg[0].buf[0]; + obuf[0] = 3; + obuf[1] = msg[j].buf[0]; ret = dw210x_op_rw(d->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); break; } + /*case 0x55: cx24116 + case 0x6a: stv0903 + case 0x68: ds3000, stv0903 + case 0x60: ts2020, stv6110, stb6100 + case 0xa0: eeprom */ + default: { + if (msg[j].flags == I2C_M_RD) { + /* read registers */ + u8 ibuf[msg[j].len]; + ret = dw210x_op_rw(d->udev, 0x91, 0, 0, + ibuf, msg[j].len, + DW210X_READ_MSG); + memcpy(msg[j].buf, ibuf, msg[j].len); + break; + } else if ((msg[j].buf[0] == 0xb0) && + (msg[j].addr == 0x68)) { + /* write firmware */ + u8 obuf[19]; + obuf[0] = (msg[j].len > 16 ? + 18 : msg[j].len + 1); + obuf[1] = msg[j].addr << 1; + obuf[2] = msg[j].buf[0]; + len = msg[j].len - 1; + i = 1; + do { + memcpy(obuf + 3, msg[j].buf + i, + (len > 16 ? 16 : len)); + ret = dw210x_op_rw(d->udev, 0x80, 0, 0, + obuf, (len > 16 ? 16 : len) + 3, + DW210X_WRITE_MSG); + i += 16; + len -= 16; + } while (len > 0); + } else { + /* write registers */ + u8 obuf[msg[j].len + 2]; + obuf[0] = msg[j].len + 1; + obuf[1] = (msg[j].addr << 1); + memcpy(obuf + 2, msg[j].buf, msg[j].len); + ret = dw210x_op_rw(d->udev, + (num > 1 ? 0x90 : 0x80), 0, 0, + obuf, msg[j].len + 2, + DW210X_WRITE_MSG); + break; + } + break; + } } - break; + msleep(3); } mutex_unlock(&d->i2c_mutex); @@ -535,8 +580,8 @@ static struct i2c_algorithm dw3101_i2c_algo = { .functionality = dw210x_i2c_func, }; -static struct i2c_algorithm s630_i2c_algo = { - .master_xfer = s630_i2c_transfer, +static struct i2c_algorithm s6x0_i2c_algo = { + .master_xfer = s6x0_i2c_transfer, .functionality = dw210x_i2c_func, }; @@ -564,25 +609,34 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) return 0; }; -static int s630_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) +static int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6]) { int i, ret; - u8 buf[3], eeprom[256], eepromline[16]; + u8 ibuf[] = { 0 }, obuf[] = { 0 }; + u8 eeprom[256], eepromline[16]; + struct i2c_msg msg[] = { + { + .addr = 0xa0 >> 1, + .flags = 0, + .buf = obuf, + .len = 1, + }, { + .addr = 0xa0 >> 1, + .flags = I2C_M_RD, + .buf = ibuf, + .len = 1, + } + }; for (i = 0; i < 256; i++) { - buf[0] = 1; - buf[1] = 0xa0; - buf[2] = i; - ret = dw210x_op_rw(d->udev, 0x90, 0, 0, - buf, 3, DW210X_WRITE_MSG); - ret = dw210x_op_rw(d->udev, 0x91, 0, 0, - buf, 1, DW210X_READ_MSG); - if (ret < 0) { + obuf[0] = i; + ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2); + if (ret != 2) { err("read eeprom failed."); return -1; } else { - eepromline[i % 16] = buf[0]; - eeprom[i] = buf[0]; + eepromline[i % 16] = ibuf[0]; + eeprom[i] = ibuf[0]; } if ((i % 16) == 15) { @@ -644,19 +698,104 @@ static struct mt312_config zl313_config = { .demod_address = 0x0e, }; +static struct ds3000_config dw2104_ds3000_config = { + .demod_address = 0x68, +}; + +static struct stv0900_config dw2104a_stv0900_config = { + .demod_address = 0x6a, + .demod_mode = 0, + .xtal = 27000000, + .clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */ + .diseqc_mode = 2,/* 2/3 PWM */ + .tun1_maddress = 0,/* 0x60 */ + .tun1_adc = 0,/* 2 Vpp */ + .path1_mode = 3, +}; + +static struct stb6100_config dw2104a_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static struct stv0900_config dw2104_stv0900_config = { + .demod_address = 0x68, + .demod_mode = 0, + .xtal = 8000000, + .clkmode = 3, + .diseqc_mode = 2, + .tun1_maddress = 0, + .tun1_adc = 1,/* 1 Vpp */ + .path1_mode = 3, +}; + +static struct stv6110_config dw2104_stv6110_config = { + .i2c_address = 0x60, + .mclk = 16000000, + .clk_div = 1, +}; + static int dw2104_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config, - &d->dev->i2c_adap)) != NULL) { + struct dvb_tuner_ops *tuner_ops = NULL; + + if (demod_probe & 4) { + d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stb6100_attach, d->fe, + &dw2104a_stb6100_config, + &d->dev->i2c_adap)) { + tuner_ops = &d->fe->ops.tuner_ops; + tuner_ops->set_frequency = stb6100_set_freq; + tuner_ops->get_frequency = stb6100_get_freq; + tuner_ops->set_bandwidth = stb6100_set_bandw; + tuner_ops->get_bandwidth = stb6100_get_bandw; + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STB6100!\n"); + return 0; + } + } + } + + if (demod_probe & 2) { + d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + &d->dev->i2c_adap, 0); + if (d->fe != NULL) { + if (dvb_attach(stv6110_attach, d->fe, + &dw2104_stv6110_config, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached STV0900+STV6110A!\n"); + return 0; + } + } + } + + if (demod_probe & 1) { + d->fe = dvb_attach(cx24116_attach, &dw2104_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached cx24116!\n"); + return 0; + } + } + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached cx24116!\n"); + info("Attached DS3000!\n"); return 0; } + return -EIO; } static struct dvb_usb_device_properties dw2102_properties; static struct dvb_usb_device_properties dw2104_properties; +static struct dvb_usb_device_properties s6x0_properties; static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { @@ -670,14 +809,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) return 0; } } + if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ d->fe = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached stv0288!\n"); - return 0; + if (dvb_attach(stb6000_attach, d->fe, 0x61, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288!\n"); + return 0; + } } } @@ -705,15 +847,38 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) return -EIO; } -static int s630_frontend_attach(struct dvb_usb_adapter *d) +static int s6x0_frontend_attach(struct dvb_usb_adapter *d) { d->fe = dvb_attach(mt312_attach, &zl313_config, - &d->dev->i2c_adap); + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(zl10039_attach, d->fe, 0x60, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached zl100313+zl10039!\n"); + return 0; + } + } + + d->fe = dvb_attach(stv0288_attach, &earda_config, + &d->dev->i2c_adap); + if (d->fe != NULL) { + if (dvb_attach(stb6000_attach, d->fe, 0x61, + &d->dev->i2c_adap)) { + d->fe->ops.set_voltage = dw210x_set_voltage; + info("Attached stv0288+stb6000!\n"); + return 0; + } + } + + d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + &d->dev->i2c_adap); if (d->fe != NULL) { d->fe->ops.set_voltage = dw210x_set_voltage; - info("Attached zl10313!\n"); + info("Attached ds3000+ds2020!\n"); return 0; } + return -EIO; } @@ -724,14 +889,6 @@ static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(stb6000_attach, adap->fe, 0x61, - &adap->dev->i2c_adap); - - return 0; -} - static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach(dvb_pll_attach, adap->fe, 0x60, @@ -740,14 +897,6 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) return 0; } -static int s630_zl10039_tuner_attach(struct dvb_usb_adapter *adap) -{ - dvb_attach(zl10039_attach, adap->fe, 0x60, - &adap->dev->i2c_adap); - - return 0; -} - static struct dvb_usb_rc_key dw210x_rc_keys[] = { { 0xf80a, KEY_Q }, /*power*/ { 0xf80c, KEY_M }, /*mute*/ @@ -922,6 +1071,8 @@ static struct usb_device_id dw2102_table[] = { {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)}, {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, + {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, + {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, { } }; @@ -935,15 +1086,13 @@ static int dw2102_load_firmware(struct usb_device *dev, u8 reset; u8 reset16[] = {0, 0, 0, 0, 0, 0, 0}; const struct firmware *fw; - const char *filename = "dvb-usb-dw2101.fw"; + const char *fw_2101 = "dvb-usb-dw2101.fw"; switch (dev->descriptor.idProduct) { case 0x2101: - ret = request_firmware(&fw, filename, &dev->dev); + ret = request_firmware(&fw, fw_2101, &dev->dev); if (ret != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details " - "on firmware-problems.", filename); + err(err_str, fw_2101); return ret; } break; @@ -983,6 +1132,11 @@ static int dw2102_load_firmware(struct usb_device *dev, } /* init registers */ switch (dev->descriptor.idProduct) { + case USB_PID_PROF_1100: + s6x0_properties.rc_key_map = tbs_rc_keys; + s6x0_properties.rc_key_map_size = + ARRAY_SIZE(tbs_rc_keys); + break; case USB_PID_TEVII_S650: dw2104_properties.rc_key_map = tevii_rc_keys; dw2104_properties.rc_key_map_size = @@ -1021,7 +1175,6 @@ static int dw2102_load_firmware(struct usb_device *dev, DW210X_READ_MSG); if (reset16[2] == 0x11) { dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo; - dw2102_properties.adapter->tuner_attach = &dw2102_earda_tuner_attach; break; } } @@ -1184,13 +1337,13 @@ static struct dvb_usb_device_properties dw3101_properties = { } }; -static struct dvb_usb_device_properties s630_properties = { +static struct dvb_usb_device_properties s6x0_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-s630.fw", .no_reconnect = 1, - .i2c_algo = &s630_i2c_algo, + .i2c_algo = &s6x0_i2c_algo, .rc_key_map = tevii_rc_keys, .rc_key_map_size = ARRAY_SIZE(tevii_rc_keys), .rc_interval = 150, @@ -1199,12 +1352,12 @@ static struct dvb_usb_device_properties s630_properties = { .generic_bulk_ctrl_endpoint = 0x81, .num_adapters = 1, .download_firmware = dw2102_load_firmware, - .read_mac_address = s630_read_mac_address, + .read_mac_address = s6x0_read_mac_address, .adapter = { { - .frontend_attach = s630_frontend_attach, + .frontend_attach = s6x0_frontend_attach, .streaming_ctrl = NULL, - .tuner_attach = s630_zl10039_tuner_attach, + .tuner_attach = NULL, .stream = { .type = USB_BULK, .count = 8, @@ -1217,12 +1370,20 @@ static struct dvb_usb_device_properties s630_properties = { }, } }, - .num_device_descs = 1, + .num_device_descs = 3, .devices = { {"TeVii S630 USB", {&dw2102_table[6], NULL}, {NULL}, }, + {"Prof 1100 USB ", + {&dw2102_table[7], NULL}, + {NULL}, + }, + {"TeVii S660 USB", + {&dw2102_table[8], NULL}, + {NULL}, + }, } }; @@ -1235,10 +1396,10 @@ static int dw2102_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &dw3101_properties, THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &s630_properties, - THIS_MODULE, NULL, adapter_nr)) { + 0 == dvb_usb_device_init(intf, &s6x0_properties, + THIS_MODULE, NULL, adapter_nr)) return 0; - } + return -ENODEV; } @@ -1269,6 +1430,7 @@ module_exit(dw2102_module_exit); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," " DVB-C 3101 USB2.0," - " TeVii S600, S630, S650 USB2.0 devices"); + " TeVii S600, S630, S650, S660 USB2.0," + " Prof 1100 USB2.0 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c index 9cbbe42ca44b..ebb7b9fd115b 100644 --- a/drivers/media/dvb/dvb-usb/friio-fe.c +++ b/drivers/media/dvb/dvb-usb/friio-fe.c @@ -134,11 +134,13 @@ static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq) deb_fe("%s: freq=%d, step=%d\n", __func__, freq, state->frontend.ops.info.frequency_stepsize); /* freq -> oscilator frequency conversion. */ - /* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */ - /* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */ - /* 1/7MHz for center freq shift */ + /* freq: 473,000,000 + n*6,000,000 [+ 142857 (center freq. shift)] */ f = freq / state->frontend.ops.info.frequency_stepsize; - f += 400; + /* add 399[1/7 MHZ] = 57MHz for the IF */ + f += 399; + /* add center frequency shift if necessary */ + if (f % 7 == 0) + f++; pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */ pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1; pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F; diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c index 20eadf9318e0..7a7f1b2b681c 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -146,8 +146,8 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, switch (c->delivery_system) { case SYS_DVBS: - /* Only QPSK is supported for DVB-S */ - if (c->modulation != QPSK) { + /* Allow QPSK and 8PSK (even for DVB-S) */ + if (c->modulation != QPSK && c->modulation != PSK_8) { deb_fe("%s: unsupported modulation selected (%d)\n", __func__, c->modulation); return -EOPNOTSUPP; diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c index fe44789ab037..6223bf01efe9 100644 --- a/drivers/media/dvb/firewire/firedtv-fw.c +++ b/drivers/media/dvb/firewire/firedtv-fw.c @@ -202,14 +202,8 @@ static void handle_fcp(struct fw_card *card, struct fw_request *request, unsigned long flags; int su; - if ((tcode != TCODE_WRITE_QUADLET_REQUEST && - tcode != TCODE_WRITE_BLOCK_REQUEST) || - offset != CSR_REGISTER_BASE + CSR_FCP_RESPONSE || - length == 0 || - (((u8 *)payload)[0] & 0xf0) != 0) { - fw_send_response(card, request, RCODE_TYPE_ERROR); + if (length < 2 || (((u8 *)payload)[0] & 0xf0) != 0) return; - } su = ((u8 *)payload)[1] & 0x7; @@ -230,10 +224,8 @@ static void handle_fcp(struct fw_card *card, struct fw_request *request, } spin_unlock_irqrestore(&node_list_lock, flags); - if (fdtv) { + if (fdtv) avc_recv(fdtv, payload, length); - fw_send_response(card, request, RCODE_COMPLETE); - } } static struct fw_address_handler fcp_handler = { diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 58aac018f109..cd7f9b7cbffa 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -208,6 +208,14 @@ config DVB_DS3000 help A DVB-S/S2 tuner module. Say Y when you want to support this frontend. +config DVB_MB86A16 + tristate "Fujitsu MB86A16 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S/DSS Direct Conversion reveiver. + Say Y when you want to support this frontend. + comment "DVB-T (terrestrial) frontends" depends on DVB_CORE @@ -526,6 +534,15 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called together with a demodulator for now. +config DVB_TUNER_DIB0090 + tristate "DiBcom DiB0090 silicon base-band tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner DiB0090 from DiBcom. + This device is only used inside a SiP called together with a + demodulator for now. + comment "SEC control devices for DVB-S" depends on DVB_CORE @@ -578,6 +595,17 @@ config DVB_ATBM8830 help A DMB-TH tuner module. Say Y when you want to support this frontend. +config DVB_TDA665x + tristate "TDA665x tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + Support for tuner modules based on Philips TDA6650/TDA6651 chips. + Say Y when you want to support this chip. + + Currently supported tuners: + * Panasonic ENV57H12D5 (ET-50DT) + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 823482535d11..874e8ada4d1d 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o obj-$(CONFIG_DVB_TDA8261) += tda8261.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o +obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o @@ -63,6 +64,7 @@ obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o +obj-$(CONFIG_DVB_TDA665x) += tda665x.o obj-$(CONFIG_DVB_LGS8GXX) += lgs8gxx.o obj-$(CONFIG_DVB_ATBM8830) += atbm8830.o obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o @@ -79,3 +81,4 @@ obj-$(CONFIG_DVB_STV6110x) += stv6110x.o obj-$(CONFIG_DVB_ISL6423) += isl6423.o obj-$(CONFIG_DVB_EC100) += ec100.o obj-$(CONFIG_DVB_DS3000) += ds3000.o +obj-$(CONFIG_DVB_MB86A16) += mb86a16.o diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c index 2dc2723b724a..24268ef2753d 100644 --- a/drivers/media/dvb/frontends/au8522_decoder.c +++ b/drivers/media/dvb/frontends/au8522_decoder.c @@ -62,7 +62,7 @@ struct au8522_register_config { The values are as follows from left to right 0="ATV RF" 1="ATV RF13" 2="CVBS" 3="S-Video" 4="PAL" 5=CVBS13" 6="SVideo13" */ -struct au8522_register_config filter_coef[] = { +static const struct au8522_register_config filter_coef[] = { {AU8522_FILTER_COEF_R410, {0x25, 0x00, 0x25, 0x25, 0x00, 0x00, 0x00} }, {AU8522_FILTER_COEF_R411, {0x20, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00} }, {AU8522_FILTER_COEF_R412, {0x03, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00} }, @@ -104,7 +104,7 @@ struct au8522_register_config filter_coef[] = { 0="SIF" 1="ATVRF/ATVRF13" Note: the "ATVRF/ATVRF13" mode has never been tested */ -struct au8522_register_config lpfilter_coef[] = { +static const struct au8522_register_config lpfilter_coef[] = { {0x060b, {0x21, 0x0b} }, {0x060c, {0xad, 0xad} }, {0x060d, {0x70, 0xf0} }, diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 2be17b93e0bd..0d12763603b4 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -49,21 +49,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define DIB0070_P1G 0x03 #define DIB0070S_P1A 0x02 -enum frontend_tune_state { - CT_TUNER_START = 10, - CT_TUNER_STEP_0, - CT_TUNER_STEP_1, - CT_TUNER_STEP_2, - CT_TUNER_STEP_3, - CT_TUNER_STEP_4, - CT_TUNER_STEP_5, - CT_TUNER_STEP_6, - CT_TUNER_STEP_7, - CT_TUNER_STOP, -}; - -#define FE_CALLBACK_TIME_NEVER 0xffffffff - struct dib0070_state { struct i2c_adapter *i2c; struct dvb_frontend *fe; @@ -71,10 +56,10 @@ struct dib0070_state { u16 wbd_ff_offset; u8 revision; - enum frontend_tune_state tune_state; - u32 current_rf; + enum frontend_tune_state tune_state; + u32 current_rf; - /* for the captrim binary search */ + /* for the captrim binary search */ s8 step; u16 adc_diff; @@ -85,7 +70,7 @@ struct dib0070_state { const struct dib0070_tuning *current_tune_table_index; const struct dib0070_lna_match *lna_match; - u8 wbd_gain_current; + u8 wbd_gain_current; u16 wbd_offset_3_3[2]; }; @@ -93,8 +78,8 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) { u8 b[2]; struct i2c_msg msg[2] = { - {.addr = state->cfg->i2c_address,.flags = 0,.buf = ®,.len = 1}, - {.addr = state->cfg->i2c_address,.flags = I2C_M_RD,.buf = b,.len = 2}, + { .addr = state->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, + { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 }, }; if (i2c_transfer(state->i2c, msg, 2) != 2) { printk(KERN_WARNING "DiB0070 I2C read failed\n"); @@ -106,7 +91,7 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) { u8 b[3] = { reg, val >> 8, val & 0xff }; - struct i2c_msg msg = {.addr = state->cfg->i2c_address,.flags = 0,.buf = b,.len = 3 }; + struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 }; if (i2c_transfer(state->i2c, &msg, 1) != 1) { printk(KERN_WARNING "DiB0070 I2C write failed\n"); return -EREMOTEIO; @@ -124,30 +109,30 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) { - struct dib0070_state *state = fe->tuner_priv; - u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; - - if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 7000) - tmp |= (0 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 6000) - tmp |= (1 << 14); - else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 > 5000) - tmp |= (2 << 14); - else - tmp |= (3 << 14); - - dib0070_write_reg(state, 0x02, tmp); - - /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { - u16 value = dib0070_read_reg(state, 0x17); - - dib0070_write_reg(state, 0x17, value & 0xfffc); - tmp = dib0070_read_reg(state, 0x01) & 0x01ff; - dib0070_write_reg(state, 0x01, tmp | (60 << 9)); - - dib0070_write_reg(state, 0x17, value); - } + struct dib0070_state *state = fe->tuner_priv; + u16 tmp = dib0070_read_reg(state, 0x02) & 0x3fff; + + if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 7000) + tmp |= (0 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 6000) + tmp |= (1 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz/1000 > 5000) + tmp |= (2 << 14); + else + tmp |= (3 << 14); + + dib0070_write_reg(state, 0x02, tmp); + + /* sharpen the BB filter in ISDB-T to have higher immunity to adjacent channels */ + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) { + u16 value = dib0070_read_reg(state, 0x17); + + dib0070_write_reg(state, 0x17, value & 0xfffc); + tmp = dib0070_read_reg(state, 0x01) & 0x01ff; + dib0070_write_reg(state, 0x01, tmp | (60 << 9)); + + dib0070_write_reg(state, 0x17, value); + } return 0; } @@ -160,14 +145,14 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state if (*tune_state == CT_TUNER_STEP_0) { dib0070_write_reg(state, 0x0f, 0xed10); - dib0070_write_reg(state, 0x17, 0x0034); + dib0070_write_reg(state, 0x17, 0x0034); dib0070_write_reg(state, 0x18, 0x0032); state->step = state->captrim = state->fcaptrim = 64; state->adc_diff = 3000; ret = 20; - *tune_state = CT_TUNER_STEP_1; + *tune_state = CT_TUNER_STEP_1; } else if (*tune_state == CT_TUNER_STEP_1) { state->step /= 2; dib0070_write_reg(state, 0x14, state->lo4 | state->captrim); @@ -178,7 +163,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state adc = dib0070_read_reg(state, 0x19); - dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc * (u32) 1800 / (u32) 1024); + dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); if (adc >= 400) { adc -= 400; @@ -193,6 +178,8 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state state->adc_diff = adc; state->fcaptrim = state->captrim; + + } state->captrim += (step_sign * state->step); @@ -213,7 +200,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt) { struct dib0070_state *state = fe->tuner_priv; - u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); + u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); dprintk("CTRL_LO5: 0x%x", lo5); return dib0070_write_reg(state, 0x15, lo5); } @@ -227,99 +214,99 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) dib0070_write_reg(state, 0x1a, 0x0000); } else { dib0070_write_reg(state, 0x1b, 0x4112); - if (state->cfg->vga_filter != 0) { - dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); - dprintk("vga filter register is set to %x", state->cfg->vga_filter); - } else - dib0070_write_reg(state, 0x1a, 0x0009); + if (state->cfg->vga_filter != 0) { + dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); + dprintk("vga filter register is set to %x", state->cfg->vga_filter); + } else + dib0070_write_reg(state, 0x1a, 0x0009); } } EXPORT_SYMBOL(dib0070_ctrl_agc_filter); struct dib0070_tuning { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 switch_trim; - u8 vco_band; - u8 hfdiv; - u8 vco_multi; - u8 presc; - u8 wbdmux; - u16 tuner_enable; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 vco_band; + u8 hfdiv; + u8 vco_multi; + u8 presc; + u8 wbdmux; + u16 tuner_enable; }; struct dib0070_lna_match { - u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ - u8 lna_band; + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 lna_band; }; static const struct dib0070_tuning dib0070s_tuning_table[] = { - {570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800}, /* UHF */ - {700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800}, - {863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800}, - {1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND */ - {1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, - {2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400}, - {0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000}, /* SBAND */ + { 570000, 2, 1, 3, 6, 6, 2, 0x4000 | 0x0800 }, /* UHF */ + { 700000, 2, 0, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 2, 4, 2, 2, 0x4000 | 0x0800 }, + { 1500000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND */ + { 1600000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 2000000, 0, 1, 1, 2, 2, 4, 0x2000 | 0x0400 }, + { 0xffffffff, 0, 0, 8, 1, 2, 1, 0x8000 | 0x1000 }, /* SBAND */ }; static const struct dib0070_tuning dib0070_tuning_table[] = { - {115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000}, /* FM below 92MHz cannot be tuned */ - {179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000}, /* VHF */ - {189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000}, - {250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000}, - {569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800}, /* UHF */ - {699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800}, - {863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800}, - {0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400}, /* LBAND or everything higher than UHF */ + { 115000, 1, 0, 7, 24, 2, 1, 0x8000 | 0x1000 }, /* FM below 92MHz cannot be tuned */ + { 179500, 1, 0, 3, 16, 2, 1, 0x8000 | 0x1000 }, /* VHF */ + { 189999, 1, 1, 3, 16, 2, 1, 0x8000 | 0x1000 }, + { 250000, 1, 0, 6, 12, 2, 1, 0x8000 | 0x1000 }, + { 569999, 2, 1, 5, 6, 2, 2, 0x4000 | 0x0800 }, /* UHF */ + { 699999, 2, 0, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 863999, 2, 1, 1, 4, 2, 2, 0x4000 | 0x0800 }, + { 0xffffffff, 0, 1, 0, 2, 2, 4, 0x2000 | 0x0400 }, /* LBAND or everything higher than UHF */ }; static const struct dib0070_lna_match dib0070_lna_flip_chip[] = { - {180000, 0}, /* VHF */ - {188000, 1}, - {196400, 2}, - {250000, 3}, - {550000, 0}, /* UHF */ - {590000, 1}, - {666000, 3}, - {864000, 5}, - {1500000, 0}, /* LBAND or everything higher than UHF */ - {1600000, 1}, - {2000000, 3}, - {0xffffffff, 7}, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 0 }, /* UHF */ + { 590000, 1 }, + { 666000, 3 }, + { 864000, 5 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; static const struct dib0070_lna_match dib0070_lna[] = { - {180000, 0}, /* VHF */ - {188000, 1}, - {196400, 2}, - {250000, 3}, - {550000, 2}, /* UHF */ - {650000, 3}, - {750000, 5}, - {850000, 6}, - {864000, 7}, - {1500000, 0}, /* LBAND or everything higher than UHF */ - {1600000, 1}, - {2000000, 3}, - {0xffffffff, 7}, + { 180000, 0 }, /* VHF */ + { 188000, 1 }, + { 196400, 2 }, + { 250000, 3 }, + { 550000, 2 }, /* UHF */ + { 650000, 3 }, + { 750000, 5 }, + { 850000, 6 }, + { 864000, 7 }, + { 1500000, 0 }, /* LBAND or everything higher than UHF */ + { 1600000, 1 }, + { 2000000, 3 }, + { 0xffffffff, 7 }, }; -#define LPF 100 // define for the loop filter 100kHz by default 16-07-06 +#define LPF 100 static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_tuning *tune; - const struct dib0070_lna_match *lna_match; + const struct dib0070_tuning *tune; + const struct dib0070_lna_match *lna_match; - enum frontend_tune_state *tune_state = &state->tune_state; - int ret = 10; /* 1ms is the default delay most of the time */ + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; /* 1ms is the default delay most of the time */ - u8 band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); - u32 freq = fe->dtv_property_cache.frequency / 1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); + u8 band = (u8)BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency/1000); + u32 freq = fe->dtv_property_cache.frequency/1000 + (band == BAND_VHF ? state->cfg->freq_offset_khz_vhf : state->cfg->freq_offset_khz_uhf); #ifdef CONFIG_SYS_ISDBT - if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) if (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) || (((state->fe->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) @@ -328,172 +315,180 @@ static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_par && (state->fe->dtv_property_cache.isdbt_sb_segment_idx == ((state->fe->dtv_property_cache.isdbt_sb_segment_count / 2) + 1)))) freq += 850; #endif + if (state->current_rf != freq) { + + switch (state->revision) { + case DIB0070S_P1A: + tune = dib0070s_tuning_table; + lna_match = dib0070_lna; + break; + default: + tune = dib0070_tuning_table; + if (state->cfg->flip_chip) + lna_match = dib0070_lna_flip_chip; + else + lna_match = dib0070_lna; + break; + } + while (freq > tune->max_freq) /* find the right one */ + tune++; + while (freq > lna_match->max_freq) /* find the right one */ + lna_match++; + + state->current_tune_table_index = tune; + state->lna_match = lna_match; + } + + if (*tune_state == CT_TUNER_START) { + dprintk("Tuning for Band: %hd (%d kHz)", band, freq); if (state->current_rf != freq) { + u8 REFDIV; + u32 FBDiv, Rest, FREF, VCOF_kHz; + u8 Den; + + state->current_rf = freq; + state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); + + + dib0070_write_reg(state, 0x17, 0x30); + + + VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; + + switch (band) { + case BAND_VHF: + REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); + break; + case BAND_FM: + REFDIV = (u8) ((state->cfg->clock_khz) / 1000); + break; + default: + REFDIV = (u8) (state->cfg->clock_khz / 10000); + break; + } + FREF = state->cfg->clock_khz / REFDIV; + + switch (state->revision) { case DIB0070S_P1A: - tune = dib0070s_tuning_table; - lna_match = dib0070_lna; + FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); + Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; break; + + case DIB0070_P1G: + case DIB0070_P1F: default: - tune = dib0070_tuning_table; - if (state->cfg->flip_chip) - lna_match = dib0070_lna_flip_chip; - else - lna_match = dib0070_lna; + FBDiv = (freq / (FREF / 2)); + Rest = 2 * freq - FBDiv * FREF; break; } - while (freq > tune->max_freq) /* find the right one */ - tune++; - while (freq > lna_match->max_freq) /* find the right one */ - lna_match++; - state->current_tune_table_index = tune; - state->lna_match = lna_match; - } + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + if (Rest > 0) { + state->lo4 |= (1 << 14) | (1 << 12); + Den = 255; + } + - if (*tune_state == CT_TUNER_START) { - dprintk("Tuning for Band: %hd (%d kHz)", band, freq); - if (state->current_rf != freq) { - u8 REFDIV; - u32 FBDiv, Rest, FREF, VCOF_kHz; - u8 Den; - - state->current_rf = freq; - state->lo4 = (state->current_tune_table_index->vco_band << 11) | (state->current_tune_table_index->hfdiv << 7); - - dib0070_write_reg(state, 0x17, 0x30); - - VCOF_kHz = state->current_tune_table_index->vco_multi * freq * 2; - - switch (band) { - case BAND_VHF: - REFDIV = (u8) ((state->cfg->clock_khz + 9999) / 10000); - break; - case BAND_FM: - REFDIV = (u8) ((state->cfg->clock_khz) / 1000); - break; - default: - REFDIV = (u8) (state->cfg->clock_khz / 10000); - break; - } - FREF = state->cfg->clock_khz / REFDIV; - - switch (state->revision) { - case DIB0070S_P1A: - FBDiv = (VCOF_kHz / state->current_tune_table_index->presc / FREF); - Rest = (VCOF_kHz / state->current_tune_table_index->presc) - FBDiv * FREF; - break; - - case DIB0070_P1G: - case DIB0070_P1F: - default: - FBDiv = (freq / (FREF / 2)); - Rest = 2 * freq - FBDiv * FREF; - break; - } - - if (Rest < LPF) - Rest = 0; - else if (Rest < 2 * LPF) - Rest = 2 * LPF; - else if (Rest > (FREF - LPF)) { - Rest = 0; - FBDiv += 1; - } else if (Rest > (FREF - 2 * LPF)) - Rest = FREF - 2 * LPF; - Rest = (Rest * 6528) / (FREF / 10); - - Den = 1; - if (Rest > 0) { - state->lo4 |= (1 << 14) | (1 << 12); - Den = 255; - } - - dib0070_write_reg(state, 0x11, (u16) FBDiv); - dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); - dib0070_write_reg(state, 0x13, (u16) Rest); - - if (state->revision == DIB0070S_P1A) { - - if (band == BAND_SBAND) { - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - dib0070_write_reg(state, 0x1d, 0xFFFF); - } else - dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); - } - - dib0070_write_reg(state, 0x20, - 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - - dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); - dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); - dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); - dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); - dprintk("VCO = %hd", state->current_tune_table_index->vco_band); - dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); - - *tune_state = CT_TUNER_STEP_0; - } else { /* we are already tuned to this frequency - the configuration is correct */ - ret = 50; /* wakeup time */ - *tune_state = CT_TUNER_STEP_5; + dib0070_write_reg(state, 0x11, (u16)FBDiv); + dib0070_write_reg(state, 0x12, (Den << 8) | REFDIV); + dib0070_write_reg(state, 0x13, (u16) Rest); + + if (state->revision == DIB0070S_P1A) { + + if (band == BAND_SBAND) { + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + dib0070_write_reg(state, 0x1d, 0xFFFF); + } else + dib0070_set_ctrl_lo5(fe, 5, 4, 3, 1); } - } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { - ret = dib0070_captrim(state, tune_state); + dib0070_write_reg(state, 0x20, + 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - } else if (*tune_state == CT_TUNER_STEP_4) { - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - if (tmp != NULL) { - while (freq / 1000 > tmp->freq) /* find the right one */ - tmp++; - dib0070_write_reg(state, 0x0f, - (0 << 15) | (1 << 14) | (3 << 12) | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) | (state-> - current_tune_table_index-> - wbdmux << 0)); - state->wbd_gain_current = tmp->wbd_gain_val; - } else { + dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); + dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); + dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); + dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); + dprintk("VCO = %hd", state->current_tune_table_index->vco_band); + dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); + + *tune_state = CT_TUNER_STEP_0; + } else { /* we are already tuned to this frequency - the configuration is correct */ + ret = 50; /* wakeup time */ + *tune_state = CT_TUNER_STEP_5; + } + } else if ((*tune_state > CT_TUNER_START) && (*tune_state < CT_TUNER_STEP_4)) { + + ret = dib0070_captrim(state, tune_state); + + } else if (*tune_state == CT_TUNER_STEP_4) { + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + dib0070_write_reg(state, 0x0f, + (0 << 15) | (1 << 14) | (3 << 12) + | (tmp->wbd_gain_val << 9) | (0 << 8) | (1 << 7) + | (state->current_tune_table_index->wbdmux << 0)); + state->wbd_gain_current = tmp->wbd_gain_val; + } else { dib0070_write_reg(state, 0x0f, (0 << 15) | (1 << 14) | (3 << 12) | (6 << 9) | (0 << 8) | (1 << 7) | (state->current_tune_table_index-> wbdmux << 0)); - state->wbd_gain_current = 6; - } + state->wbd_gain_current = 6; + } - dib0070_write_reg(state, 0x06, 0x3fff); + dib0070_write_reg(state, 0x06, 0x3fff); dib0070_write_reg(state, 0x07, (state->current_tune_table_index->switch_trim << 11) | (7 << 8) | (state->lna_match->lna_band << 3) | (3 << 0)); - dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); - dib0070_write_reg(state, 0x0d, 0x0d80); + dib0070_write_reg(state, 0x08, (state->lna_match->lna_band << 10) | (3 << 7) | (127)); + dib0070_write_reg(state, 0x0d, 0x0d80); - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x17, 0x0033); - *tune_state = CT_TUNER_STEP_5; - } else if (*tune_state == CT_TUNER_STEP_5) { - dib0070_set_bandwidth(fe, ch); - *tune_state = CT_TUNER_STOP; - } else { - ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ - } - return ret; + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x17, 0x0033); + + + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + dib0070_set_bandwidth(fe, ch); + *tune_state = CT_TUNER_STOP; + } else { + ret = FE_CALLBACK_TIME_NEVER; /* tuner finished, time to call again infinite */ + } + return ret; } + static int dib0070_tune(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { - struct dib0070_state *state = fe->tuner_priv; - uint32_t ret; + struct dib0070_state *state = fe->tuner_priv; + uint32_t ret; - state->tune_state = CT_TUNER_START; + state->tune_state = CT_TUNER_START; - do { - ret = dib0070_tune_digital(fe, p); - if (ret != FE_CALLBACK_TIME_NEVER) - msleep(ret / 10); - else - break; - } while (state->tune_state != CT_TUNER_STOP); + do { + ret = dib0070_tune_digital(fe, p); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret/10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); - return 0; + return 0; } static int dib0070_wakeup(struct dvb_frontend *fe) @@ -512,92 +507,113 @@ static int dib0070_sleep(struct dvb_frontend *fe) return 0; } -static const u16 dib0070_p1f_defaults[] = { +u8 dib0070_get_rf_output(struct dvb_frontend *fe) +{ + struct dib0070_state *state = fe->tuner_priv; + return (dib0070_read_reg(state, 0x07) >> 11) & 0x3; +} +EXPORT_SYMBOL(dib0070_get_rf_output); + +int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no) +{ + struct dib0070_state *state = fe->tuner_priv; + u16 rxrf2 = dib0070_read_reg(state, 0x07) & 0xfe7ff; + if (no > 3) + no = 3; + if (no < 1) + no = 1; + return dib0070_write_reg(state, 0x07, rxrf2 | (no << 11)); +} +EXPORT_SYMBOL(dib0070_set_rf_output); + +static const u16 dib0070_p1f_defaults[] = + +{ 7, 0x02, - 0x0008, - 0x0000, - 0x0000, - 0x0000, - 0x0000, - 0x0002, - 0x0100, + 0x0008, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0002, + 0x0100, 3, 0x0d, - 0x0d80, - 0x0001, - 0x0000, + 0x0d80, + 0x0001, + 0x0000, 4, 0x11, - 0x0000, - 0x0103, - 0x0000, - 0x0000, + 0x0000, + 0x0103, + 0x0000, + 0x0000, 3, 0x16, - 0x0004 | 0x0040, - 0x0030, - 0x07ff, + 0x0004 | 0x0040, + 0x0030, + 0x07ff, 6, 0x1b, - 0x4112, - 0xff00, - 0xc07f, - 0x0000, - 0x0180, - 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, + 0x4112, + 0xff00, + 0xc07f, + 0x0000, + 0x0180, + 0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001, 0, }; static u16 dib0070_read_wbd_offset(struct dib0070_state *state, u8 gain) { - u16 tuner_en = dib0070_read_reg(state, 0x20); - u16 offset; - - dib0070_write_reg(state, 0x18, 0x07ff); - dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); - dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); - msleep(9); - offset = dib0070_read_reg(state, 0x19); - dib0070_write_reg(state, 0x20, tuner_en); - return offset; + u16 tuner_en = dib0070_read_reg(state, 0x20); + u16 offset; + + dib0070_write_reg(state, 0x18, 0x07ff); + dib0070_write_reg(state, 0x20, 0x0800 | 0x4000 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001); + dib0070_write_reg(state, 0x0f, (1 << 14) | (2 << 12) | (gain << 9) | (1 << 8) | (1 << 7) | (0 << 0)); + msleep(9); + offset = dib0070_read_reg(state, 0x19); + dib0070_write_reg(state, 0x20, tuner_en); + return offset; } static void dib0070_wbd_offset_calibration(struct dib0070_state *state) { - u8 gain; - for (gain = 6; gain < 8; gain++) { - state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); - dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain - 6]); - } + u8 gain; + for (gain = 6; gain < 8; gain++) { + state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); + dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); + } } u16 dib0070_wbd_offset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; - const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; - u32 freq = fe->dtv_property_cache.frequency / 1000; - - if (tmp != NULL) { - while (freq / 1000 > tmp->freq) /* find the right one */ - tmp++; - state->wbd_gain_current = tmp->wbd_gain_val; + struct dib0070_state *state = fe->tuner_priv; + const struct dib0070_wbd_gain_cfg *tmp = state->cfg->wbd_gain; + u32 freq = fe->dtv_property_cache.frequency/1000; + + if (tmp != NULL) { + while (freq/1000 > tmp->freq) /* find the right one */ + tmp++; + state->wbd_gain_current = tmp->wbd_gain_val; } else - state->wbd_gain_current = 6; + state->wbd_gain_current = 6; - return state->wbd_offset_3_3[state->wbd_gain_current - 6]; + return state->wbd_offset_3_3[state->wbd_gain_current - 6]; } - EXPORT_SYMBOL(dib0070_wbd_offset); #define pgm_read_word(w) (*w) static int dib0070_reset(struct dvb_frontend *fe) { - struct dib0070_state *state = fe->tuner_priv; + struct dib0070_state *state = fe->tuner_priv; u16 l, r, *n; HARD_RESET(state); + #ifndef FORCE_SBAND_TUNER if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1) state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff; @@ -605,7 +621,7 @@ static int dib0070_reset(struct dvb_frontend *fe) #else #warning forcing SBAND #endif - state->revision = DIB0070S_P1A; + state->revision = DIB0070S_P1A; /* P1F or not */ dprintk("Revision: %x", state->revision); @@ -620,7 +636,7 @@ static int dib0070_reset(struct dvb_frontend *fe) while (l) { r = pgm_read_word(n++); do { - dib0070_write_reg(state, (u8) r, pgm_read_word(n++)); + dib0070_write_reg(state, (u8)r, pgm_read_word(n++)); r++; } while (--l); l = pgm_read_word(n++); @@ -633,6 +649,7 @@ static int dib0070_reset(struct dvb_frontend *fe) else r = 2; + r |= state->cfg->osc_buffer_state << 3; dib0070_write_reg(state, 0x10, r); @@ -643,16 +660,24 @@ static int dib0070_reset(struct dvb_frontend *fe) dib0070_write_reg(state, 0x02, r | (1 << 5)); } - if (state->revision == DIB0070S_P1A) - dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); - else + if (state->revision == DIB0070S_P1A) + dib0070_set_ctrl_lo5(fe, 2, 4, 3, 0); + else dib0070_set_ctrl_lo5(fe, 5, 4, state->cfg->charge_pump, state->cfg->enable_third_order_filter); dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8); - dib0070_wbd_offset_calibration(state); + dib0070_wbd_offset_calibration(state); - return 0; + return 0; +} + +static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dib0070_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; } static int dib0070_release(struct dvb_frontend *fe) @@ -664,18 +689,18 @@ static int dib0070_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops dib0070_ops = { .info = { - .name = "DiBcom DiB0070", - .frequency_min = 45000000, - .frequency_max = 860000000, - .frequency_step = 1000, - }, - .release = dib0070_release, - - .init = dib0070_wakeup, - .sleep = dib0070_sleep, - .set_params = dib0070_tune, - -// .get_frequency = dib0070_get_frequency, + .name = "DiBcom DiB0070", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0070_release, + + .init = dib0070_wakeup, + .sleep = dib0070_sleep, + .set_params = dib0070_tune, + + .get_frequency = dib0070_get_frequency, // .get_bandwidth = dib0070_get_bandwidth }; @@ -687,7 +712,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter state->cfg = cfg; state->i2c = i2c; - state->fe = fe; + state->fe = fe; fe->tuner_priv = state; if (dib0070_reset(fe) != 0) @@ -699,12 +724,11 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter fe->tuner_priv = state; return fe; - free_mem: +free_mem: kfree(state); fe->tuner_priv = NULL; return NULL; } - EXPORT_SYMBOL(dib0070_attach); MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h index eec9e52ffa75..45c31fae3967 100644 --- a/drivers/media/dvb/frontends/dib0070.h +++ b/drivers/media/dvb/frontends/dib0070.h @@ -52,6 +52,8 @@ struct dib0070_config { extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); extern u16 dib0070_wbd_offset(struct dvb_frontend *); extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, u8 open); +extern u8 dib0070_get_rf_output(struct dvb_frontend *fe); +extern int dib0070_set_rf_output(struct dvb_frontend *fe, u8 no); #else static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg) { @@ -62,7 +64,7 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struc static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; + return 0; } static inline void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c new file mode 100644 index 000000000000..614552709a6f --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.c @@ -0,0 +1,1522 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-9 DiBcom (http://www.dibcom.fr/) + * + * 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. + * + * 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. + * + * + * This code is more or less generated from another driver, please + * excuse some codingstyle oddities. + * + */ + +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include "dvb_frontend.h" + +#include "dib0090.h" +#include "dibx000_common.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); + +#define dprintk(args...) do { \ + if (debug) { \ + printk(KERN_DEBUG "DiB0090: "); \ + printk(args); \ + printk("\n"); \ + } \ +} while (0) + +#define CONFIG_SYS_ISDBT +#define CONFIG_BAND_CBAND +#define CONFIG_BAND_VHF +#define CONFIG_BAND_UHF +#define CONFIG_DIB0090_USE_PWM_AGC + +#define EN_LNA0 0x8000 +#define EN_LNA1 0x4000 +#define EN_LNA2 0x2000 +#define EN_LNA3 0x1000 +#define EN_MIX0 0x0800 +#define EN_MIX1 0x0400 +#define EN_MIX2 0x0200 +#define EN_MIX3 0x0100 +#define EN_IQADC 0x0040 +#define EN_PLL 0x0020 +#define EN_TX 0x0010 +#define EN_BB 0x0008 +#define EN_LO 0x0004 +#define EN_BIAS 0x0001 + +#define EN_IQANA 0x0002 +#define EN_DIGCLK 0x0080 /* not in the 0x24 reg, only in 0x1b */ +#define EN_CRYSTAL 0x0002 + +#define EN_UHF 0x22E9 +#define EN_VHF 0x44E9 +#define EN_LBD 0x11E9 +#define EN_SBD 0x44E9 +#define EN_CAB 0x88E9 + +#define pgm_read_word(w) (*w) + +struct dc_calibration; + +struct dib0090_tuning { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 switch_trim; + u8 lna_tune; + u8 lna_bias; + u16 v2i; + u16 mix; + u16 load; + u16 tuner_enable; +}; + +struct dib0090_pll { + u32 max_freq; /* for every frequency less than or equal to that field: this information is correct */ + u8 vco_band; + u8 hfdiv_code; + u8 hfdiv; + u8 topresc; +}; + +struct dib0090_state { + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + const struct dib0090_config *config; + + u8 current_band; + u16 revision; + enum frontend_tune_state tune_state; + u32 current_rf; + + u16 wbd_offset; + s16 wbd_target; /* in dB */ + + s16 rf_gain_limit; /* take-over-point: where to split between bb and rf gain */ + s16 current_gain; /* keeps the currently programmed gain */ + u8 agc_step; /* new binary search */ + + u16 gain[2]; /* for channel monitoring */ + + const u16 *rf_ramp; + const u16 *bb_ramp; + + /* for the software AGC ramps */ + u16 bb_1_def; + u16 rf_lt_def; + u16 gain_reg[4]; + + /* for the captrim/dc-offset search */ + s8 step; + s16 adc_diff; + s16 min_adc_diff; + + s8 captrim; + s8 fcaptrim; + + const struct dc_calibration *dc; + u16 bb6, bb7; + + const struct dib0090_tuning *current_tune_table_index; + const struct dib0090_pll *current_pll_table_index; + + u8 tuner_is_tuned; + u8 agc_freeze; + + u8 reset; +}; + +static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) +{ + u8 b[2]; + struct i2c_msg msg[2] = { + {.addr = state->config->i2c_address, .flags = 0, .buf = ®, .len = 1}, + {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2}, + }; + if (i2c_transfer(state->i2c, msg, 2) != 2) { + printk(KERN_WARNING "DiB0090 I2C read failed\n"); + return 0; + } + return (b[0] << 8) | b[1]; +} + +static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) +{ + u8 b[3] = { reg & 0xff, val >> 8, val & 0xff }; + struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 }; + if (i2c_transfer(state->i2c, &msg, 1) != 1) { + printk(KERN_WARNING "DiB0090 I2C write failed\n"); + return -EREMOTEIO; + } + return 0; +} + +#define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) +#define ADC_TARGET -220 +#define GAIN_ALPHA 5 +#define WBD_ALPHA 6 +#define LPF 100 +static void dib0090_write_regs(struct dib0090_state *state, u8 r, const u16 * b, u8 c) +{ + do { + dib0090_write_reg(state, r++, *b++); + } while (--c); +} + +static u16 dib0090_identify(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 v; + + v = dib0090_read_reg(state, 0x1a); + +#ifdef FIRMWARE_FIREFLY + /* pll is not locked locked */ + if (!(v & 0x800)) + dprintk("FE%d : Identification : pll is not yet locked", fe->id); +#endif + + /* without PLL lock info */ + v &= 0x3ff; + dprintk("P/V: %04x:", v); + + if ((v >> 8) & 0xf) + dprintk("FE%d : Product ID = 0x%x : KROSUS", fe->id, (v >> 8) & 0xf); + else + return 0xff; + + v &= 0xff; + if (((v >> 5) & 0x7) == 0x1) + dprintk("FE%d : MP001 : 9090/8096", fe->id); + else if (((v >> 5) & 0x7) == 0x4) + dprintk("FE%d : MP005 : Single Sband", fe->id); + else if (((v >> 5) & 0x7) == 0x6) + dprintk("FE%d : MP008 : diversity VHF-UHF-LBAND", fe->id); + else if (((v >> 5) & 0x7) == 0x7) + dprintk("FE%d : MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND", fe->id); + else + return 0xff; + + /* revision only */ + if ((v & 0x1f) == 0x3) + dprintk("FE%d : P1-D/E/F detected", fe->id); + else if ((v & 0x1f) == 0x1) + dprintk("FE%d : P1C detected", fe->id); + else if ((v & 0x1f) == 0x0) { +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + dprintk("FE%d : P1-A/B detected: using previous driver - support will be removed soon", fe->id); + dib0090_p1b_register(fe); +#else + dprintk("FE%d : P1-A/B detected: driver is deactivated - not available", fe->id); + return 0xff; +#endif + } + + return v; +} + +static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_config *cfg) +{ + struct dib0090_state *state = fe->tuner_priv; + + HARD_RESET(state); + + dib0090_write_reg(state, 0x24, EN_PLL); + dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + + /* adcClkOutRatio=8->7, release reset */ + dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (cfg->clkoutdrive != 0) + dib0090_write_reg(state, 0x23, + (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (cfg->clkoutdrive << 5) | (cfg-> + clkouttobamse + << 4) | (0 + << + 2) + | (0)); + else + dib0090_write_reg(state, 0x23, + (0 << 15) | ((!cfg->analog_output) << 14) | (1 << 10) | (1 << 9) | (0 << 8) | (7 << 5) | (cfg-> + clkouttobamse << 4) | (0 + << + 2) + | (0)); + + /* enable pll, de-activate reset, ratio: 2/1 = 60MHz */ + dib0090_write_reg(state, 0x21, + (cfg->io.pll_bypass << 15) | (1 << 13) | (cfg->io.pll_range << 12) | (cfg->io.pll_loopdiv << 6) | (cfg->io.pll_prediv)); + +} + +static int dib0090_wakeup(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 0); + return 0; +} + +static int dib0090_sleep(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + if (state->config->sleep) + state->config->sleep(fe, 1); + return 0; +} + +extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + struct dib0090_state *state = fe->tuner_priv; + if (fast) + dib0090_write_reg(state, 0x04, 0); + else + dib0090_write_reg(state, 0x04, 1); +} +EXPORT_SYMBOL(dib0090_dcc_freq); + +static const u16 rf_ramp_pwm_cband[] = { + 0, /* max RF gain in 10th of dB */ + 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 0, /* ramp_max = maximum X used on the ramp */ + (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ + (0 << 10) | 0, /* 0x2d, LNA 1 */ + (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ + (0 << 10) | 0, /* 0x2f, LNA 2 */ + (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ + (0 << 10) | 0, /* 0x31, LNA 3 */ + (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ + (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_vhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1, 13.2dB */ + 105, 412, 255, /* LNA2, 10.5dB */ + 50, 50, 127, /* LNA3, 5dB */ + 125, 175, 127, /* LNA4, 12.5dB */ + 0, 0, 127, /* CBAND, 0dB */ +}; + +static const u16 rf_ramp_uhf[] = { + 412, /* max RF gain in 10th of dB */ + 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ + 105, 412, 255, /* LNA2 : 10.5 dB */ + 50, 50, 127, /* LNA3 : 5.0 dB */ + 125, 175, 127, /* LNA4 : 12.5 dB */ + 0, 0, 127, /* CBAND : 0.0 dB */ +}; + +static const u16 rf_ramp_cband[] = { + 332, /* max RF gain in 10th of dB */ + 132, 252, 127, /* LNA1, dB */ + 80, 332, 255, /* LNA2, dB */ + 0, 0, 127, /* LNA3, dB */ + 0, 0, 127, /* LNA4, dB */ + 120, 120, 127, /* LT1 CBAND */ +}; + +static const u16 rf_ramp_pwm_vhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 417, /* 0x31, LNA 3 */ + (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 rf_ramp_pwm_uhf[] = { + 404, /* max RF gain in 10th of dB */ + 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ + 1011, /* ramp_max = maximum X used on the ramp */ + (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ + (0 << 10) | 756, /* 0x2d, LNA 1 */ + (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ + (0 << 10) | 1011, /* 0x2f, LNA 2 */ + (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ + (0 << 10) | 127, /* 0x31, LNA 3 */ + (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ +}; + +static const u16 bb_ramp_boost[] = { + 550, /* max BB gain in 10th of dB */ + 260, 260, 26, /* BB1, 26dB */ + 290, 550, 29, /* BB2, 29dB */ +}; + +static const u16 bb_ramp_pwm_normal[] = { + 500, /* max RF gain in 10th of dB */ + 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ + 400, + (2 << 9) | 0, /* 0x35 = 21dB */ + (0 << 9) | 168, /* 0x36 */ + (2 << 9) | 168, /* 0x37 = 29dB */ + (0 << 9) | 400, /* 0x38 */ +}; + +struct slope { + int16_t range; + int16_t slope; +}; +static u16 slopes_to_scale(const struct slope *slopes, u8 num, s16 val) +{ + u8 i; + u16 rest; + u16 ret = 0; + for (i = 0; i < num; i++) { + if (val > slopes[i].range) + rest = slopes[i].range; + else + rest = val; + ret += (rest * slopes[i].slope) / slopes[i].range; + val -= rest; + } + return ret; +} + +static const struct slope dib0090_wbd_slopes[3] = { + {66, 120}, /* -64,-52: offset - 65 */ + {600, 170}, /* -52,-35: 65 - 665 */ + {170, 250}, /* -45,-10: 665 - 835 */ +}; + +static s16 dib0090_wbd_to_db(struct dib0090_state *state, u16 wbd) +{ + wbd &= 0x3ff; + if (wbd < state->wbd_offset) + wbd = 0; + else + wbd -= state->wbd_offset; + /* -64dB is the floor */ + return -640 + (s16) slopes_to_scale(dib0090_wbd_slopes, ARRAY_SIZE(dib0090_wbd_slopes), wbd); +} + +static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) +{ + u16 offset = 250; + + /* TODO : DAB digital N+/-1 interferer perfs : offset = 10 */ + + if (state->current_band == BAND_VHF) + offset = 650; +#ifndef FIRMWARE_FIREFLY + if (state->current_band == BAND_VHF) + offset = state->config->wbd_vhf_offset; + if (state->current_band == BAND_CBAND) + offset = state->config->wbd_cband_offset; +#endif + + state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); + dprintk("wbd-target: %d dB", (u32) state->wbd_target); +} + +static const int gain_reg_addr[4] = { + 0x08, 0x0a, 0x0f, 0x01 +}; + +static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 top_delta, u8 force) +{ + u16 rf, bb, ref; + u16 i, v, gain_reg[4] = { 0 }, gain; + const u16 *g; + + if (top_delta < -511) + top_delta = -511; + if (top_delta > 511) + top_delta = 511; + + if (force) { + top_delta *= (1 << WBD_ALPHA); + gain_delta *= (1 << GAIN_ALPHA); + } + + if (top_delta >= ((s16) (state->rf_ramp[0] << WBD_ALPHA) - state->rf_gain_limit)) /* overflow */ + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + else + state->rf_gain_limit += top_delta; + + if (state->rf_gain_limit < 0) /*underflow */ + state->rf_gain_limit = 0; + + /* use gain as a temporary variable and correct current_gain */ + gain = ((state->rf_gain_limit >> WBD_ALPHA) + state->bb_ramp[0]) << GAIN_ALPHA; + if (gain_delta >= ((s16) gain - state->current_gain)) /* overflow */ + state->current_gain = gain; + else + state->current_gain += gain_delta; + /* cannot be less than 0 (only if gain_delta is less than 0 we can have current_gain < 0) */ + if (state->current_gain < 0) + state->current_gain = 0; + + /* now split total gain to rf and bb gain */ + gain = state->current_gain >> GAIN_ALPHA; + + /* requested gain is bigger than rf gain limit - ACI/WBD adjustment */ + if (gain > (state->rf_gain_limit >> WBD_ALPHA)) { + rf = state->rf_gain_limit >> WBD_ALPHA; + bb = gain - rf; + if (bb > state->bb_ramp[0]) + bb = state->bb_ramp[0]; + } else { /* high signal level -> all gains put on RF */ + rf = gain; + bb = 0; + } + + state->gain[0] = rf; + state->gain[1] = bb; + + /* software ramp */ + /* Start with RF gains */ + g = state->rf_ramp + 1; /* point on RF LNA1 max gain */ + ref = rf; + for (i = 0; i < 7; i++) { /* Go over all amplifiers => 5RF amps + 2 BB amps = 7 amps */ + if (g[0] == 0 || ref < (g[1] - g[0])) /* if total gain of the current amp is null or this amp is not concerned because it starts to work from an higher gain value */ + v = 0; /* force the gain to write for the current amp to be null */ + else if (ref >= g[1]) /* Gain to set is higher than the high working point of this amp */ + v = g[2]; /* force this amp to be full gain */ + else /* compute the value to set to this amp because we are somewhere in his range */ + v = ((ref - (g[1] - g[0])) * g[2]) / g[0]; + + if (i == 0) /* LNA 1 reg mapping */ + gain_reg[0] = v; + else if (i == 1) /* LNA 2 reg mapping */ + gain_reg[0] |= v << 7; + else if (i == 2) /* LNA 3 reg mapping */ + gain_reg[1] = v; + else if (i == 3) /* LNA 4 reg mapping */ + gain_reg[1] |= v << 7; + else if (i == 4) /* CBAND LNA reg mapping */ + gain_reg[2] = v | state->rf_lt_def; + else if (i == 5) /* BB gain 1 reg mapping */ + gain_reg[3] = v << 3; + else if (i == 6) /* BB gain 2 reg mapping */ + gain_reg[3] |= v << 8; + + g += 3; /* go to next gain bloc */ + + /* When RF is finished, start with BB */ + if (i == 4) { + g = state->bb_ramp + 1; /* point on BB gain 1 max gain */ + ref = bb; + } + } + gain_reg[3] |= state->bb_1_def; + gain_reg[3] |= ((bb % 10) * 100) / 125; + +#ifdef DEBUG_AGC + dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, + gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); +#endif + + /* Write the amplifier regs */ + for (i = 0; i < 4; i++) { + v = gain_reg[i]; + if (force || state->gain_reg[i] != v) { + state->gain_reg[i] = v; + dib0090_write_reg(state, gain_reg_addr[i], v); + } + } +} + +static void dib0090_set_boost(struct dib0090_state *state, int onoff) +{ + state->bb_1_def &= 0xdfff; + state->bb_1_def |= onoff << 13; +} + +static void dib0090_set_rframp(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; +} + +static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->rf_ramp = cfg; + + dib0090_write_reg(state, 0x2a, 0xffff); + + dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); + + dib0090_write_regs(state, 0x2c, cfg + 3, 6); + dib0090_write_regs(state, 0x3e, cfg + 9, 2); +} + +static void dib0090_set_bbramp(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ +} + +static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) +{ + state->bb_ramp = cfg; + + dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ + + dib0090_write_reg(state, 0x33, 0xffff); + dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); + dib0090_write_regs(state, 0x35, cfg + 3, 4); +} + +void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + /* reset the AGC */ + + if (state->config->use_pwm_agc) { +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF) { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } else +#endif + { + dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); + dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + } + + if (state->rf_ramp[0] != 0) + dib0090_write_reg(state, 0x32, (3 << 11)); + else + dib0090_write_reg(state, 0x32, (0 << 11)); + + dib0090_write_reg(state, 0x39, (1 << 10)); + } +} +EXPORT_SYMBOL(dib0090_pwm_gain_reset); + +int dib0090_gain_control(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + enum frontend_tune_state *tune_state = &state->tune_state; + int ret = 10; + + u16 wbd_val = 0; + u8 apply_gain_immediatly = 1; + s16 wbd_error = 0, adc_error = 0; + + if (*tune_state == CT_AGC_START) { + state->agc_freeze = 0; + dib0090_write_reg(state, 0x04, 0x0); + +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) { + dib0090_set_rframp(state, rf_ramp_sband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_VHF + if (state->current_band == BAND_VHF) { + dib0090_set_rframp(state, rf_ramp_vhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif +#ifdef CONFIG_BAND_CBAND + if (state->current_band == BAND_CBAND) { + dib0090_set_rframp(state, rf_ramp_cband); + dib0090_set_bbramp(state, bb_ramp_boost); + } else +#endif + { + dib0090_set_rframp(state, rf_ramp_uhf); + dib0090_set_bbramp(state, bb_ramp_boost); + } + + dib0090_write_reg(state, 0x32, 0); + dib0090_write_reg(state, 0x39, 0); + + dib0090_wbd_target(state, state->current_rf); + + state->rf_gain_limit = state->rf_ramp[0] << WBD_ALPHA; + state->current_gain = ((state->rf_ramp[0] + state->bb_ramp[0]) / 2) << GAIN_ALPHA; + + *tune_state = CT_AGC_STEP_0; + } else if (!state->agc_freeze) { + s16 wbd; + + int adc; + wbd_val = dib0090_read_reg(state, 0x1d); + + /* read and calc the wbd power */ + wbd = dib0090_wbd_to_db(state, wbd_val); + wbd_error = state->wbd_target - wbd; + + if (*tune_state == CT_AGC_STEP_0) { + if (wbd_error < 0 && state->rf_gain_limit > 0) { +#ifdef CONFIG_BAND_CBAND + /* in case of CBAND tune reduce first the lt_gain2 before adjusting the RF gain */ + u8 ltg2 = (state->rf_lt_def >> 10) & 0x7; + if (state->current_band == BAND_CBAND && ltg2) { + ltg2 >>= 1; + state->rf_lt_def &= ltg2 << 10; /* reduce in 3 steps from 7 to 0 */ + } +#endif + } else { + state->agc_step = 0; + *tune_state = CT_AGC_STEP_1; + } + } else { + /* calc the adc power */ + adc = state->config->get_adc_power(fe); + adc = (adc * ((s32) 355774) + (((s32) 1) << 20)) >> 21; /* included in [0:-700] */ + + adc_error = (s16) (((s32) ADC_TARGET) - adc); +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) + adc_error += 130; +#endif +#ifdef CONFIG_STANDARD_DVBT + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DVBT && + (state->fe->dtv_property_cache.modulation == QAM_64 || state->fe->dtv_property_cache.modulation == QAM_16)) + adc_error += 60; +#endif +#ifdef CONFIG_SYS_ISDBT + if ((state->fe->dtv_property_cache.delivery_system == SYS_ISDBT) && (((state->fe->dtv_property_cache.layer[0].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[0].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[0]. + modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[1].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[1].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[1]. + modulation == QAM_16))) + || + ((state->fe->dtv_property_cache.layer[2].segment_count > + 0) + && + ((state->fe->dtv_property_cache.layer[2].modulation == + QAM_64) + || (state->fe->dtv_property_cache.layer[2]. + modulation == QAM_16))) + ) + ) + adc_error += 60; +#endif + + if (*tune_state == CT_AGC_STEP_1) { /* quickly go to the correct range of the ADC power */ + if (ABS(adc_error) < 50 || state->agc_step++ > 5) { + +#ifdef CONFIG_STANDARD_DAB + if (state->fe->dtv_property_cache.delivery_system == STANDARD_DAB) { + dib0090_write_reg(state, 0x02, (1 << 15) | (15 << 11) | (31 << 6) | (63)); /* cap value = 63 : narrow BB filter : Fc = 1.8MHz */ + dib0090_write_reg(state, 0x04, 0x0); + } else +#endif + { + dib0090_write_reg(state, 0x02, (1 << 15) | (3 << 11) | (6 << 6) | (32)); + dib0090_write_reg(state, 0x04, 0x01); /*0 = 1KHz ; 1 = 150Hz ; 2 = 50Hz ; 3 = 50KHz ; 4 = servo fast */ + } + + *tune_state = CT_AGC_STOP; + } + } else { + /* everything higher than or equal to CT_AGC_STOP means tracking */ + ret = 100; /* 10ms interval */ + apply_gain_immediatly = 0; + } + } +#ifdef DEBUG_AGC + dprintk + ("FE: %d, tune state %d, ADC = %3ddB (ADC err %3d) WBD %3ddB (WBD err %3d, WBD val SADC: %4d), RFGainLimit (TOP): %3d, signal: %3ddBm", + (u32) fe->id, (u32) *tune_state, (u32) adc, (u32) adc_error, (u32) wbd, (u32) wbd_error, (u32) wbd_val, + (u32) state->rf_gain_limit >> WBD_ALPHA, (s32) 200 + adc - (state->current_gain >> GAIN_ALPHA)); +#endif + } + + /* apply gain */ + if (!state->agc_freeze) + dib0090_gain_apply(state, adc_error, wbd_error, apply_gain_immediatly); + return ret; +} +EXPORT_SYMBOL(dib0090_gain_control); + +void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + struct dib0090_state *state = fe->tuner_priv; + if (rf) + *rf = state->gain[0]; + if (bb) + *bb = state->gain[1]; + if (rf_gain_limit) + *rf_gain_limit = state->rf_gain_limit; + if (rflt) + *rflt = (state->rf_lt_def >> 10) & 0x7; +} +EXPORT_SYMBOL(dib0090_get_current_gain); + +u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +{ + struct dib0090_state *st = tuner->tuner_priv; + return st->wbd_offset; +} +EXPORT_SYMBOL(dib0090_get_wbd_offset); + +static const u16 dib0090_defaults[] = { + + 25, 0x01, + 0x0000, + 0x99a0, + 0x6008, + 0x0000, + 0x8acb, + 0x0000, + 0x0405, + 0x0000, + 0x0000, + 0x0000, + 0xb802, + 0x0300, + 0x2d12, + 0xbac0, + 0x7c00, + 0xdbb9, + 0x0954, + 0x0743, + 0x8000, + 0x0001, + 0x0040, + 0x0100, + 0x0000, + 0xe910, + 0x149e, + + 1, 0x1c, + 0xff2d, + + 1, 0x39, + 0x0000, + + 1, 0x1b, + EN_IQADC | EN_BB | EN_BIAS | EN_DIGCLK | EN_PLL | EN_CRYSTAL, + 2, 0x1e, + 0x07FF, + 0x0007, + + 1, 0x24, + EN_UHF | EN_CRYSTAL, + + 2, 0x3c, + 0x3ff, + 0x111, + 0 +}; + +static int dib0090_reset(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + u16 l, r, *n; + + dib0090_reset_digital(fe, state->config); + state->revision = dib0090_identify(fe); + + /* Revision definition */ + if (state->revision == 0xff) + return -EINVAL; +#ifdef EFUSE + else if ((state->revision & 0x1f) >= 3) /* Update the efuse : Only available for KROSUS > P1C */ + dib0090_set_EFUSE(state); +#endif + +#ifdef CONFIG_TUNER_DIB0090_P1B_SUPPORT + if (!(state->revision & 0x1)) /* it is P1B - reset is already done */ + return 0; +#endif + + /* Upload the default values */ + n = (u16 *) dib0090_defaults; + l = pgm_read_word(n++); + while (l) { + r = pgm_read_word(n++); + do { + /* DEBUG_TUNER */ + /* dprintk("%d, %d, %d", l, r, pgm_read_word(n)); */ + dib0090_write_reg(state, r, pgm_read_word(n++)); + r++; + } while (--l); + l = pgm_read_word(n++); + } + + /* Congigure in function of the crystal */ + if (state->config->io.clock_khz >= 24000) + l = 1; + else + l = 2; + dib0090_write_reg(state, 0x14, l); + dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); + + state->reset = 3; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ + + return 0; +} + +#define steps(u) (((u) > 15) ? ((u)-16) : (u)) +#define INTERN_WAIT 10 +static int dib0090_get_offset(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = INTERN_WAIT * 10; + + switch (*tune_state) { + case CT_TUNER_STEP_2: + /* Turns to positive */ + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_STEP_3; + break; + + case CT_TUNER_STEP_3: + state->adc_diff = dib0090_read_reg(state, 0x1d); + + /* Turns to negative */ + dib0090_write_reg(state, 0x1f, 0x4); + *tune_state = CT_TUNER_STEP_4; + break; + + case CT_TUNER_STEP_4: + state->adc_diff -= dib0090_read_reg(state, 0x1d); + *tune_state = CT_TUNER_STEP_5; + ret = 0; + break; + + default: + break; + } + + return ret; +} + +struct dc_calibration { + uint8_t addr; + uint8_t offset; + uint8_t pga:1; + uint16_t bb1; + uint8_t i:1; +}; + +static const struct dc_calibration dc_table[] = { + /* Step1 BB gain1= 26 with boost 1, gain 2 = 0 */ + {0x06, 5, 1, (1 << 13) | (0 << 8) | (26 << 3), 1}, + {0x07, 11, 1, (1 << 13) | (0 << 8) | (26 << 3), 0}, + /* Step 2 BB gain 1 = 26 with boost = 1 & gain 2 = 29 */ + {0x06, 0, 0, (1 << 13) | (29 << 8) | (26 << 3), 1}, + {0x06, 10, 0, (1 << 13) | (29 << 8) | (26 << 3), 0}, + {0}, +}; + +static void dib0090_set_trim(struct dib0090_state *state) +{ + u16 *val; + + if (state->dc->addr == 0x07) + val = &state->bb7; + else + val = &state->bb6; + + *val &= ~(0x1f << state->dc->offset); + *val |= state->step << state->dc->offset; + + dib0090_write_reg(state, state->dc->addr, *val); +} + +static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + int ret = 0; + + switch (*tune_state) { + + case CT_TUNER_START: + /* init */ + dprintk("Internal DC calibration"); + + /* the LNA is off */ + dib0090_write_reg(state, 0x24, 0x02ed); + + /* force vcm2 = 0.8V */ + state->bb6 = 0; + state->bb7 = 0x040d; + + state->dc = dc_table; + + *tune_state = CT_TUNER_STEP_0; + + /* fall through */ + + case CT_TUNER_STEP_0: + dib0090_write_reg(state, 0x01, state->dc->bb1); + dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); + + state->step = 0; + + state->min_adc_diff = 1023; + + *tune_state = CT_TUNER_STEP_1; + ret = 50; + break; + + case CT_TUNER_STEP_1: + dib0090_set_trim(state); + + *tune_state = CT_TUNER_STEP_2; + break; + + case CT_TUNER_STEP_2: + case CT_TUNER_STEP_3: + case CT_TUNER_STEP_4: + ret = dib0090_get_offset(state, tune_state); + break; + + case CT_TUNER_STEP_5: /* found an offset */ + dprintk("FE%d: IQC read=%d, current=%x", state->fe->id, (u32) state->adc_diff, state->step); + + /* first turn for this frequency */ + if (state->step == 0) { + if (state->dc->pga && state->adc_diff < 0) + state->step = 0x10; + if (state->dc->pga == 0 && state->adc_diff > 0) + state->step = 0x10; + } + + state->adc_diff = ABS(state->adc_diff); + + if (state->adc_diff < state->min_adc_diff && steps(state->step) < 15) { /* stop search when the delta to 0 is increasing */ + state->step++; + state->min_adc_diff = state->adc_diff; + *tune_state = CT_TUNER_STEP_1; + } else { + + /* the minimum was what we have seen in the step before */ + state->step--; + dib0090_set_trim(state); + + dprintk("FE%d: BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->fe->id, state->dc->addr, state->adc_diff, + state->step); + + state->dc++; + if (state->dc->addr == 0) /* done */ + *tune_state = CT_TUNER_STEP_6; + else + *tune_state = CT_TUNER_STEP_0; + + } + break; + + case CT_TUNER_STEP_6: + dib0090_write_reg(state, 0x07, state->bb7 & ~0x0008); + dib0090_write_reg(state, 0x1f, 0x7); + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->reset &= ~0x1; + default: + break; + } + return ret; +} + +static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tune_state *tune_state) +{ + switch (*tune_state) { + case CT_TUNER_START: + /* WBD-mode=log, Bias=2, Gain=6, Testmode=1, en=1, WBDMUX=1 */ + dib0090_write_reg(state, 0x10, 0xdb09 | (1 << 10)); + dib0090_write_reg(state, 0x24, EN_UHF & 0x0fff); + + *tune_state = CT_TUNER_STEP_0; + return 90; /* wait for the WBDMUX to switch and for the ADC to sample */ + case CT_TUNER_STEP_0: + state->wbd_offset = dib0090_read_reg(state, 0x1d); + dprintk("WBD calibration offset = %d", state->wbd_offset); + + *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ + state->reset &= ~0x2; + break; + default: + break; + } + return 0; +} + +static void dib0090_set_bandwidth(struct dib0090_state *state) +{ + u16 tmp; + + if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 5000) + tmp = (3 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 6000) + tmp = (2 << 14); + else if (state->fe->dtv_property_cache.bandwidth_hz / 1000 <= 7000) + tmp = (1 << 14); + else + tmp = (0 << 14); + + state->bb_1_def &= 0x3fff; + state->bb_1_def |= tmp; + + dib0090_write_reg(state, 0x01, state->bb_1_def); /* be sure that we have the right bb-filter */ +} + +static const struct dib0090_pll dib0090_pll_table[] = { +#ifdef CONFIG_BAND_CBAND + {56000, 0, 9, 48, 6}, + {70000, 1, 9, 48, 6}, + {87000, 0, 8, 32, 4}, + {105000, 1, 8, 32, 4}, + {115000, 0, 7, 24, 6}, + {140000, 1, 7, 24, 6}, + {170000, 0, 6, 16, 4}, +#endif +#ifdef CONFIG_BAND_VHF + {200000, 1, 6, 16, 4}, + {230000, 0, 5, 12, 6}, + {280000, 1, 5, 12, 6}, + {340000, 0, 4, 8, 4}, + {380000, 1, 4, 8, 4}, + {450000, 0, 3, 6, 6}, +#endif +#ifdef CONFIG_BAND_UHF + {580000, 1, 3, 6, 6}, + {700000, 0, 2, 4, 4}, + {860000, 1, 2, 4, 4}, +#endif +#ifdef CONFIG_BAND_LBAND + {1800000, 1, 0, 2, 4}, +#endif +#ifdef CONFIG_BAND_SBAND + {2900000, 0, 14, 1, 4}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table_fm_vhf_on_cband[] = { + +#ifdef CONFIG_BAND_CBAND + {184000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {227000, 4, 3, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, + {380000, 4, 7, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +static const struct dib0090_tuning dib0090_tuning_table[] = { + +#ifdef CONFIG_BAND_CBAND + {170000, 4, 1, 15, 0x280, 0x2912, 0xb94e, EN_CAB}, +#endif +#ifdef CONFIG_BAND_VHF + {184000, 1, 1, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {227000, 1, 3, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, + {380000, 1, 7, 15, 0x300, 0x4d12, 0xb94e, EN_VHF}, +#endif +#ifdef CONFIG_BAND_UHF + {520000, 2, 0, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {550000, 2, 2, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {650000, 2, 3, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {750000, 2, 5, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {850000, 2, 6, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, + {900000, 2, 7, 15, 0x300, 0x1d12, 0xb9ce, EN_UHF}, +#endif +#ifdef CONFIG_BAND_LBAND + {1500000, 4, 0, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1600000, 4, 1, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, + {1800000, 4, 3, 20, 0x300, 0x1912, 0x82c9, EN_LBD}, +#endif +#ifdef CONFIG_BAND_SBAND + {2300000, 1, 4, 20, 0x300, 0x2d2A, 0x82c7, EN_SBD}, + {2900000, 1, 7, 20, 0x280, 0x2deb, 0x8347, EN_SBD}, +#endif +}; + +#define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ +static int dib0090_tune(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + const struct dib0090_tuning *tune = state->current_tune_table_index; + const struct dib0090_pll *pll = state->current_pll_table_index; + enum frontend_tune_state *tune_state = &state->tune_state; + + u32 rf; + u16 lo4 = 0xe900, lo5, lo6, Den; + u32 FBDiv, Rest, FREF, VCOF_kHz = 0; + u16 tmp, adc; + int8_t step_sign; + int ret = 10; /* 1ms is the default delay most of the time */ + u8 c, i; + + state->current_band = (u8) BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); + rf = fe->dtv_property_cache.frequency / 1000 + (state->current_band == + BAND_UHF ? state->config->freq_offset_khz_uhf : state->config->freq_offset_khz_vhf); + /* in any case we first need to do a reset if needed */ + if (state->reset & 0x1) + return dib0090_dc_offset_calibration(state, tune_state); + else if (state->reset & 0x2) + return dib0090_wbd_calibration(state, tune_state); + + /************************* VCO ***************************/ + /* Default values for FG */ + /* from these are needed : */ + /* Cp,HFdiv,VCOband,SD,Num,Den,FB and REFDiv */ + +#ifdef CONFIG_SYS_ISDBT + if (state->fe->dtv_property_cache.delivery_system == SYS_ISDBT && state->fe->dtv_property_cache.isdbt_sb_mode == 1) + rf += 850; +#endif + + if (state->current_rf != rf) { + state->tuner_is_tuned = 0; + + tune = dib0090_tuning_table; + + tmp = (state->revision >> 5) & 0x7; + if (tmp == 0x4 || tmp == 0x7) { + /* CBAND tuner version for VHF */ + if (state->current_band == BAND_FM || state->current_band == BAND_VHF) { + /* Force CBAND */ + state->current_band = BAND_CBAND; + tune = dib0090_tuning_table_fm_vhf_on_cband; + } + } + + pll = dib0090_pll_table; + /* Look for the interval */ + while (rf > tune->max_freq) + tune++; + while (rf > pll->max_freq) + pll++; + state->current_tune_table_index = tune; + state->current_pll_table_index = pll; + } + + if (*tune_state == CT_TUNER_START) { + + if (state->tuner_is_tuned == 0) + state->current_rf = 0; + + if (state->current_rf != rf) { + + dib0090_write_reg(state, 0x0b, 0xb800 | (tune->switch_trim)); + + /* external loop filter, otherwise: + * lo5 = (0 << 15) | (0 << 12) | (0 << 11) | (3 << 9) | (4 << 6) | (3 << 4) | 4; + * lo6 = 0x0e34 */ + if (pll->vco_band) + lo5 = 0x049e; + else if (state->config->analog_output) + lo5 = 0x041d; + else + lo5 = 0x041c; + + lo5 |= (pll->hfdiv_code << 11) | (pll->vco_band << 7); /* bit 15 is the split to the slave, we do not do it here */ + + if (!state->config->io.pll_int_loop_filt) + lo6 = 0xff28; + else + lo6 = (state->config->io.pll_int_loop_filt << 3); + + VCOF_kHz = (pll->hfdiv * rf) * 2; + + FREF = state->config->io.clock_khz; + + FBDiv = (VCOF_kHz / pll->topresc / FREF); + Rest = (VCOF_kHz / pll->topresc) - FBDiv * FREF; + + if (Rest < LPF) + Rest = 0; + else if (Rest < 2 * LPF) + Rest = 2 * LPF; + else if (Rest > (FREF - LPF)) { + Rest = 0; + FBDiv += 1; + } else if (Rest > (FREF - 2 * LPF)) + Rest = FREF - 2 * LPF; + Rest = (Rest * 6528) / (FREF / 10); + + Den = 1; + + dprintk(" ***** ******* Rest value = %d", Rest); + + if (Rest > 0) { + if (state->config->analog_output) + lo6 |= (1 << 2) | 2; + else + lo6 |= (1 << 2) | 1; + Den = 255; + } +#ifdef CONFIG_BAND_SBAND + if (state->current_band == BAND_SBAND) + lo6 &= 0xfffb; +#endif + + dib0090_write_reg(state, 0x15, (u16) FBDiv); + + dib0090_write_reg(state, 0x16, (Den << 8) | 1); + + dib0090_write_reg(state, 0x17, (u16) Rest); + + dib0090_write_reg(state, 0x19, lo5); + + dib0090_write_reg(state, 0x1c, lo6); + + lo6 = tune->tuner_enable; + if (state->config->analog_output) + lo6 = (lo6 & 0xff9f) | 0x2; + + dib0090_write_reg(state, 0x24, lo6 | EN_LO +#ifdef CONFIG_DIB0090_USE_PWM_AGC + | state->config->use_pwm_agc * EN_CRYSTAL +#endif + ); + + state->current_rf = rf; + + /* prepare a complete captrim */ + state->step = state->captrim = state->fcaptrim = 64; + + } else { /* we are already tuned to this frequency - the configuration is correct */ + + /* do a minimal captrim even if the frequency has not changed */ + state->step = 4; + state->captrim = state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7f; + } + state->adc_diff = 3000; + + dib0090_write_reg(state, 0x10, 0x2B1); + + dib0090_write_reg(state, 0x1e, 0x0032); + + ret = 20; + *tune_state = CT_TUNER_STEP_1; + } else if (*tune_state == CT_TUNER_STEP_0) { + /* nothing */ + } else if (*tune_state == CT_TUNER_STEP_1) { + state->step /= 2; + dib0090_write_reg(state, 0x18, lo4 | state->captrim); + *tune_state = CT_TUNER_STEP_2; + } else if (*tune_state == CT_TUNER_STEP_2) { + + adc = dib0090_read_reg(state, 0x1d); + dprintk("FE %d CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) fe->id, (u32) state->captrim, (u32) adc, + (u32) (adc) * (u32) 1800 / (u32) 1024); + + if (adc >= 400) { + adc -= 400; + step_sign = -1; + } else { + adc = 400 - adc; + step_sign = 1; + } + + if (adc < state->adc_diff) { + dprintk("FE %d CAPTRIM=%d is closer to target (%d/%d)", (u32) fe->id, (u32) state->captrim, (u32) adc, (u32) state->adc_diff); + state->adc_diff = adc; + state->fcaptrim = state->captrim; + + } + + state->captrim += step_sign * state->step; + if (state->step >= 1) + *tune_state = CT_TUNER_STEP_1; + else + *tune_state = CT_TUNER_STEP_3; + + ret = 15; + } else if (*tune_state == CT_TUNER_STEP_3) { + /*write the final cptrim config */ + dib0090_write_reg(state, 0x18, lo4 | state->fcaptrim); + +#ifdef CONFIG_TUNER_DIB0090_CAPTRIM_MEMORY + state->memory[state->memory_index].cap = state->fcaptrim; +#endif + + *tune_state = CT_TUNER_STEP_4; + } else if (*tune_state == CT_TUNER_STEP_4) { + dib0090_write_reg(state, 0x1e, 0x07ff); + + dprintk("FE %d Final Captrim: %d", (u32) fe->id, (u32) state->fcaptrim); + dprintk("FE %d HFDIV code: %d", (u32) fe->id, (u32) pll->hfdiv_code); + dprintk("FE %d VCO = %d", (u32) fe->id, (u32) pll->vco_band); + dprintk("FE %d VCOF in kHz: %d ((%d*%d) << 1))", (u32) fe->id, (u32) ((pll->hfdiv * rf) * 2), (u32) pll->hfdiv, (u32) rf); + dprintk("FE %d REFDIV: %d, FREF: %d", (u32) fe->id, (u32) 1, (u32) state->config->io.clock_khz); + dprintk("FE %d FBDIV: %d, Rest: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); + dprintk("FE %d Num: %d, Den: %d, SD: %d", (u32) fe->id, (u32) dib0090_read_reg(state, 0x17), + (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); + + c = 4; + i = 3; +#if defined(CONFIG_BAND_LBAND) || defined(CONFIG_BAND_SBAND) + if ((state->current_band == BAND_LBAND) || (state->current_band == BAND_SBAND)) { + c = 2; + i = 2; + } +#endif + dib0090_write_reg(state, 0x10, (c << 13) | (i << 11) | (WBD +#ifdef CONFIG_DIB0090_USE_PWM_AGC + | (state->config->use_pwm_agc << 1) +#endif + )); + dib0090_write_reg(state, 0x09, (tune->lna_tune << 5) | (tune->lna_bias << 0)); + dib0090_write_reg(state, 0x0c, tune->v2i); + dib0090_write_reg(state, 0x0d, tune->mix); + dib0090_write_reg(state, 0x0e, tune->load); + + *tune_state = CT_TUNER_STEP_5; + } else if (*tune_state == CT_TUNER_STEP_5) { + + /* initialize the lt gain register */ + state->rf_lt_def = 0x7c00; + dib0090_write_reg(state, 0x0f, state->rf_lt_def); + + dib0090_set_bandwidth(state); + state->tuner_is_tuned = 1; + *tune_state = CT_TUNER_STOP; + } else + ret = FE_CALLBACK_TIME_NEVER; + return ret; +} + +static int dib0090_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + struct dib0090_state *state = fe->tuner_priv; + + return state->tune_state; +} +EXPORT_SYMBOL(dib0090_get_tune_state); + +int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib0090_state *state = fe->tuner_priv; + + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib0090_set_tune_state); + +static int dib0090_get_frequency(struct dvb_frontend *fe, u32 * frequency) +{ + struct dib0090_state *state = fe->tuner_priv; + + *frequency = 1000 * state->current_rf; + return 0; +} + +static int dib0090_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dib0090_state *state = fe->tuner_priv; + uint32_t ret; + + state->tune_state = CT_TUNER_START; + + do { + ret = dib0090_tune(fe); + if (ret != FE_CALLBACK_TIME_NEVER) + msleep(ret / 10); + else + break; + } while (state->tune_state != CT_TUNER_STOP); + + return 0; +} + +static const struct dvb_tuner_ops dib0090_ops = { + .info = { + .name = "DiBcom DiB0090", + .frequency_min = 45000000, + .frequency_max = 860000000, + .frequency_step = 1000, + }, + .release = dib0090_release, + + .init = dib0090_wakeup, + .sleep = dib0090_sleep, + .set_params = dib0090_set_params, + .get_frequency = dib0090_get_frequency, +}; + +struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config) +{ + struct dib0090_state *st = kzalloc(sizeof(struct dib0090_state), GFP_KERNEL); + if (st == NULL) + return NULL; + + st->config = config; + st->i2c = i2c; + st->fe = fe; + fe->tuner_priv = st; + + if (dib0090_reset(fe) != 0) + goto free_mem; + + printk(KERN_INFO "DiB0090: successfully identified\n"); + memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); + + return fe; + free_mem: + kfree(st); + fe->tuner_priv = NULL; + return NULL; +} +EXPORT_SYMBOL(dib0090_register); + +MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); +MODULE_AUTHOR("Olivier Grenie <olivier.grenie@dibcom.fr>"); +MODULE_DESCRIPTION("Driver for the DiBcom 0090 base-band RF Tuner"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dib0090.h b/drivers/media/dvb/frontends/dib0090.h new file mode 100644 index 000000000000..aa7711e88776 --- /dev/null +++ b/drivers/media/dvb/frontends/dib0090.h @@ -0,0 +1,108 @@ +/* + * Linux-DVB Driver for DiBcom's DiB0090 base-band RF Tuner. + * + * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/) + * + * 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, version 2. + */ +#ifndef DIB0090_H +#define DIB0090_H + +struct dvb_frontend; +struct i2c_adapter; + +#define DEFAULT_DIB0090_I2C_ADDRESS 0x60 + +struct dib0090_io_config { + u32 clock_khz; + + u8 pll_bypass:1; + u8 pll_range:1; + u8 pll_prediv:6; + u8 pll_loopdiv:6; + + u8 adc_clock_ratio; /* valid is 8, 7 ,6 */ + u16 pll_int_loop_filt; +}; + +struct dib0090_config { + struct dib0090_io_config io; + int (*reset) (struct dvb_frontend *, int); + int (*sleep) (struct dvb_frontend *, int); + + /* offset in kHz */ + int freq_offset_khz_uhf; + int freq_offset_khz_vhf; + + int (*get_adc_power) (struct dvb_frontend *); + + u8 clkouttobamse:1; /* activate or deactivate clock output */ + u8 analog_output; + + u8 i2c_address; + /* add drives and other things if necessary */ + u16 wbd_vhf_offset; + u16 wbd_cband_offset; + u8 use_pwm_agc; + u8 clkoutdrive; +}; + +#if defined(CONFIG_DVB_TUNER_DIB0090) || (defined(CONFIG_DVB_TUNER_DIB0090_MODULE) && defined(MODULE)) +extern struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct dib0090_config *config); +extern void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast); +extern void dib0090_pwm_gain_reset(struct dvb_frontend *fe); +extern u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner); +extern int dib0090_gain_control(struct dvb_frontend *fe); +extern enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe); +extern int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt); +#else +static inline struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0090_config *config) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +static inline void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline void dib0090_pwm_gain_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} + +static inline u16 dib0090_get_wbd_offset(struct dvb_frontend *tuner) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return 0; +} + +static inline int dib0090_gain_control(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_DONE; +} + +static inline int dib0090_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +static inline void dib0090_get_current_gain(struct dvb_frontend *fe, u16 * rf, u16 * bb, u16 * rf_gain_limit, u16 * rflt) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +#endif + +#endif diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 898400d331a3..6f6fa29d9ea4 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -28,18 +28,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) -enum frontend_tune_state { - CT_AGC_START = 20, - CT_AGC_STEP_0, - CT_AGC_STEP_1, - CT_AGC_STEP_2, - CT_AGC_STEP_3, - CT_AGC_STEP_4, - CT_AGC_STOP, - - CT_DEMOD_START = 30, -}; - #define FE_STATUS_TUNE_FAILED 0 struct i2c_device { @@ -133,104 +121,104 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) return dib8000_i2c_write16(&state->i2c, reg, val); } -const int16_t coeff_2k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_2k_sb_1seg_dqpsk[8] = { (769 << 5) | 0x0a, (745 << 5) | 0x03, (595 << 5) | 0x0d, (769 << 5) | 0x0a, (920 << 5) | 0x09, (784 << 5) | 0x02, (519 << 5) | 0x0c, (920 << 5) | 0x09 }; -const int16_t coeff_2k_sb_1seg[8] = { +static const int16_t coeff_2k_sb_1seg[8] = { (692 << 5) | 0x0b, (683 << 5) | 0x01, (519 << 5) | 0x09, (692 << 5) | 0x0b, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f, 0 | 0x1f }; -const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_0dqpsk_1dqpsk[8] = { (832 << 5) | 0x10, (912 << 5) | 0x05, (900 << 5) | 0x12, (832 << 5) | 0x10, (-931 << 5) | 0x0f, (912 << 5) | 0x04, (807 << 5) | 0x11, (-931 << 5) | 0x0f }; -const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_0dqpsk[8] = { (622 << 5) | 0x0c, (941 << 5) | 0x04, (796 << 5) | 0x10, (622 << 5) | 0x0c, (982 << 5) | 0x0c, (519 << 5) | 0x02, (572 << 5) | 0x0e, (982 << 5) | 0x0c }; -const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_2k_sb_3seg_1dqpsk[8] = { (699 << 5) | 0x14, (607 << 5) | 0x04, (944 << 5) | 0x13, (699 << 5) | 0x14, (-720 << 5) | 0x0d, (640 << 5) | 0x03, (866 << 5) | 0x12, (-720 << 5) | 0x0d }; -const int16_t coeff_2k_sb_3seg[8] = { +static const int16_t coeff_2k_sb_3seg[8] = { (664 << 5) | 0x0c, (925 << 5) | 0x03, (937 << 5) | 0x10, (664 << 5) | 0x0c, (-610 << 5) | 0x0a, (697 << 5) | 0x01, (836 << 5) | 0x0e, (-610 << 5) | 0x0a }; -const int16_t coeff_4k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_4k_sb_1seg_dqpsk[8] = { (-955 << 5) | 0x0e, (687 << 5) | 0x04, (818 << 5) | 0x10, (-955 << 5) | 0x0e, (-922 << 5) | 0x0d, (750 << 5) | 0x03, (665 << 5) | 0x0f, (-922 << 5) | 0x0d }; -const int16_t coeff_4k_sb_1seg[8] = { +static const int16_t coeff_4k_sb_1seg[8] = { (638 << 5) | 0x0d, (683 << 5) | 0x02, (638 << 5) | 0x0d, (638 << 5) | 0x0d, (-655 << 5) | 0x0a, (517 << 5) | 0x00, (698 << 5) | 0x0d, (-655 << 5) | 0x0a }; -const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_0dqpsk_1dqpsk[8] = { (-707 << 5) | 0x14, (910 << 5) | 0x06, (889 << 5) | 0x16, (-707 << 5) | 0x14, (-958 << 5) | 0x13, (993 << 5) | 0x05, (523 << 5) | 0x14, (-958 << 5) | 0x13 }; -const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_0dqpsk[8] = { (-723 << 5) | 0x13, (910 << 5) | 0x05, (777 << 5) | 0x14, (-723 << 5) | 0x13, (-568 << 5) | 0x0f, (547 << 5) | 0x03, (696 << 5) | 0x12, (-568 << 5) | 0x0f }; -const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_4k_sb_3seg_1dqpsk[8] = { (-940 << 5) | 0x15, (607 << 5) | 0x05, (915 << 5) | 0x16, (-940 << 5) | 0x15, (-848 << 5) | 0x13, (683 << 5) | 0x04, (543 << 5) | 0x14, (-848 << 5) | 0x13 }; -const int16_t coeff_4k_sb_3seg[8] = { +static const int16_t coeff_4k_sb_3seg[8] = { (612 << 5) | 0x12, (910 << 5) | 0x04, (864 << 5) | 0x14, (612 << 5) | 0x12, (-869 << 5) | 0x13, (683 << 5) | 0x02, (869 << 5) | 0x12, (-869 << 5) | 0x13 }; -const int16_t coeff_8k_sb_1seg_dqpsk[8] = { +static const int16_t coeff_8k_sb_1seg_dqpsk[8] = { (-835 << 5) | 0x12, (684 << 5) | 0x05, (735 << 5) | 0x14, (-835 << 5) | 0x12, (-598 << 5) | 0x10, (781 << 5) | 0x04, (739 << 5) | 0x13, (-598 << 5) | 0x10 }; -const int16_t coeff_8k_sb_1seg[8] = { +static const int16_t coeff_8k_sb_1seg[8] = { (673 << 5) | 0x0f, (683 << 5) | 0x03, (808 << 5) | 0x12, (673 << 5) | 0x0f, (585 << 5) | 0x0f, (512 << 5) | 0x01, (780 << 5) | 0x0f, (585 << 5) | 0x0f }; -const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_0dqpsk_1dqpsk[8] = { (863 << 5) | 0x17, (930 << 5) | 0x07, (878 << 5) | 0x19, (863 << 5) | 0x17, (0 << 5) | 0x14, (521 << 5) | 0x05, (980 << 5) | 0x18, (0 << 5) | 0x14 }; -const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_0dqpsk[8] = { (-924 << 5) | 0x17, (910 << 5) | 0x06, (774 << 5) | 0x17, (-924 << 5) | 0x17, (-877 << 5) | 0x15, (565 << 5) | 0x04, (553 << 5) | 0x15, (-877 << 5) | 0x15 }; -const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { +static const int16_t coeff_8k_sb_3seg_1dqpsk[8] = { (-921 << 5) | 0x19, (607 << 5) | 0x06, (881 << 5) | 0x19, (-921 << 5) | 0x19, (-921 << 5) | 0x14, (713 << 5) | 0x05, (1018 << 5) | 0x18, (-921 << 5) | 0x14 }; -const int16_t coeff_8k_sb_3seg[8] = { +static const int16_t coeff_8k_sb_3seg[8] = { (514 << 5) | 0x14, (910 << 5) | 0x05, (861 << 5) | 0x17, (514 << 5) | 0x14, (690 << 5) | 0x14, (683 << 5) | 0x03, (662 << 5) | 0x15, (690 << 5) | 0x14 }; -const int16_t ana_fe_coeff_3seg[24] = { +static const int16_t ana_fe_coeff_3seg[24] = { 81, 80, 78, 74, 68, 61, 54, 45, 37, 28, 19, 11, 4, 1022, 1017, 1013, 1010, 1008, 1008, 1008, 1008, 1010, 1014, 1017 }; -const int16_t ana_fe_coeff_1seg[24] = { +static const int16_t ana_fe_coeff_1seg[24] = { 249, 226, 164, 82, 5, 981, 970, 988, 1018, 20, 31, 26, 8, 1012, 1000, 1018, 1012, 8, 15, 14, 9, 3, 1017, 1003 }; -const int16_t ana_fe_coeff_13seg[24] = { +static const int16_t ana_fe_coeff_13seg[24] = { 396, 305, 105, -51, -77, -12, 41, 31, -11, -30, -11, 14, 15, -2, -13, -7, 5, 8, 1, -6, -7, -3, 0, 1 }; @@ -852,6 +840,14 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) return 0; } +void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + dib8000_set_adc_state(state, DIBX000_ADC_ON); + dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000))); +} +EXPORT_SYMBOL(dib8000_pwm_agc_reset); + static int dib8000_agc_soft_split(struct dib8000_state *state) { u16 agc, split_offset; @@ -939,6 +935,32 @@ static int dib8000_agc_startup(struct dvb_frontend *fe) } +static const int32_t lut_1000ln_mant[] = +{ + 908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600 +}; + +int32_t dib8000_get_adc_power(struct dvb_frontend *fe, uint8_t mode) +{ + struct dib8000_state *state = fe->demodulator_priv; + uint32_t ix = 0, tmp_val = 0, exp = 0, mant = 0; + int32_t val; + + val = dib8000_read32(state, 384); + /* mode = 1 : ln_agcpower calc using mant-exp conversion and mantis look up table */ + if (mode) { + tmp_val = val; + while (tmp_val >>= 1) + exp++; + mant = (val * 1000 / (1<<exp)); + ix = (uint8_t)((mant-1000)/100); /* index of the LUT */ + val = (lut_1000ln_mant[ix] + 693*(exp-20) - 6908); /* 1000 * ln(adcpower_real) ; 693 = 1000ln(2) ; 6908 = 1000*ln(1000) ; 20 comes from adc_real = adc_pow_int / 2**20 */ + val = (val*256)/1000; + } + return val; +} +EXPORT_SYMBOL(dib8000_get_adc_power); + static void dib8000_update_timf(struct dib8000_state *state) { u32 timf = state->timf = dib8000_read32(state, 435); @@ -1401,10 +1423,9 @@ static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosear } break; } - } - if (state->fe.dtv_property_cache.isdbt_sb_mode == 1) for (i = 0; i < 8; i++) dib8000_write_word(state, 343 + i, ncoeff[i]); + } // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 dib8000_write_word(state, 351, @@ -1854,6 +1875,24 @@ static int dib8000_sleep(struct dvb_frontend *fe) } } +enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + return state->tune_state; +} +EXPORT_SYMBOL(dib8000_get_tune_state); + +int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib8000_state *state = fe->demodulator_priv; + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib8000_set_tune_state); + + + + static int dib8000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dib8000_state *state = fe->demodulator_priv; @@ -2043,29 +2082,31 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) *stat = 0; - if ((lock >> 14) & 1) // AGC + if ((lock >> 13) & 1) *stat |= FE_HAS_SIGNAL; - if ((lock >> 8) & 1) // Equal + if ((lock >> 8) & 1) /* Equal */ *stat |= FE_HAS_CARRIER; - if ((lock >> 3) & 1) // TMCC_SYNC + if (((lock >> 1) & 0xf) == 0xf) /* TMCC_SYNC */ *stat |= FE_HAS_SYNC; - if ((lock >> 5) & 7) // FEC MPEG + if (((lock >> 12) & 1) && ((lock >> 5) & 7)) /* FEC MPEG */ *stat |= FE_HAS_LOCK; - lock = dib8000_read_word(state, 554); // Viterbi Layer A - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + if ((lock >> 12) & 1) { + lock = dib8000_read_word(state, 554); /* Viterbi Layer A */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; - lock = dib8000_read_word(state, 555); // Viterbi Layer B - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + lock = dib8000_read_word(state, 555); /* Viterbi Layer B */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; - lock = dib8000_read_word(state, 556); // Viterbi Layer C - if (lock & 0x01) - *stat |= FE_HAS_VITERBI; + lock = dib8000_read_word(state, 556); /* Viterbi Layer C */ + if (lock & 0x01) + *stat |= FE_HAS_VITERBI; + } return 0; } diff --git a/drivers/media/dvb/frontends/dib8000.h b/drivers/media/dvb/frontends/dib8000.h index 8c89482b738a..b1ee20799639 100644 --- a/drivers/media/dvb/frontends/dib8000.h +++ b/drivers/media/dvb/frontends/dib8000.h @@ -46,6 +46,10 @@ extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value); extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff); extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff); +extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state); +extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe); +extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe); +extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode); #else static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg) { @@ -59,35 +63,53 @@ static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe return NULL; } -int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) +static inline int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) +static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) +static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } -int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) +static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } +static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return CT_SHUTDOWN; +} +static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} +static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); +} #endif #endif diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index 4efca30d2127..e6f3d73db9d3 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -6,7 +6,7 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0) +#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { @@ -25,7 +25,7 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) { if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { - dprintk("selecting interface: %d\n", intf); + dprintk("selecting interface: %d", intf); mst->selected_interface = intf; return dibx000_write_word(mst, mst->base_reg + 4, intf); } @@ -171,9 +171,18 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) { i2c_del_adapter(&mst->gated_tuner_i2c_adap); } - EXPORT_SYMBOL(dibx000_exit_i2c_master); + +u32 systime() +{ + struct timespec t; + + t = current_kernel_time(); + return (t.tv_sec * 10000) + (t.tv_nsec / 100000); +} +EXPORT_SYMBOL(systime); + MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>"); MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index 5be10eca07c0..4f5d141a308d 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -36,13 +36,17 @@ extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); +extern u32 systime(void); + #define BAND_LBAND 0x01 #define BAND_UHF 0x02 #define BAND_VHF 0x04 #define BAND_SBAND 0x08 -#define BAND_FM 0x10 +#define BAND_FM 0x10 +#define BAND_CBAND 0x20 -#define BAND_OF_FREQUENCY(freq_kHz) ( (freq_kHz) <= 115000 ? BAND_FM : \ +#define BAND_OF_FREQUENCY(freq_kHz) ((freq_kHz) <= 170000 ? BAND_CBAND : \ + (freq_kHz) <= 115000 ? BAND_FM : \ (freq_kHz) <= 250000 ? BAND_VHF : \ (freq_kHz) <= 863000 ? BAND_UHF : \ (freq_kHz) <= 2000000 ? BAND_LBAND : BAND_SBAND ) @@ -149,4 +153,67 @@ enum dibx000_adc_states { #define OUTMODE_MPEG2_FIFO 5 #define OUTMODE_ANALOG_ADC 6 +enum frontend_tune_state { + CT_TUNER_START = 10, + CT_TUNER_STEP_0, + CT_TUNER_STEP_1, + CT_TUNER_STEP_2, + CT_TUNER_STEP_3, + CT_TUNER_STEP_4, + CT_TUNER_STEP_5, + CT_TUNER_STEP_6, + CT_TUNER_STEP_7, + CT_TUNER_STOP, + + CT_AGC_START = 20, + CT_AGC_STEP_0, + CT_AGC_STEP_1, + CT_AGC_STEP_2, + CT_AGC_STEP_3, + CT_AGC_STEP_4, + CT_AGC_STOP, + + CT_DEMOD_START = 30, + CT_DEMOD_STEP_1, + CT_DEMOD_STEP_2, + CT_DEMOD_STEP_3, + CT_DEMOD_STEP_4, + CT_DEMOD_STEP_5, + CT_DEMOD_STEP_6, + CT_DEMOD_STEP_7, + CT_DEMOD_STEP_8, + CT_DEMOD_STEP_9, + CT_DEMOD_STEP_10, + CT_DEMOD_SEARCH_NEXT = 41, + CT_DEMOD_STEP_LOCKED, + CT_DEMOD_STOP, + + CT_DONE = 100, + CT_SHUTDOWN, + +}; + +struct dvb_frontend_parametersContext { +#define CHANNEL_STATUS_PARAMETERS_UNKNOWN 0x01 +#define CHANNEL_STATUS_PARAMETERS_SET 0x02 + u8 status; + u32 tune_time_estimation[2]; + s32 tps_available; + u16 tps[9]; +}; + +#define FE_STATUS_TUNE_FAILED 0 +#define FE_STATUS_TUNE_TIMED_OUT -1 +#define FE_STATUS_TUNE_TIME_TOO_SHORT -2 +#define FE_STATUS_TUNE_PENDING -3 +#define FE_STATUS_STD_SUCCESS -4 +#define FE_STATUS_FFT_SUCCESS -5 +#define FE_STATUS_DEMOD_SUCCESS -6 +#define FE_STATUS_LOCKED -7 +#define FE_STATUS_DATA_LOCKED -8 + +#define FE_CALLBACK_TIME_NEVER 0xffffffff + +#define ABS(x) ((x < 0) ? (-x) : (x)) + #endif diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h index 4fa6e52d1fe8..9cb11c9cae53 100644 --- a/drivers/media/dvb/frontends/lgdt3305.h +++ b/drivers/media/dvb/frontends/lgdt3305.h @@ -54,13 +54,13 @@ struct lgdt3305_config { u16 usref_qam256; /* default: 0x2a80 */ /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ - int deny_i2c_rptr:1; + unsigned int deny_i2c_rptr:1; /* spectral inversion - 0:disabled 1:enabled */ - int spectral_inversion:1; + unsigned int spectral_inversion:1; /* use RF AGC loop - 0:disabled 1:enabled */ - int rf_agc_loop:1; + unsigned int rf_agc_loop:1; enum lgdt3305_mpeg_mode mpeg_mode; enum lgdt3305_tp_clock_edge tpclk_edge; diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c index eabcadc425d5..dee53960e7e8 100644 --- a/drivers/media/dvb/frontends/lgs8gxx.c +++ b/drivers/media/dvb/frontends/lgs8gxx.c @@ -199,7 +199,7 @@ static int lgs8gxx_set_if_freq(struct lgs8gxx_state *priv, u32 freq /*in kHz*/) val = freq; if (freq != 0) { - val *= (u64)1 << 32; + val <<= 32; if (if_clk != 0) do_div(val, if_clk); v32 = val & 0xFFFFFFFF; @@ -246,7 +246,7 @@ static int lgs8gxx_get_afc_phase(struct lgs8gxx_state *priv) val = v32; val *= priv->config->if_clk_freq; - val /= (u64)1 << 32; + val >>= 32; dprintk("AFC = %u kHz\n", (u32)val); return 0; } diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c index 71f607fe8fc7..b181bf023ada 100644 --- a/drivers/media/dvb/frontends/lnbp21.c +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -1,7 +1,7 @@ /* * lnbp21.c - driver for lnb supply and control ic lnbp21 * - * Copyright (C) 2006 Oliver Endriss + * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de> * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> * * This program is free software; you can redistribute it and/or @@ -91,6 +91,31 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; } +static int lnbp21_set_tone(struct dvb_frontend *fe, + fe_sec_tone_mode_t tone) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv; + struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + switch (tone) { + case SEC_TONE_OFF: + lnbp21->config &= ~LNBP21_TEN; + break; + case SEC_TONE_ON: + lnbp21->config |= LNBP21_TEN; + break; + default: + return -EINVAL; + }; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + static void lnbp21_release(struct dvb_frontend *fe) { /* LNBP power off */ @@ -133,6 +158,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe, /* override frontend ops */ fe->ops.set_voltage = lnbp21_set_voltage; fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + fe->ops.set_tone = lnbp21_set_tone; printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr); return fe; diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c new file mode 100644 index 000000000000..d05f7500e0c5 --- /dev/null +++ b/drivers/media/dvb/frontends/mb86a16.c @@ -0,0 +1,1878 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver 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. + + 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. +*/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> + +#include "dvb_frontend.h" +#include "mb86a16.h" +#include "mb86a16_priv.h" + +unsigned int verbose = 5; +module_param(verbose, int, 0644); + +#define ABS(x) ((x) < 0 ? (-x) : (x)) + +struct mb86a16_state { + struct i2c_adapter *i2c_adap; + const struct mb86a16_config *config; + struct dvb_frontend frontend; + + /* tuning parameters */ + int frequency; + int srate; + + /* Internal stuff */ + int master_clk; + int deci; + int csel; + int rsel; +}; + +#define MB86A16_ERROR 0 +#define MB86A16_NOTICE 1 +#define MB86A16_INFO 2 +#define MB86A16_DEBUG 3 + +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > MB86A16_ERROR) && (x > y)) \ + printk(KERN_ERR "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_INFO) && (x > y)) \ + printk(KERN_INFO "%s: " format "\n", __func__, ##arg); \ + else if ((x > MB86A16_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "%s: " format "\n", __func__, ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ +} while (0) + +#define TRACE_IN dprintk(verbose, MB86A16_DEBUG, 1, "-->()") +#define TRACE_OUT dprintk(verbose, MB86A16_DEBUG, 1, "()-->") + +static int mb86a16_write(struct mb86a16_state *state, u8 reg, u8 val) +{ + int ret; + u8 buf[] = { reg, val }; + + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + dprintk(verbose, MB86A16_DEBUG, 1, + "writing to [0x%02x],Reg[0x%02x],Data[0x%02x]", + state->config->demod_address, buf[0], buf[1]); + + ret = i2c_transfer(state->i2c_adap, &msg, 1); + + return (ret != 1) ? -EREMOTEIO : 0; +} + +static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) +{ + int ret; + u8 b0[] = { reg }; + u8 b1[] = { 0 }; + + struct i2c_msg msg[] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + ret = i2c_transfer(state->i2c_adap, msg, 2); + if (ret != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)", + reg, ret); + + return -EREMOTEIO; + } + *val = b1[0]; + + return ret; +} + +static int CNTM_set(struct mb86a16_state *state, + unsigned char timint1, + unsigned char timint2, + unsigned char cnext) +{ + unsigned char val; + + val = (timint1 << 4) | (timint2 << 2) | cnext; + if (mb86a16_write(state, MB86A16_CNTMR, val) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int smrt_set(struct mb86a16_state *state, int rate) +{ + int tmp ; + int m ; + unsigned char STOFS0, STOFS1; + + m = 1 << state->deci; + tmp = (8192 * state->master_clk - 2 * m * rate * 8192 + state->master_clk / 2) / state->master_clk; + + STOFS0 = tmp & 0x0ff; + STOFS1 = (tmp & 0xf00) >> 8; + + if (mb86a16_write(state, MB86A16_SRATE1, (state->deci << 2) | + (state->csel << 1) | + state->rsel) < 0) + goto err; + if (mb86a16_write(state, MB86A16_SRATE2, STOFS0) < 0) + goto err; + if (mb86a16_write(state, MB86A16_SRATE3, STOFS1) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -1; +} + +static int srst(struct mb86a16_state *state) +{ + if (mb86a16_write(state, MB86A16_RESET, 0x04) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + +} + +static int afcex_data_set(struct mb86a16_state *state, + unsigned char AFCEX_L, + unsigned char AFCEX_H) +{ + if (mb86a16_write(state, MB86A16_AFCEXL, AFCEX_L) < 0) + goto err; + if (mb86a16_write(state, MB86A16_AFCEXH, AFCEX_H) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + + return -1; +} + +static int afcofs_data_set(struct mb86a16_state *state, + unsigned char AFCEX_L, + unsigned char AFCEX_H) +{ + if (mb86a16_write(state, 0x58, AFCEX_L) < 0) + goto err; + if (mb86a16_write(state, 0x59, AFCEX_H) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int stlp_set(struct mb86a16_state *state, + unsigned char STRAS, + unsigned char STRBS) +{ + if (mb86a16_write(state, MB86A16_STRFILTCOEF1, (STRBS << 3) | (STRAS)) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int Vi_set(struct mb86a16_state *state, unsigned char ETH, unsigned char VIA) +{ + if (mb86a16_write(state, MB86A16_VISET2, 0x04) < 0) + goto err; + if (mb86a16_write(state, MB86A16_VISET3, 0xf5) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int initial_set(struct mb86a16_state *state) +{ + if (stlp_set(state, 5, 7)) + goto err; + + udelay(100); + if (afcex_data_set(state, 0, 0)) + goto err; + + udelay(100); + if (afcofs_data_set(state, 0, 0)) + goto err; + + udelay(100); + if (mb86a16_write(state, MB86A16_CRLFILTCOEF1, 0x16) < 0) + goto err; + if (mb86a16_write(state, 0x2f, 0x21) < 0) + goto err; + if (mb86a16_write(state, MB86A16_VIMAG, 0x38) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS1, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS2, 0x1c) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS3, 0x20) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS4, 0x1e) < 0) + goto err; + if (mb86a16_write(state, MB86A16_FAGCS5, 0x23) < 0) + goto err; + if (mb86a16_write(state, 0x54, 0xff) < 0) + goto err; + if (mb86a16_write(state, MB86A16_TSOUT, 0x00) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int S01T_set(struct mb86a16_state *state, + unsigned char s1t, + unsigned s0t) +{ + if (mb86a16_write(state, 0x33, (s1t << 3) | s0t) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + + +static int EN_set(struct mb86a16_state *state, + int cren, + int afcen) +{ + unsigned char val; + + val = 0x7a | (cren << 7) | (afcen << 2); + if (mb86a16_write(state, 0x49, val) < 0) + goto err; + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int AFCEXEN_set(struct mb86a16_state *state, + int afcexen, + int smrt) +{ + unsigned char AFCA ; + + if (smrt > 18875) + AFCA = 4; + else if (smrt > 9375) + AFCA = 3; + else if (smrt > 2250) + AFCA = 2; + else + AFCA = 1; + + if (mb86a16_write(state, 0x2a, 0x02 | (afcexen << 5) | (AFCA << 2)) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int DAGC_data_set(struct mb86a16_state *state, + unsigned char DAGCA, + unsigned char DAGCW) +{ + if (mb86a16_write(state, 0x2d, (DAGCA << 3) | DAGCW) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static void smrt_info_get(struct mb86a16_state *state, int rate) +{ + if (rate >= 37501) { + state->deci = 0; state->csel = 0; state->rsel = 0; + } else if (rate >= 30001) { + state->deci = 0; state->csel = 0; state->rsel = 1; + } else if (rate >= 26251) { + state->deci = 0; state->csel = 1; state->rsel = 0; + } else if (rate >= 22501) { + state->deci = 0; state->csel = 1; state->rsel = 1; + } else if (rate >= 18751) { + state->deci = 1; state->csel = 0; state->rsel = 0; + } else if (rate >= 15001) { + state->deci = 1; state->csel = 0; state->rsel = 1; + } else if (rate >= 13126) { + state->deci = 1; state->csel = 1; state->rsel = 0; + } else if (rate >= 11251) { + state->deci = 1; state->csel = 1; state->rsel = 1; + } else if (rate >= 9376) { + state->deci = 2; state->csel = 0; state->rsel = 0; + } else if (rate >= 7501) { + state->deci = 2; state->csel = 0; state->rsel = 1; + } else if (rate >= 6563) { + state->deci = 2; state->csel = 1; state->rsel = 0; + } else if (rate >= 5626) { + state->deci = 2; state->csel = 1; state->rsel = 1; + } else if (rate >= 4688) { + state->deci = 3; state->csel = 0; state->rsel = 0; + } else if (rate >= 3751) { + state->deci = 3; state->csel = 0; state->rsel = 1; + } else if (rate >= 3282) { + state->deci = 3; state->csel = 1; state->rsel = 0; + } else if (rate >= 2814) { + state->deci = 3; state->csel = 1; state->rsel = 1; + } else if (rate >= 2344) { + state->deci = 4; state->csel = 0; state->rsel = 0; + } else if (rate >= 1876) { + state->deci = 4; state->csel = 0; state->rsel = 1; + } else if (rate >= 1641) { + state->deci = 4; state->csel = 1; state->rsel = 0; + } else if (rate >= 1407) { + state->deci = 4; state->csel = 1; state->rsel = 1; + } else if (rate >= 1172) { + state->deci = 5; state->csel = 0; state->rsel = 0; + } else if (rate >= 939) { + state->deci = 5; state->csel = 0; state->rsel = 1; + } else if (rate >= 821) { + state->deci = 5; state->csel = 1; state->rsel = 0; + } else { + state->deci = 5; state->csel = 1; state->rsel = 1; + } + + if (state->csel == 0) + state->master_clk = 92000; + else + state->master_clk = 61333; + +} + +static int signal_det(struct mb86a16_state *state, + int smrt, + unsigned char *SIG) +{ + + int ret ; + int smrtd ; + int wait_sym ; + + u32 wait_t; + unsigned char S[3] ; + int i ; + + if (*SIG > 45) { + if (CNTM_set(state, 2, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + wait_sym = 40000; + } else { + if (CNTM_set(state, 3, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + wait_sym = 80000; + } + for (i = 0; i < 3; i++) { + if (i == 0) + smrtd = smrt * 98 / 100; + else if (i == 1) + smrtd = smrt; + else + smrtd = smrt * 102 / 100; + smrt_info_get(state, smrtd); + smrt_set(state, smrtd); + srst(state); + wait_t = (wait_sym + 99 * smrtd / 100) / smrtd; + if (wait_t == 0) + wait_t = 1; + msleep_interruptible(10); + if (mb86a16_read(state, 0x37, &(S[i])) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + } + if ((S[1] > S[0] * 112 / 100) && + (S[1] > S[2] * 112 / 100)) { + + ret = 1; + } else { + ret = 0; + } + *SIG = S[1]; + + if (CNTM_set(state, 0, 1, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set Error"); + return -1; + } + + return ret; +} + +static int rf_val_set(struct mb86a16_state *state, + int f, + int smrt, + unsigned char R) +{ + unsigned char C, F, B; + int M; + unsigned char rf_val[5]; + int ack = -1; + + if (smrt > 37750) + C = 1; + else if (smrt > 18875) + C = 2; + else if (smrt > 5500) + C = 3; + else + C = 4; + + if (smrt > 30500) + F = 3; + else if (smrt > 9375) + F = 1; + else if (smrt > 4625) + F = 0; + else + F = 2; + + if (f < 1060) + B = 0; + else if (f < 1175) + B = 1; + else if (f < 1305) + B = 2; + else if (f < 1435) + B = 3; + else if (f < 1570) + B = 4; + else if (f < 1715) + B = 5; + else if (f < 1845) + B = 6; + else if (f < 1980) + B = 7; + else if (f < 2080) + B = 8; + else + B = 9; + + M = f * (1 << R) / 2; + + rf_val[0] = 0x01 | (C << 3) | (F << 1); + rf_val[1] = (R << 5) | ((M & 0x1f000) >> 12); + rf_val[2] = (M & 0x00ff0) >> 4; + rf_val[3] = ((M & 0x0000f) << 4) | B; + + /* Frequency Set */ + if (mb86a16_write(state, 0x21, rf_val[0]) < 0) + ack = 0; + if (mb86a16_write(state, 0x22, rf_val[1]) < 0) + ack = 0; + if (mb86a16_write(state, 0x23, rf_val[2]) < 0) + ack = 0; + if (mb86a16_write(state, 0x24, rf_val[3]) < 0) + ack = 0; + if (mb86a16_write(state, 0x25, 0x01) < 0) + ack = 0; + if (ack == 0) { + dprintk(verbose, MB86A16_ERROR, 1, "RF Setup - I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int afcerr_chk(struct mb86a16_state *state) +{ + unsigned char AFCM_L, AFCM_H ; + int AFCM ; + int afcm, afcerr ; + + if (mb86a16_read(state, 0x0e, &AFCM_L) != 2) + goto err; + if (mb86a16_read(state, 0x0f, &AFCM_H) != 2) + goto err; + + AFCM = (AFCM_H << 8) + AFCM_L; + + if (AFCM > 2048) + afcm = AFCM - 4096; + else + afcm = AFCM; + afcerr = afcm * state->master_clk / 8192; + + return afcerr; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int dagcm_val_get(struct mb86a16_state *state) +{ + int DAGCM; + unsigned char DAGCM_H, DAGCM_L; + + if (mb86a16_read(state, 0x45, &DAGCM_L) != 2) + goto err; + if (mb86a16_read(state, 0x46, &DAGCM_H) != 2) + goto err; + + DAGCM = (DAGCM_H << 8) + DAGCM_L; + + return DAGCM; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + u8 stat, stat2; + struct mb86a16_state *state = fe->demodulator_priv; + + *status = 0; + + if (mb86a16_read(state, MB86A16_SIG1, &stat) != 2) + goto err; + if (mb86a16_read(state, MB86A16_SIG2, &stat2) != 2) + goto err; + if ((stat > 25) && (stat2 > 25)) + *status |= FE_HAS_SIGNAL; + if ((stat > 45) && (stat2 > 45)) + *status |= FE_HAS_CARRIER; + + if (mb86a16_read(state, MB86A16_STATUS, &stat) != 2) + goto err; + + if (stat & 0x01) + *status |= FE_HAS_SYNC; + if (stat & 0x01) + *status |= FE_HAS_VITERBI; + + if (mb86a16_read(state, MB86A16_FRAMESYNC, &stat) != 2) + goto err; + + if ((stat & 0x0f) && (*status & FE_HAS_VITERBI)) + *status |= FE_HAS_LOCK; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int sync_chk(struct mb86a16_state *state, + unsigned char *VIRM) +{ + unsigned char val; + int sync; + + if (mb86a16_read(state, 0x0d, &val) != 2) + goto err; + + dprintk(verbose, MB86A16_INFO, 1, "Status = %02x,", val); + sync = val & 0x01; + *VIRM = (val & 0x1c) >> 2; + + return sync; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + +} + +static int freqerr_chk(struct mb86a16_state *state, + int fTP, + int smrt, + int unit) +{ + unsigned char CRM, AFCML, AFCMH; + unsigned char temp1, temp2, temp3; + int crm, afcm, AFCM; + int crrerr, afcerr; /* kHz */ + int frqerr; /* MHz */ + int afcen, afcexen = 0; + int R, M, fOSC, fOSC_OFS; + + if (mb86a16_read(state, 0x43, &CRM) != 2) + goto err; + + if (CRM > 127) + crm = CRM - 256; + else + crm = CRM; + + crrerr = smrt * crm / 256; + if (mb86a16_read(state, 0x49, &temp1) != 2) + goto err; + + afcen = (temp1 & 0x04) >> 2; + if (afcen == 0) { + if (mb86a16_read(state, 0x2a, &temp1) != 2) + goto err; + afcexen = (temp1 & 0x20) >> 5; + } + + if (afcen == 1) { + if (mb86a16_read(state, 0x0e, &AFCML) != 2) + goto err; + if (mb86a16_read(state, 0x0f, &AFCMH) != 2) + goto err; + } else if (afcexen == 1) { + if (mb86a16_read(state, 0x2b, &AFCML) != 2) + goto err; + if (mb86a16_read(state, 0x2c, &AFCMH) != 2) + goto err; + } + if ((afcen == 1) || (afcexen == 1)) { + smrt_info_get(state, smrt); + AFCM = ((AFCMH & 0x01) << 8) + AFCML; + if (AFCM > 255) + afcm = AFCM - 512; + else + afcm = AFCM; + + afcerr = afcm * state->master_clk / 8192; + } else + afcerr = 0; + + if (mb86a16_read(state, 0x22, &temp1) != 2) + goto err; + if (mb86a16_read(state, 0x23, &temp2) != 2) + goto err; + if (mb86a16_read(state, 0x24, &temp3) != 2) + goto err; + + R = (temp1 & 0xe0) >> 5; + M = ((temp1 & 0x1f) << 12) + (temp2 << 4) + (temp3 >> 4); + if (R == 0) + fOSC = 2 * M; + else + fOSC = M; + + fOSC_OFS = fOSC - fTP; + + if (unit == 0) { /* MHz */ + if (crrerr + afcerr + fOSC_OFS * 1000 >= 0) + frqerr = (crrerr + afcerr + fOSC_OFS * 1000 + 500) / 1000; + else + frqerr = (crrerr + afcerr + fOSC_OFS * 1000 - 500) / 1000; + } else { /* kHz */ + frqerr = crrerr + afcerr + fOSC_OFS * 1000; + } + + return frqerr; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static unsigned char vco_dev_get(struct mb86a16_state *state, int smrt) +{ + unsigned char R; + + if (smrt > 9375) + R = 0; + else + R = 1; + + return R; +} + +static void swp_info_get(struct mb86a16_state *state, + int fOSC_start, + int smrt, + int v, int R, + int swp_ofs, + int *fOSC, + int *afcex_freq, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + int crnt_swp_freq ; + + crnt_swp_freq = fOSC_start * 1000 + v * swp_ofs; + + if (R == 0) + *fOSC = (crnt_swp_freq + 1000) / 2000 * 2; + else + *fOSC = (crnt_swp_freq + 500) / 1000; + + if (*fOSC >= crnt_swp_freq) + *afcex_freq = *fOSC * 1000 - crnt_swp_freq; + else + *afcex_freq = crnt_swp_freq - *fOSC * 1000; + + AFCEX = *afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + + +static int swp_freq_calcuation(struct mb86a16_state *state, int i, int v, int *V, int vmax, int vmin, + int SIGMIN, int fOSC, int afcex_freq, int swp_ofs, unsigned char *SIG1) +{ + int swp_freq ; + + if ((i % 2 == 1) && (v <= vmax)) { + /* positive v (case 1) */ + if ((v - 1 == vmin) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v - 1) > *(V + 30 + v)) && + (*(V + 30 + v - 1) > SIGMIN)) { + + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } else if ((v == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v) > *(V + 30 + v - 1)) && + (*(V + 30 + v) > SIGMIN)) { + /* (case 2) */ + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else if ((*(V + 30 + v) > 0) && + (*(V + 30 + v - 1) > 0) && + (*(V + 30 + v - 2) > 0) && + (*(V + 30 + v - 3) > 0) && + (*(V + 30 + v - 1) > *(V + 30 + v)) && + (*(V + 30 + v - 2) > *(V + 30 + v - 3)) && + ((*(V + 30 + v - 1) > SIGMIN) || + (*(V + 30 + v - 2) > SIGMIN))) { + /* (case 3) */ + if (*(V + 30 + v - 1) >= *(V + 30 + v - 2)) { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs * 2; + *SIG1 = *(V + 30 + v - 2); + } + } else if ((v == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v - 1) >= 0) && + (*(V + 30 + v - 2) >= 0) && + (*(V + 30 + v) > *(V + 30 + v - 2)) && + (*(V + 30 + v - 1) > *(V + 30 + v - 2)) && + ((*(V + 30 + v) > SIGMIN) || + (*(V + 30 + v - 1) > SIGMIN))) { + /* (case 4) */ + if (*(V + 30 + v) >= *(V + 30 + v - 1)) { + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else { + swp_freq = fOSC * 1000 + afcex_freq - swp_ofs; + *SIG1 = *(V + 30 + v - 1); + } + } else { + swp_freq = -1 ; + } + } else if ((i % 2 == 0) && (v >= vmin)) { + /* Negative v (case 1) */ + if ((*(V + 30 + v) > 0) && + (*(V + 30 + v + 1) > 0) && + (*(V + 30 + v + 2) > 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && + (*(V + 30 + v + 1) > SIGMIN)) { + + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else if ((v + 1 == vmax) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 1) > SIGMIN)) { + /* (case 2) */ + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v); + } else if ((v == vmin) && + (*(V + 30 + v) > 0) && + (*(V + 30 + v + 1) > 0) && + (*(V + 30 + v + 2) > 0) && + (*(V + 30 + v) > *(V + 30 + v + 1)) && + (*(V + 30 + v) > *(V + 30 + v + 2)) && + (*(V + 30 + v) > SIGMIN)) { + /* (case 3) */ + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else if ((*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 3) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 2) > *(V + 30 + v + 3)) && + ((*(V + 30 + v + 1) > SIGMIN) || + (*(V + 30 + v + 2) > SIGMIN))) { + /* (case 4) */ + if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; + *SIG1 = *(V + 30 + v + 2); + } + } else if ((*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 3) >= 0) && + (*(V + 30 + v) > *(V + 30 + v + 2)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 2)) && + (*(V + 30 + v) > *(V + 30 + v + 3)) && + (*(V + 30 + v + 1) > *(V + 30 + v + 3)) && + ((*(V + 30 + v) > SIGMIN) || + (*(V + 30 + v + 1) > SIGMIN))) { + /* (case 5) */ + if (*(V + 30 + v) >= *(V + 30 + v + 1)) { + swp_freq = fOSC * 1000 + afcex_freq; + *SIG1 = *(V + 30 + v); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } + } else if ((v + 2 == vmin) && + (*(V + 30 + v) >= 0) && + (*(V + 30 + v + 1) >= 0) && + (*(V + 30 + v + 2) >= 0) && + (*(V + 30 + v + 1) > *(V + 30 + v)) && + (*(V + 30 + v + 2) > *(V + 30 + v)) && + ((*(V + 30 + v + 1) > SIGMIN) || + (*(V + 30 + v + 2) > SIGMIN))) { + /* (case 6) */ + if (*(V + 30 + v + 1) >= *(V + 30 + v + 2)) { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs; + *SIG1 = *(V + 30 + v + 1); + } else { + swp_freq = fOSC * 1000 + afcex_freq + swp_ofs * 2; + *SIG1 = *(V + 30 + v + 2); + } + } else if ((vmax == 0) && (vmin == 0) && (*(V + 30 + v) > SIGMIN)) { + swp_freq = fOSC * 1000; + *SIG1 = *(V + 30 + v); + } else + swp_freq = -1; + } else + swp_freq = -1; + + return swp_freq; +} + +static void swp_info_get2(struct mb86a16_state *state, + int smrt, + int R, + int swp_freq, + int *afcex_freq, + int *fOSC, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + + if (R == 0) + *fOSC = (swp_freq + 1000) / 2000 * 2; + else + *fOSC = (swp_freq + 500) / 1000; + + if (*fOSC >= swp_freq) + *afcex_freq = *fOSC * 1000 - swp_freq; + else + *afcex_freq = swp_freq - *fOSC * 1000; + + AFCEX = *afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + +static void afcex_info_get(struct mb86a16_state *state, + int afcex_freq, + unsigned char *AFCEX_L, + unsigned char *AFCEX_H) +{ + int AFCEX ; + + AFCEX = afcex_freq * 8192 / state->master_clk; + *AFCEX_L = AFCEX & 0x00ff; + *AFCEX_H = (AFCEX & 0x0f00) >> 8; +} + +static int SEQ_set(struct mb86a16_state *state, unsigned char loop) +{ + /* SLOCK0 = 0 */ + if (mb86a16_write(state, 0x32, 0x02 | (loop << 2)) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int iq_vt_set(struct mb86a16_state *state, unsigned char IQINV) +{ + /* Viterbi Rate, IQ Settings */ + if (mb86a16_write(state, 0x06, 0xdf | (IQINV << 5)) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int FEC_srst(struct mb86a16_state *state) +{ + if (mb86a16_write(state, MB86A16_RESET, 0x02) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int S2T_set(struct mb86a16_state *state, unsigned char S2T) +{ + if (mb86a16_write(state, 0x34, 0x70 | S2T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + +static int S45T_set(struct mb86a16_state *state, unsigned char S4T, unsigned char S5T) +{ + if (mb86a16_write(state, 0x35, 0x00 | (S5T << 4) | S4T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + return 0; +} + + +static int mb86a16_set_fe(struct mb86a16_state *state) +{ + u8 agcval, cnmval; + + int i, j; + int fOSC = 0; + int fOSC_start = 0; + int wait_t; + int fcp; + int swp_ofs; + int V[60]; + u8 SIG1MIN; + + unsigned char CREN, AFCEN, AFCEXEN; + unsigned char SIG1; + unsigned char TIMINT1, TIMINT2, TIMEXT; + unsigned char S0T, S1T; + unsigned char S2T; +/* unsigned char S2T, S3T; */ + unsigned char S4T, S5T; + unsigned char AFCEX_L, AFCEX_H; + unsigned char R; + unsigned char VIRM; + unsigned char ETH, VIA; + unsigned char junk; + + int loop; + int ftemp; + int v, vmax, vmin; + int vmax_his, vmin_his; + int swp_freq, prev_swp_freq[20]; + int prev_freq_num; + int signal_dupl; + int afcex_freq; + int signal; + int afcerr; + int temp_freq, delta_freq; + int dagcm[4]; + int smrt_d; +/* int freq_err; */ + int n; + int ret = -1; + int sync; + + dprintk(verbose, MB86A16_INFO, 1, "freq=%d Mhz, symbrt=%d Ksps", state->frequency, state->srate); + + fcp = 3000; + swp_ofs = state->srate / 4; + + for (i = 0; i < 60; i++) + V[i] = -1; + + for (i = 0; i < 20; i++) + prev_swp_freq[i] = 0; + + SIG1MIN = 25; + + for (n = 0; ((n < 3) && (ret == -1)); n++) { + SEQ_set(state, 0); + iq_vt_set(state, 0); + + CREN = 0; + AFCEN = 0; + AFCEXEN = 1; + TIMINT1 = 0; + TIMINT2 = 1; + TIMEXT = 2; + S1T = 0; + S0T = 0; + + if (initial_set(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "initial set failed"); + return -1; + } + if (DAGC_data_set(state, 3, 2) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; /* (0, 0) */ + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; /* (1, smrt) = (1, symbolrate) */ + } + if (CNTM_set(state, TIMINT1, TIMINT2, TIMEXT) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "CNTM set error"); + return -1; /* (0, 1, 2) */ + } + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; /* (0, 0) */ + } + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt info get error"); + return -1; + } + + R = vco_dev_get(state, state->srate); + if (R == 1) + fOSC_start = state->frequency; + + else if (R == 0) { + if (state->frequency % 2 == 0) { + fOSC_start = state->frequency; + } else { + fOSC_start = state->frequency + 1; + if (fOSC_start > 2150) + fOSC_start = state->frequency - 1; + } + } + loop = 1; + ftemp = fOSC_start * 1000; + vmax = 0 ; + while (loop == 1) { + ftemp = ftemp + swp_ofs; + vmax++; + + /* Upper bound */ + if (ftemp > 2150000) { + loop = 0; + vmax--; + } else { + if ((ftemp == 2150000) || + (ftemp - state->frequency * 1000 >= fcp + state->srate / 4)) + loop = 0; + } + } + + loop = 1; + ftemp = fOSC_start * 1000; + vmin = 0 ; + while (loop == 1) { + ftemp = ftemp - swp_ofs; + vmin--; + + /* Lower bound */ + if (ftemp < 950000) { + loop = 0; + vmin++; + } else { + if ((ftemp == 950000) || + (state->frequency * 1000 - ftemp >= fcp + state->srate / 4)) + loop = 0; + } + } + + wait_t = (8000 + state->srate / 2) / state->srate; + if (wait_t == 0) + wait_t = 1; + + i = 0; + j = 0; + prev_freq_num = 0; + loop = 1; + signal = 0; + vmax_his = 0; + vmin_his = 0; + v = 0; + + while (loop == 1) { + swp_info_get(state, fOSC_start, state->srate, + v, R, swp_ofs, &fOSC, + &afcex_freq, &AFCEX_L, &AFCEX_H); + + udelay(100); + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + udelay(100); + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + msleep_interruptible(wait_t); + + if (mb86a16_read(state, 0x37, &SIG1) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -1; + } + V[30 + v] = SIG1 ; + swp_freq = swp_freq_calcuation(state, i, v, V, vmax, vmin, + SIG1MIN, fOSC, afcex_freq, + swp_ofs, &SIG1); /* changed */ + + signal_dupl = 0; + for (j = 0; j < prev_freq_num; j++) { + if ((ABS(prev_swp_freq[j] - swp_freq)) < (swp_ofs * 3 / 2)) { + signal_dupl = 1; + dprintk(verbose, MB86A16_INFO, 1, "Probably Duplicate Signal, j = %d", j); + } + } + if ((signal_dupl == 0) && (swp_freq > 0) && (ABS(swp_freq - state->frequency * 1000) < fcp + state->srate / 6)) { + dprintk(verbose, MB86A16_DEBUG, 1, "------ Signal detect ------ [swp_freq=[%07d, srate=%05d]]", swp_freq, state->srate); + prev_swp_freq[prev_freq_num] = swp_freq; + prev_freq_num++; + swp_info_get2(state, state->srate, R, swp_freq, + &afcex_freq, &fOSC, + &AFCEX_L, &AFCEX_H); + + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + signal = signal_det(state, state->srate, &SIG1); + if (signal == 1) { + dprintk(verbose, MB86A16_ERROR, 1, "***** Signal Found *****"); + loop = 0; + } else { + dprintk(verbose, MB86A16_ERROR, 1, "!!!!! No signal !!!!!, try again..."); + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + } + } + if (v > vmax) + vmax_his = 1 ; + if (v < vmin) + vmin_his = 1 ; + i++; + + if ((i % 2 == 1) && (vmax_his == 1)) + i++; + if ((i % 2 == 0) && (vmin_his == 1)) + i++; + + if (i % 2 == 1) + v = (i + 1) / 2; + else + v = -i / 2; + + if ((vmax_his == 1) && (vmin_his == 1)) + loop = 0 ; + } + + if (signal == 1) { + dprintk(verbose, MB86A16_INFO, 1, " Start Freq Error Check"); + S1T = 7 ; + S0T = 1 ; + CREN = 0 ; + AFCEN = 1 ; + AFCEXEN = 0 ; + + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; + } + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + afcex_info_get(state, afcex_freq, &AFCEX_L, &AFCEX_H); + if (afcofs_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCOFS data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + /* delay 4~200 */ + wait_t = 200000 / state->master_clk + 200000 / state->srate; + msleep(wait_t); + afcerr = afcerr_chk(state); + if (afcerr == -1) + return -1; + + swp_freq = fOSC * 1000 + afcerr ; + AFCEXEN = 1 ; + if (state->srate >= 1500) + smrt_d = state->srate / 3; + else + smrt_d = state->srate / 2; + smrt_info_get(state, smrt_d); + if (smrt_set(state, smrt_d) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, smrt_d) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + R = vco_dev_get(state, smrt_d); + if (DAGC_data_set(state, 2, 0) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + for (i = 0; i < 3; i++) { + temp_freq = swp_freq + (i - 1) * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[i] = dagcm_val_get(state); + } + if ((dagcm[0] > dagcm[1]) && + (dagcm[0] > dagcm[2]) && + (dagcm[0] - dagcm[1] > 2 * (dagcm[2] - dagcm[1]))) { + + temp_freq = swp_freq - 2 * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[3] = dagcm_val_get(state); + if (dagcm[3] > dagcm[1]) + delta_freq = (dagcm[2] - dagcm[0] + dagcm[1] - dagcm[3]) * state->srate / 300; + else + delta_freq = 0; + } else if ((dagcm[2] > dagcm[1]) && + (dagcm[2] > dagcm[0]) && + (dagcm[2] - dagcm[1] > 2 * (dagcm[0] - dagcm[1]))) { + + temp_freq = swp_freq + 2 * state->srate / 8; + swp_info_get2(state, smrt_d, R, temp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, smrt_d, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set"); + return -1; + } + wait_t = 200000 / state->master_clk + 40000 / smrt_d; + msleep(wait_t); + dagcm[3] = dagcm_val_get(state); + if (dagcm[3] > dagcm[1]) + delta_freq = (dagcm[2] - dagcm[0] + dagcm[3] - dagcm[1]) * state->srate / 300; + else + delta_freq = 0 ; + + } else { + delta_freq = 0 ; + } + dprintk(verbose, MB86A16_INFO, 1, "SWEEP Frequency = %d", swp_freq); + swp_freq += delta_freq; + dprintk(verbose, MB86A16_INFO, 1, "Adjusting .., DELTA Freq = %d, SWEEP Freq=%d", delta_freq, swp_freq); + if (ABS(state->frequency * 1000 - swp_freq) > 3800) { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL !"); + } else { + + S1T = 0; + S0T = 3; + CREN = 1; + AFCEN = 0; + AFCEXEN = 1; + + if (S01T_set(state, S1T, S0T) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "S01T set error"); + return -1; + } + if (DAGC_data_set(state, 0, 0) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "DAGC data set error"); + return -1; + } + R = vco_dev_get(state, state->srate); + smrt_info_get(state, state->srate); + if (smrt_set(state, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "smrt set error"); + return -1; + } + if (EN_set(state, CREN, AFCEN) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "EN set error"); + return -1; + } + if (AFCEXEN_set(state, AFCEXEN, state->srate) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "AFCEXEN set error"); + return -1; + } + swp_info_get2(state, state->srate, R, swp_freq, &afcex_freq, &fOSC, &AFCEX_L, &AFCEX_H); + if (rf_val_set(state, fOSC, state->srate, R) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "rf val set error"); + return -1; + } + if (afcex_data_set(state, AFCEX_L, AFCEX_H) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "afcex data set error"); + return -1; + } + if (srst(state) < 0) { + dprintk(verbose, MB86A16_ERROR, 1, "srst error"); + return -1; + } + wait_t = 7 + (10000 + state->srate / 2) / state->srate; + if (wait_t == 0) + wait_t = 1; + msleep_interruptible(wait_t); + if (mb86a16_read(state, 0x37, &SIG1) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + if (SIG1 > 110) { + S2T = 4; S4T = 1; S5T = 6; ETH = 4; VIA = 6; + wait_t = 7 + (917504 + state->srate / 2) / state->srate; + } else if (SIG1 > 105) { + S2T = 4; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1048576 + state->srate / 2) / state->srate; + } else if (SIG1 > 85) { + S2T = 5; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1310720 + state->srate / 2) / state->srate; + } else if (SIG1 > 65) { + S2T = 6; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (1572864 + state->srate / 2) / state->srate; + } else { + S2T = 7; S4T = 2; S5T = 8; ETH = 7; VIA = 2; + wait_t = 7 + (2097152 + state->srate / 2) / state->srate; + } + wait_t *= 2; /* FOS */ + S2T_set(state, S2T); + S45T_set(state, S4T, S5T); + Vi_set(state, ETH, VIA); + srst(state); + msleep_interruptible(wait_t); + sync = sync_chk(state, &VIRM); + dprintk(verbose, MB86A16_INFO, 1, "-------- Viterbi=[%d] SYNC=[%d] ---------", VIRM, sync); + if (VIRM) { + if (VIRM == 4) { + /* 5/6 */ + if (SIG1 > 110) + wait_t = (786432 + state->srate / 2) / state->srate; + else + wait_t = (1572864 + state->srate / 2) / state->srate; + if (state->srate < 5000) + /* FIXME ! , should be a long wait ! */ + msleep_interruptible(wait_t); + else + msleep_interruptible(wait_t); + + if (sync_chk(state, &junk) == 0) { + iq_vt_set(state, 1); + FEC_srst(state); + } + } + /* 1/2, 2/3, 3/4, 7/8 */ + if (SIG1 > 110) + wait_t = (786432 + state->srate / 2) / state->srate; + else + wait_t = (1572864 + state->srate / 2) / state->srate; + msleep_interruptible(wait_t); + SEQ_set(state, 1); + } else { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SYNC"); + SEQ_set(state, 1); + ret = -1; + } + } + } else { + dprintk(verbose, MB86A16_INFO, 1, "NO -- SIGNAL"); + ret = -1; + } + + sync = sync_chk(state, &junk); + if (sync) { + dprintk(verbose, MB86A16_INFO, 1, "******* SYNC *******"); + freqerr_chk(state, state->frequency, state->srate, 1); + ret = 0; + break; + } + } + + mb86a16_read(state, 0x15, &agcval); + mb86a16_read(state, 0x26, &cnmval); + dprintk(verbose, MB86A16_INFO, 1, "AGC = %02x CNM = %02x", agcval, cnmval); + + return ret; +} + +static int mb86a16_send_diseqc_msg(struct dvb_frontend *fe, + struct dvb_diseqc_master_cmd *cmd) +{ + struct mb86a16_state *state = fe->demodulator_priv; + int i; + u8 regs; + + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) + goto err; + + regs = 0x18; + + if (cmd->msg_len > 5 || cmd->msg_len < 4) + return -EINVAL; + + for (i = 0; i < cmd->msg_len; i++) { + if (mb86a16_write(state, regs, cmd->msg[i]) < 0) + goto err; + + regs++; + } + i += 0x90; + + msleep_interruptible(10); + + if (mb86a16_write(state, MB86A16_DCC1, i) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + switch (burst) { + case SEC_MINI_A: + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_TBEN | + MB86A16_DCC1_TBO) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + case SEC_MINI_B: + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_TBEN) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + } + + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + switch (tone) { + case SEC_TONE_ON: + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x00) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA | + MB86A16_DCC1_CTOE) < 0) + + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, MB86A16_DCCOUT_DISEN) < 0) + goto err; + break; + case SEC_TONE_OFF: + if (mb86a16_write(state, MB86A16_TONEOUT2, 0x04) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCC1, MB86A16_DCC1_DISTA) < 0) + goto err; + if (mb86a16_write(state, MB86A16_DCCOUT, 0x00) < 0) + goto err; + break; + default: + return -EINVAL; + } + return 0; + +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static enum dvbfe_search mb86a16_search(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct mb86a16_state *state = fe->demodulator_priv; + + state->frequency = p->frequency / 1000; + state->srate = p->u.qpsk.symbol_rate / 1000; + + if (!mb86a16_set_fe(state)) { + dprintk(verbose, MB86A16_ERROR, 1, "Succesfully acquired LOCK"); + return DVBFE_ALGO_SEARCH_SUCCESS; + } + + dprintk(verbose, MB86A16_ERROR, 1, "Lock acquisition failed!"); + return DVBFE_ALGO_SEARCH_FAILED; +} + +static void mb86a16_release(struct dvb_frontend *fe) +{ + struct mb86a16_state *state = fe->demodulator_priv; + kfree(state); +} + +static int mb86a16_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int mb86a16_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int mb86a16_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + u8 ber_mon, ber_tab, ber_lsb, ber_mid, ber_msb, ber_tim, ber_rst; + u32 timer; + + struct mb86a16_state *state = fe->demodulator_priv; + + *ber = 0; + if (mb86a16_read(state, MB86A16_BERMON, &ber_mon) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERTAB, &ber_tab) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERLSB, &ber_lsb) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERMID, &ber_mid) != 2) + goto err; + if (mb86a16_read(state, MB86A16_BERMSB, &ber_msb) != 2) + goto err; + /* BER monitor invalid when BER_EN = 0 */ + if (ber_mon & 0x04) { + /* coarse, fast calculation */ + *ber = ber_tab & 0x1f; + dprintk(verbose, MB86A16_DEBUG, 1, "BER coarse=[0x%02x]", *ber); + if (ber_mon & 0x01) { + /* + * BER_SEL = 1, The monitored BER is the estimated + * value with a Reed-Solomon decoder error amount at + * the deinterleaver output. + * monitored BER is expressed as a 20 bit output in total + */ + ber_rst = ber_mon >> 3; + *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; + if (ber_rst == 0) + timer = 12500000; + if (ber_rst == 1) + timer = 25000000; + if (ber_rst == 2) + timer = 50000000; + if (ber_rst == 3) + timer = 100000000; + + *ber /= timer; + dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); + } else { + /* + * BER_SEL = 0, The monitored BER is the estimated + * value with a Viterbi decoder error amount at the + * QPSK demodulator output. + * monitored BER is expressed as a 24 bit output in total + */ + ber_tim = ber_mon >> 1; + *ber = (((ber_msb << 8) | ber_mid) << 8) | ber_lsb; + if (ber_tim == 0) + timer = 16; + if (ber_tim == 1) + timer = 24; + + *ber /= 2 ^ timer; + dprintk(verbose, MB86A16_DEBUG, 1, "BER fine=[0x%02x]", *ber); + } + } + return 0; +err: + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; +} + +static int mb86a16_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + u8 agcm = 0; + struct mb86a16_state *state = fe->demodulator_priv; + + *strength = 0; + if (mb86a16_read(state, MB86A16_AGCM, &agcm) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + *strength = ((0xff - agcm) * 100) / 256; + dprintk(verbose, MB86A16_DEBUG, 1, "Signal strength=[%d %%]", (u8) *strength); + *strength = (0xffff - 0xff) + agcm; + + return 0; +} + +struct cnr { + u8 cn_reg; + u8 cn_val; +}; + +static const struct cnr cnr_tab[] = { + { 35, 2 }, + { 40, 3 }, + { 50, 4 }, + { 60, 5 }, + { 70, 6 }, + { 80, 7 }, + { 92, 8 }, + { 103, 9 }, + { 115, 10 }, + { 138, 12 }, + { 162, 15 }, + { 180, 18 }, + { 185, 19 }, + { 189, 20 }, + { 195, 22 }, + { 199, 24 }, + { 201, 25 }, + { 202, 26 }, + { 203, 27 }, + { 205, 28 }, + { 208, 30 } +}; + +static int mb86a16_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct mb86a16_state *state = fe->demodulator_priv; + int i = 0; + int low_tide = 2, high_tide = 30, q_level; + u8 cn; + + *snr = 0; + if (mb86a16_read(state, 0x26, &cn) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + + for (i = 0; i < ARRAY_SIZE(cnr_tab); i++) { + if (cn < cnr_tab[i].cn_reg) { + *snr = cnr_tab[i].cn_val; + break; + } + } + q_level = (*snr * 100) / (high_tide - low_tide); + dprintk(verbose, MB86A16_ERROR, 1, "SNR (Quality) = [%d dB], Level=%d %%", *snr, q_level); + *snr = (0xffff - 0xff) + *snr; + + return 0; +} + +static int mb86a16_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + u8 dist; + struct mb86a16_state *state = fe->demodulator_priv; + + if (mb86a16_read(state, MB86A16_DISTMON, &dist) != 2) { + dprintk(verbose, MB86A16_ERROR, 1, "I2C transfer error"); + return -EREMOTEIO; + } + *ucblocks = dist; + + return 0; +} + +static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_CUSTOM; +} + +static struct dvb_frontend_ops mb86a16_ops = { + .info = { + .name = "Fujitsu MB86A16 DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 3000, + .frequency_tolerance = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | FE_CAN_QPSK | + FE_CAN_FEC_AUTO + }, + .release = mb86a16_release, + + .get_frontend_algo = mb86a16_frontend_algo, + .search = mb86a16_search, + .read_status = mb86a16_read_status, + .init = mb86a16_init, + .sleep = mb86a16_sleep, + .read_status = mb86a16_read_status, + + .read_ber = mb86a16_read_ber, + .read_signal_strength = mb86a16_read_signal_strength, + .read_snr = mb86a16_read_snr, + .read_ucblocks = mb86a16_read_ucblocks, + + .diseqc_send_master_cmd = mb86a16_send_diseqc_msg, + .diseqc_send_burst = mb86a16_send_diseqc_burst, + .set_tone = mb86a16_set_tone, +}; + +struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap) +{ + u8 dev_id = 0; + struct mb86a16_state *state = NULL; + + state = kmalloc(sizeof(struct mb86a16_state), GFP_KERNEL); + if (state == NULL) + goto error; + + state->config = config; + state->i2c_adap = i2c_adap; + + mb86a16_read(state, 0x7f, &dev_id); + if (dev_id != 0xfe) + goto error; + + memcpy(&state->frontend.ops, &mb86a16_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + state->frontend.ops.set_voltage = state->config->set_voltage; + + return &state->frontend; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(mb86a16_attach); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Manu Abraham"); diff --git a/drivers/media/dvb/frontends/mb86a16.h b/drivers/media/dvb/frontends/mb86a16.h new file mode 100644 index 000000000000..6ea8c376394f --- /dev/null +++ b/drivers/media/dvb/frontends/mb86a16.h @@ -0,0 +1,52 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver 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. + + 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. +*/ + +#ifndef __MB86A16_H +#define __MB86A16_H + +#include <linux/dvb/frontend.h> +#include "dvb_frontend.h" + + +struct mb86a16_config { + u8 demod_address; + + int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage); +}; + + + +#if defined(CONFIG_DVB_MB86A16) || (defined(CONFIG_DVB_MB86A16_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap); + +#else + +static inline struct dvb_frontend *mb86a16_attach(const struct mb86a16_config *config, + struct i2c_adapter *i2c_adap) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_MB86A16 */ + +#endif /* __MB86A16_H */ diff --git a/drivers/media/dvb/frontends/mb86a16_priv.h b/drivers/media/dvb/frontends/mb86a16_priv.h new file mode 100644 index 000000000000..360a35acfe84 --- /dev/null +++ b/drivers/media/dvb/frontends/mb86a16_priv.h @@ -0,0 +1,151 @@ +/* + Fujitsu MB86A16 DVB-S/DSS DC Receiver 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. + + 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. +*/ + +#ifndef __MB86A16_PRIV_H +#define __MB86A16_PRIV_H + +#define MB86A16_TSOUT 0x00 +#define MB86A16_TSOUT_HIZSEL (0x01 << 5) +#define MB86A16_TSOUT_HIZCNTI (0x01 << 4) +#define MB86A16_TSOUT_MODE (0x01 << 3) +#define MB86A16_TSOUT_ORDER (0x01 << 2) +#define MB86A16_TSOUT_ERROR (0x01 << 1) +#define Mb86A16_TSOUT_EDGE (0x01 << 0) + +#define MB86A16_FEC 0x01 +#define MB86A16_FEC_FSYNC (0x01 << 5) +#define MB86A16_FEC_PCKB8 (0x01 << 4) +#define MB86A16_FEC_DVDS (0x01 << 3) +#define MB86A16_FEC_EREN (0x01 << 2) +#define Mb86A16_FEC_RSEN (0x01 << 1) +#define MB86A16_FEC_DIEN (0x01 << 0) + +#define MB86A16_AGC 0x02 +#define MB86A16_AGC_AGMD (0x01 << 6) +#define MB86A16_AGC_AGCW (0x0f << 2) +#define MB86A16_AGC_AGCP (0x01 << 1) +#define MB86A16_AGC_AGCR (0x01 << 0) + +#define MB86A16_SRATE1 0x03 +#define MB86A16_SRATE1_DECI (0x07 << 2) +#define MB86A16_SRATE1_CSEL (0x01 << 1) +#define MB86A16_SRATE1_RSEL (0x01 << 0) + +#define MB86A16_SRATE2 0x04 +#define MB86A16_SRATE2_STOFSL (0xff << 0) + +#define MB86A16_SRATE3 0x05 +#define MB86A16_SRATE2_STOFSH (0xff << 0) + +#define MB86A16_VITERBI 0x06 +#define MB86A16_FRAMESYNC 0x07 +#define MB86A16_CRLFILTCOEF1 0x08 +#define MB86A16_CRLFILTCOEF2 0x09 +#define MB86A16_STRFILTCOEF1 0x0a +#define MB86A16_STRFILTCOEF2 0x0b +#define MB86A16_RESET 0x0c +#define MB86A16_STATUS 0x0d +#define MB86A16_AFCML 0x0e +#define MB86A16_AFCMH 0x0f +#define MB86A16_BERMON 0x10 +#define MB86A16_BERTAB 0x11 +#define MB86A16_BERLSB 0x12 +#define MB86A16_BERMID 0x13 +#define MB86A16_BERMSB 0x14 +#define MB86A16_AGCM 0x15 + +#define MB86A16_DCC1 0x16 +#define MB86A16_DCC1_DISTA (0x01 << 7) +#define MB86A16_DCC1_PRTY (0x01 << 6) +#define MB86A16_DCC1_CTOE (0x01 << 5) +#define MB86A16_DCC1_TBEN (0x01 << 4) +#define MB86A16_DCC1_TBO (0x01 << 3) +#define MB86A16_DCC1_NUM (0x07 << 0) + +#define MB86A16_DCC2 0x17 +#define MB86A16_DCC2_DCBST (0x01 << 0) + +#define MB86A16_DCC3 0x18 +#define MB86A16_DCC3_CODE0 (0xff << 0) + +#define MB86A16_DCC4 0x19 +#define MB86A16_DCC4_CODE1 (0xff << 0) + +#define MB86A16_DCC5 0x1a +#define MB86A16_DCC5_CODE2 (0xff << 0) + +#define MB86A16_DCC6 0x1b +#define MB86A16_DCC6_CODE3 (0xff << 0) + +#define MB86A16_DCC7 0x1c +#define MB86A16_DCC7_CODE4 (0xff << 0) + +#define MB86A16_DCC8 0x1d +#define MB86A16_DCC8_CODE5 (0xff << 0) + +#define MB86A16_DCCOUT 0x1e +#define MB86A16_DCCOUT_DISEN (0x01 << 0) + +#define MB86A16_TONEOUT1 0x1f +#define MB86A16_TONE_TDIVL (0xff << 0) + +#define MB86A16_TONEOUT2 0x20 +#define MB86A16_TONE_TMD (0x03 << 2) +#define MB86A16_TONE_TDIVH (0x03 << 0) + +#define MB86A16_FREQ1 0x21 +#define MB86A16_FREQ2 0x22 +#define MB86A16_FREQ3 0x23 +#define MB86A16_FREQ4 0x24 +#define MB86A16_FREQSET 0x25 +#define MB86A16_CNM 0x26 +#define MB86A16_PORT0 0x27 +#define MB86A16_PORT1 0x28 +#define MB86A16_DRCFILT 0x29 +#define MB86A16_AFC 0x2a +#define MB86A16_AFCEXL 0x2b +#define MB86A16_AFCEXH 0x2c +#define MB86A16_DAGC 0x2d +#define MB86A16_SEQMODE 0x32 +#define MB86A16_S0S1T 0x33 +#define MB86A16_S2S3T 0x34 +#define MB86A16_S4S5T 0x35 +#define MB86A16_CNTMR 0x36 +#define MB86A16_SIG1 0x37 +#define MB86A16_SIG2 0x38 +#define MB86A16_VIMAG 0x39 +#define MB86A16_VISET1 0x3a +#define MB86A16_VISET2 0x3b +#define MB86A16_VISET3 0x3c +#define MB86A16_FAGCS1 0x3d +#define MB86A16_FAGCS2 0x3e +#define MB86A16_FAGCS3 0x3f +#define MB86A16_FAGCS4 0x40 +#define MB86A16_FAGCS5 0x41 +#define MB86A16_FAGCS6 0x42 +#define MB86A16_CRM 0x43 +#define MB86A16_STRM 0x44 +#define MB86A16_DAGCML 0x45 +#define MB86A16_DAGCMH 0x46 +#define MB86A16_QPSKTST 0x49 +#define MB86A16_DISTMON 0x52 +#define MB86A16_VERSION 0x7f + +#endif /* __MB86A16_PRIV_H */ diff --git a/drivers/media/dvb/frontends/stv0900_core.c b/drivers/media/dvb/frontends/stv0900_core.c index df49ea0983bc..8762c86044a5 100644 --- a/drivers/media/dvb/frontends/stv0900_core.c +++ b/drivers/media/dvb/frontends/stv0900_core.c @@ -1451,6 +1451,8 @@ static int stv0900_status(struct stv0900_internal *intp, { enum fe_stv0900_search_state demod_state; int locked = FALSE; + u8 tsbitrate0_val, tsbitrate1_val; + s32 bitrate; demod_state = stv0900_get_bits(intp, HEADER_MODE); switch (demod_state) { @@ -1473,6 +1475,17 @@ static int stv0900_status(struct stv0900_internal *intp, dprintk("%s: locked = %d\n", __func__, locked); + if (stvdebug) { + /* Print TS bitrate */ + tsbitrate0_val = stv0900_read_reg(intp, TSBITRATE0); + tsbitrate1_val = stv0900_read_reg(intp, TSBITRATE1); + /* Formula Bit rate = Mclk * px_tsfifo_bitrate / 16384 */ + bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) + * (tsbitrate1_val << 8 | tsbitrate0_val); + bitrate /= 16384; + dprintk("TS bitrate = %d Mbit/sec \n", bitrate); + }; + return locked; } diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c index 48edd542242e..1573466a5c74 100644 --- a/drivers/media/dvb/frontends/stv090x.c +++ b/drivers/media/dvb/frontends/stv090x.c @@ -3597,7 +3597,8 @@ static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma reg = STV090x_READ_DEMOD(state, DISTXCTL); - STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2); + STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, + (state->config->diseqc_envelope_mode) ? 4 : 2); STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1); if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0) goto err; @@ -3649,10 +3650,10 @@ static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t reg = STV090x_READ_DEMOD(state, DISTXCTL); if (burst == SEC_MINI_A) { - mode = 3; + mode = (state->config->diseqc_envelope_mode) ? 5 : 3; value = 0x00; } else { - mode = 2; + mode = (state->config->diseqc_envelope_mode) ? 4 : 2; value = 0xFF; } diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h index e968c98bb70f..b133807663ea 100644 --- a/drivers/media/dvb/frontends/stv090x.h +++ b/drivers/media/dvb/frontends/stv090x.h @@ -75,6 +75,8 @@ struct stv090x_config { enum stv090x_i2crpt repeater_level; + bool diseqc_envelope_mode; + int (*tuner_init) (struct dvb_frontend *fe); int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode); int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 6c1dbf9288d8..6ca533ea0f0e 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -426,6 +426,10 @@ struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, id = tda10021_readreg(state, 0x1a); if ((id & 0xf0) != 0x70) goto error; + /* Don't claim TDA10023 */ + if (id == 0x7d) + goto error; + printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n", state->config->demod_address, id); diff --git a/drivers/media/dvb/frontends/tda665x.c b/drivers/media/dvb/frontends/tda665x.c new file mode 100644 index 000000000000..87d52739c828 --- /dev/null +++ b/drivers/media/dvb/frontends/tda665x.c @@ -0,0 +1,257 @@ +/* + TDA665x tuner 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. + + 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. +*/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include "dvb_frontend.h" +#include "tda665x.h" + +struct tda665x_state { + struct dvb_frontend *fe; + struct i2c_adapter *i2c; + const struct tda665x_config *config; + + u32 frequency; + u32 bandwidth; +}; + +static int tda665x_read(struct tda665x_state *state, u8 *buf) +{ + const struct tda665x_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = I2C_M_RD, .buf = buf, .len = 2 }; + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) + goto exit; + + return err; +exit: + printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); + return err; +} + +static int tda665x_write(struct tda665x_state *state, u8 *buf, u8 length) +{ + const struct tda665x_config *config = state->config; + int err = 0; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, .buf = buf, .len = length }; + + err = i2c_transfer(state->i2c, &msg, 1); + if (err != 1) + goto exit; + + return err; +exit: + printk(KERN_ERR "%s: I/O Error err=<%d>\n", __func__, err); + return err; +} + +static int tda665x_get_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda665x_state *state = fe->tuner_priv; + int err = 0; + + switch (param) { + case DVBFE_TUNER_FREQUENCY: + tstate->frequency = state->frequency; + break; + case DVBFE_TUNER_BANDWIDTH: + break; + default: + printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); + err = -EINVAL; + break; + } + + return err; +} + +static int tda665x_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct tda665x_state *state = fe->tuner_priv; + u8 result = 0; + int err = 0; + + *status = 0; + + err = tda665x_read(state, &result); + if (err < 0) + goto exit; + + if ((result >> 6) & 0x01) { + printk(KERN_DEBUG "%s: Tuner Phase Locked\n", __func__); + *status = 1; + } + + return err; +exit: + printk(KERN_ERR "%s: I/O Error\n", __func__); + return err; +} + +static int tda665x_set_state(struct dvb_frontend *fe, + enum tuner_param param, + struct tuner_state *tstate) +{ + struct tda665x_state *state = fe->tuner_priv; + const struct tda665x_config *config = state->config; + u32 frequency, status = 0; + u8 buf[4]; + int err = 0; + + if (param & DVBFE_TUNER_FREQUENCY) { + + frequency = tstate->frequency; + if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) { + printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency); + return -EINVAL; + } + + frequency += config->frequency_offst; + frequency *= config->ref_multiplier; + frequency += config->ref_divider >> 1; + frequency /= config->ref_divider; + + buf[0] = (u8) (frequency & 0x7f00) >> 8; + buf[1] = (u8) (frequency & 0x00ff) >> 0; + buf[2] = 0x80 | 0x40 | 0x02; + buf[3] = 0x00; + + /* restore frequency */ + frequency = tstate->frequency; + + if (frequency < 153000000) { + /* VHF-L */ + buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */ + if (frequency < 68000000) + buf[3] |= 0x40; /* 83uA */ + if (frequency < 1040000000) + buf[3] |= 0x60; /* 122uA */ + if (frequency < 1250000000) + buf[3] |= 0x80; /* 163uA */ + else + buf[3] |= 0xa0; /* 254uA */ + } else if (frequency < 438000000) { + /* VHF-H */ + buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */ + if (frequency < 230000000) + buf[3] |= 0x40; + if (frequency < 300000000) + buf[3] |= 0x60; + else + buf[3] |= 0x80; + } else { + /* UHF */ + buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */ + if (frequency < 470000000) + buf[3] |= 0x60; + if (frequency < 526000000) + buf[3] |= 0x80; + else + buf[3] |= 0xa0; + } + + /* Set params */ + err = tda665x_write(state, buf, 5); + if (err < 0) + goto exit; + + /* sleep for some time */ + printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__); + msleep(20); + /* check status */ + err = tda665x_get_status(fe, &status); + if (err < 0) + goto exit; + + if (status == 1) { + printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status); + state->frequency = frequency; /* cache successful state */ + } else { + printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status); + } + } else { + printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param); + return -EINVAL; + } + + return 0; +exit: + printk(KERN_ERR "%s: I/O Error\n", __func__); + return err; +} + +static int tda665x_release(struct dvb_frontend *fe) +{ + struct tda665x_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + return 0; +} + +static struct dvb_tuner_ops tda665x_ops = { + + .set_state = tda665x_set_state, + .get_state = tda665x_get_state, + .get_status = tda665x_get_status, + .release = tda665x_release +}; + +struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c) +{ + struct tda665x_state *state = NULL; + struct dvb_tuner_info *info; + + state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); + if (state == NULL) + goto exit; + + state->config = config; + state->i2c = i2c; + state->fe = fe; + fe->tuner_priv = state; + fe->ops.tuner_ops = tda665x_ops; + info = &fe->ops.tuner_ops.info; + + memcpy(info->name, config->name, sizeof(config->name)); + info->frequency_min = config->frequency_min; + info->frequency_max = config->frequency_max; + info->frequency_step = config->frequency_offst; + + printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); + + return fe; + +exit: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(tda665x_attach); + +MODULE_DESCRIPTION("TDA665x driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/tda665x.h b/drivers/media/dvb/frontends/tda665x.h new file mode 100644 index 000000000000..ec7927aa75ae --- /dev/null +++ b/drivers/media/dvb/frontends/tda665x.h @@ -0,0 +1,52 @@ +/* + TDA665x tuner 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. + + 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. +*/ + +#ifndef __TDA665x_H +#define __TDA665x_H + +struct tda665x_config { + char name[128]; + + u8 addr; + u32 frequency_min; + u32 frequency_max; + u32 frequency_offst; + u32 ref_multiplier; + u32 ref_divider; +}; + +#if defined(CONFIG_DVB_TDA665x) || (defined(CONFIG_DVB_TDA665x_MODULE) && defined(MODULE)) + +extern struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c); + +#else + +static inline struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, + const struct tda665x_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); + return NULL; +} + +#endif /* CONFIG_DVB_TDA665x */ + +#endif /* __TDA665x_H */ diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig new file mode 100644 index 000000000000..f7b72a32adf3 --- /dev/null +++ b/drivers/media/dvb/mantis/Kconfig @@ -0,0 +1,32 @@ +config MANTIS_CORE + tristate "Mantis/Hopper PCI bridge based devices" + depends on PCI && I2C && INPUT + + help + Support for PCI cards based on the Mantis and Hopper PCi bridge. + + Say Y if you own such a device and want to use it. + +config DVB_MANTIS + tristate "MANTIS based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_MB86A16 + select DVB_ZL10353 + select DVB_STV0299 + select DVB_PLL + help + Support for PCI cards based on the Mantis PCI bridge. + Say Y when you have a Mantis based DVB card and want to use it. + + If unsure say N. + +config DVB_HOPPER + tristate "HOPPER based cards" + depends on MANTIS_CORE && DVB_CORE && PCI && I2C + select DVB_ZL10353 + select DVB_PLL + help + Support for PCI cards based on the Hopper PCI bridge. + Say Y when you have a Hopper based DVB card and want to use it. + + If unsure say N diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile new file mode 100644 index 000000000000..98dc5cd258ac --- /dev/null +++ b/drivers/media/dvb/mantis/Makefile @@ -0,0 +1,28 @@ +mantis_core-objs := mantis_ioc.o \ + mantis_uart.o \ + mantis_dma.o \ + mantis_pci.o \ + mantis_i2c.o \ + mantis_dvb.o \ + mantis_evm.o \ + mantis_hif.o \ + mantis_ca.o \ + mantis_pcmcia.o \ + mantis_input.o + +mantis-objs := mantis_cards.o \ + mantis_vp1033.o \ + mantis_vp1034.o \ + mantis_vp1041.o \ + mantis_vp2033.o \ + mantis_vp2040.o \ + mantis_vp3030.o + +hopper-objs := hopper_cards.o \ + hopper_vp3028.o + +obj-$(CONFIG_MANTIS_CORE) += mantis_core.o +obj-$(CONFIG_DVB_MANTIS) += mantis.o +obj-$(CONFIG_DVB_HOPPER) += hopper.o + +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c new file mode 100644 index 000000000000..d073c61e3c0d --- /dev/null +++ b/drivers/media/dvb/mantis/hopper_cards.c @@ -0,0 +1,275 @@ +/* + Hopper 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. + + 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. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <asm/irq.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "hopper_vp3028.h" +#include "mantis_dma.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +#define DRIVER_NAME "Hopper" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static int devs; + +static irqreturn_t hopper_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit hopper_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + 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; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &hopper_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + devs++; + + return err; + +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit hopper_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; + +} + +static struct pci_device_id hopper_pci_table[] = { + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3028_DVB_T, &vp3028_config), + { } +}; + +static struct pci_driver hopper_pci_driver = { + .name = DRIVER_NAME, + .id_table = hopper_pci_table, + .probe = hopper_pci_probe, + .remove = hopper_pci_remove, +}; + +static int __devinit hopper_init(void) +{ + return pci_register_driver(&hopper_pci_driver); +} + +static void __devexit hopper_exit(void) +{ + return pci_unregister_driver(&hopper_pci_driver); +} + +module_init(hopper_init); +module_exit(hopper_exit); + +MODULE_DESCRIPTION("HOPPER driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c new file mode 100644 index 000000000000..96674c78e86b --- /dev/null +++ b/drivers/media/dvb/mantis/hopper_vp3028.c @@ -0,0 +1,88 @@ +/* + Hopper VP-3028 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "hopper_vp3028.h" + +struct zl10353_config hopper_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + gpio_set_bits(mantis, config->reset, 1); + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = zl10353_attach(&hopper_vp3028_config, adapter); + + if (!fe) + return -1; + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3028_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3028_frontend_init, + .power = GPIF_A00, + .reset = GPIF_A03, +}; diff --git a/drivers/media/dvb/mantis/hopper_vp3028.h b/drivers/media/dvb/mantis/hopper_vp3028.h new file mode 100644 index 000000000000..57239498bc87 --- /dev/null +++ b/drivers/media/dvb/mantis/hopper_vp3028.h @@ -0,0 +1,30 @@ +/* + Hopper VP-3028 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. + + 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. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "mantis_common.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct mantis_hwconfig vp3028_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/dvb/mantis/mantis_ca.c b/drivers/media/dvb/mantis/mantis_ca.c new file mode 100644 index 000000000000..403ce043d00e --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_ca.c @@ -0,0 +1,207 @@ +/* + 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +#include "mantis_ca.h" + +static int mantis_ca_read_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_mem(ca, addr); +} + +static int mantis_ca_write_attr_mem(struct dvb_ca_en50221 *en50221, int slot, int addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request Attribute Mem Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_mem(ca, addr, data); +} + +static int mantis_ca_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Read", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_read_iom(ca, addr); +} + +static int mantis_ca_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr, u8 data) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Request CAM control Write", slot); + + if (slot != 0) + return -EINVAL; + + return mantis_hif_write_iom(ca, addr, data); +} + +static int mantis_ca_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot RESET", slot); + udelay(500); /* Wait.. */ + mmwrite(0xda, MANTIS_PCMCIA_RESET); /* Leading edge assert */ + udelay(500); + mmwrite(0x00, MANTIS_PCMCIA_RESET); /* Trailing edge deassert */ + msleep(1000); + dvb_ca_en50221_camready_irq(&ca->en50221, 0); + + return 0; +} + +static int mantis_ca_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Slot shutdown", slot); + + return 0; +} + +static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); +/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ + + return 0; +} + +static int mantis_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +{ + struct mantis_ca *ca = en50221->data; + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Slot(%d): Poll Slot status", slot); + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "CA Module present and ready"); + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } else { + dprintk(MANTIS_DEBUG, 1, "CA Module not present or not ready"); + } + + return 0; +} + +int mantis_ca_init(struct mantis_pci *mantis) +{ + struct dvb_adapter *dvb_adapter = &mantis->dvb_adapter; + struct mantis_ca *ca; + int ca_flags = 0, result; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis CA"); + ca = kzalloc(sizeof(struct mantis_ca), GFP_KERNEL); + if (!ca) { + dprintk(MANTIS_ERROR, 1, "Out of memory!, exiting .."); + result = -ENOMEM; + goto err; + } + + ca->ca_priv = mantis; + mantis->mantis_ca = ca; + ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE; + /* register CA interface */ + ca->en50221.owner = THIS_MODULE; + ca->en50221.read_attribute_mem = mantis_ca_read_attr_mem; + ca->en50221.write_attribute_mem = mantis_ca_write_attr_mem; + ca->en50221.read_cam_control = mantis_ca_read_cam_ctl; + ca->en50221.write_cam_control = mantis_ca_write_cam_ctl; + ca->en50221.slot_reset = mantis_ca_slot_reset; + ca->en50221.slot_shutdown = mantis_ca_slot_shutdown; + ca->en50221.slot_ts_enable = mantis_ts_control; + ca->en50221.poll_slot_status = mantis_slot_status; + ca->en50221.data = ca; + + mutex_init(&ca->ca_lock); + + init_waitqueue_head(&ca->hif_data_wq); + init_waitqueue_head(&ca->hif_opdone_wq); + init_waitqueue_head(&ca->hif_write_wq); + + dprintk(MANTIS_ERROR, 1, "Registering EN50221 device"); + result = dvb_ca_en50221_init(dvb_adapter, &ca->en50221, ca_flags, 1); + if (result != 0) { + dprintk(MANTIS_ERROR, 1, "EN50221: Initialization failed <%d>", result); + goto err; + } + dprintk(MANTIS_ERROR, 1, "Registered EN50221 device"); + mantis_evmgr_init(ca); + return 0; +err: + kfree(ca); + return result; +} +EXPORT_SYMBOL_GPL(mantis_ca_init); + +void mantis_ca_exit(struct mantis_pci *mantis) +{ + struct mantis_ca *ca = mantis->mantis_ca; + + dprintk(MANTIS_DEBUG, 1, "Mantis CA exit"); + + mantis_evmgr_exit(ca); + dprintk(MANTIS_ERROR, 1, "Unregistering EN50221 device"); + if (ca) + dvb_ca_en50221_release(&ca->en50221); + + kfree(ca); +} +EXPORT_SYMBOL_GPL(mantis_ca_exit); diff --git a/drivers/media/dvb/mantis/mantis_ca.h b/drivers/media/dvb/mantis/mantis_ca.h new file mode 100644 index 000000000000..dc63e55f7eca --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_ca.h @@ -0,0 +1,27 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_CA_H +#define __MANTIS_CA_H + +extern int mantis_ca_init(struct mantis_pci *mantis); +extern void mantis_ca_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CA_H */ diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c new file mode 100644 index 000000000000..16f1708fd3bc --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_cards.c @@ -0,0 +1,305 @@ +/* + 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. + + 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. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <asm/irq.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_dvb.h" +#include "mantis_uart.h" +#include "mantis_ioc.h" +#include "mantis_pci.h" +#include "mantis_i2c.h" +#include "mantis_reg.h" + +static unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +static int devs; + +#define DRIVER_NAME "Mantis" + +static char *label[10] = { + "DMA", + "IRQ-0", + "IRQ-1", + "OCERR", + "PABRT", + "RIPRR", + "PPERR", + "FTRGT", + "RISCI", + "RACK" +}; + +static irqreturn_t mantis_irq_handler(int irq, void *dev_id) +{ + u32 stat = 0, mask = 0, lstat = 0, mstat = 0; + u32 rst_stat = 0, rst_mask = 0; + + struct mantis_pci *mantis; + struct mantis_ca *ca; + + mantis = (struct mantis_pci *) dev_id; + if (unlikely(mantis == NULL)) { + dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + return IRQ_NONE; + } + ca = mantis->mantis_ca; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + mstat = lstat = stat & ~MANTIS_INT_RISCSTAT; + if (!(stat & mask)) + return IRQ_NONE; + + rst_mask = MANTIS_GPIF_WRACK | + MANTIS_GPIF_OTHERR | + MANTIS_SBUF_WSTO | + MANTIS_GPIF_EXTIRQ; + + rst_stat = mmread(MANTIS_GPIF_STATUS); + rst_stat &= rst_mask; + mmwrite(rst_stat, MANTIS_GPIF_STATUS); + + mantis->mantis_int_stat = stat; + mantis->mantis_int_mask = mask; + dprintk(MANTIS_DEBUG, 0, "\n-- Stat=<%02x> Mask=<%02x> --", stat, mask); + if (stat & MANTIS_INT_RISCEN) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[0]); + } + if (stat & MANTIS_INT_IRQ0) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[1]); + mantis->gpif_status = rst_stat; + wake_up(&ca->hif_write_wq); + schedule_work(&ca->hif_evm_work); + } + if (stat & MANTIS_INT_IRQ1) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[2]); + schedule_work(&mantis->uart_work); + } + if (stat & MANTIS_INT_OCERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[3]); + } + if (stat & MANTIS_INT_PABORT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[4]); + } + if (stat & MANTIS_INT_RIPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[5]); + } + if (stat & MANTIS_INT_PPERR) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[6]); + } + if (stat & MANTIS_INT_FTRGT) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[7]); + } + if (stat & MANTIS_INT_RISCI) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); + mantis->finished_block = (stat & MANTIS_INT_RISCSTAT) >> 28; + tasklet_schedule(&mantis->tasklet); + } + if (stat & MANTIS_INT_I2CDONE) { + dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); + wake_up(&mantis->i2c_wq); + } + mmwrite(stat, MANTIS_INT_STAT); + stat &= ~(MANTIS_INT_RISCEN | MANTIS_INT_I2CDONE | + MANTIS_INT_I2CRACK | MANTIS_INT_PCMCIA7 | + MANTIS_INT_PCMCIA6 | MANTIS_INT_PCMCIA5 | + MANTIS_INT_PCMCIA4 | MANTIS_INT_PCMCIA3 | + MANTIS_INT_PCMCIA2 | MANTIS_INT_PCMCIA1 | + MANTIS_INT_PCMCIA0 | MANTIS_INT_IRQ1 | + MANTIS_INT_IRQ0 | MANTIS_INT_OCERR | + MANTIS_INT_PABORT | MANTIS_INT_RIPERR | + MANTIS_INT_PPERR | MANTIS_INT_FTRGT | + MANTIS_INT_RISCI); + + if (stat) + dprintk(MANTIS_DEBUG, 0, "<Unknown> Stat=<%02x> Mask=<%02x>", stat, mask); + + dprintk(MANTIS_DEBUG, 0, "\n"); + return IRQ_HANDLED; +} + +static int __devinit mantis_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + int err = 0; + + 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; + } + + mantis->num = devs; + mantis->verbose = verbose; + mantis->pdev = pdev; + config = (struct mantis_hwconfig *) pci_id->driver_data; + config->irq_handler = &mantis_irq_handler; + mantis->hwconfig = config; + + err = mantis_pci_init(mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI initialization failed <%d>", err); + goto fail1; + } + + err = mantis_stream_control(mantis, STREAM_TO_HIF); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis stream control failed <%d>", err); + goto fail1; + } + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C initialization failed <%d>", err); + goto fail2; + } + + err = mantis_get_mac(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis MAC address read failed <%d>", err); + goto fail2; + } + + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA initialization failed <%d>", err); + goto fail3; + } + + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DVB initialization failed <%d>", err); + goto fail4; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART initialization failed <%d>", err); + goto fail6; + } + + devs++; + + return err; + + + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis UART exit! <%d>", err); + mantis_uart_exit(mantis); + +fail6: +fail4: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis DMA exit! <%d>", err); + mantis_dma_exit(mantis); + +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis I2C exit! <%d>", err); + mantis_i2c_exit(mantis); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis PCI exit! <%d>", err); + mantis_pci_exit(mantis); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis free! <%d>", err); + kfree(mantis); + +fail0: + return err; +} + +static void __devexit mantis_pci_remove(struct pci_dev *pdev) +{ + struct mantis_pci *mantis = pci_get_drvdata(pdev); + + if (mantis) { + + mantis_uart_exit(mantis); + mantis_dvb_exit(mantis); + mantis_dma_exit(mantis); + mantis_i2c_exit(mantis); + mantis_pci_exit(mantis); + kfree(mantis); + } + return; +} + +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, &vp2033_config), + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config), + { } +}; + +static struct pci_driver mantis_pci_driver = { + .name = DRIVER_NAME, + .id_table = mantis_pci_table, + .probe = mantis_pci_probe, + .remove = mantis_pci_remove, +}; + +static int __devinit mantis_init(void) +{ + return pci_register_driver(&mantis_pci_driver); +} + +static void __devexit mantis_exit(void) +{ + return pci_unregister_driver(&mantis_pci_driver); +} + +module_init(mantis_init); +module_exit(mantis_exit); + +MODULE_DESCRIPTION("MANTIS driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h new file mode 100644 index 000000000000..d0b645a483c9 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_common.h @@ -0,0 +1,179 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_COMMON_H +#define __MANTIS_COMMON_H + +#include <linux/mutex.h> +#include <linux/workqueue.h> + +#include "mantis_uart.h" + +#include "mantis_link.h" + +#define MANTIS_ERROR 0 +#define MANTIS_NOTICE 1 +#define MANTIS_INFO 2 +#define MANTIS_DEBUG 3 +#define MANTIS_TMG 9 + +#define dprintk(y, z, format, arg...) do { \ + if (z) { \ + if ((mantis->verbose > MANTIS_ERROR) && (mantis->verbose > y)) \ + printk(KERN_ERR "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_NOTICE) && (mantis->verbose > y)) \ + printk(KERN_NOTICE "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_INFO) && (mantis->verbose > y)) \ + printk(KERN_INFO "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_DEBUG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + else if ((mantis->verbose > MANTIS_TMG) && (mantis->verbose > y)) \ + printk(KERN_DEBUG "%s (%d): " format "\n" , __func__ , mantis->num , ##arg); \ + } else { \ + if (mantis->verbose > y) \ + printk(format , ##arg); \ + } \ +} while(0) + +#define mwrite(dat, addr) writel((dat), addr) +#define mread(addr) readl(addr) + +#define mmwrite(dat, addr) mwrite((dat), (mantis->mmio + (addr))) +#define mmread(addr) mread(mantis->mmio + (addr)) + +#define MANTIS_TS_188 0 +#define MANTIS_TS_204 1 + +#define TWINHAN_TECHNOLOGIES 0x1822 +#define MANTIS 0x4e35 + +#define TECHNISAT 0x1ae4 +#define TERRATEC 0x153b + +#define MAKE_ENTRY(__subven, __subdev, __configptr) { \ + .vendor = TWINHAN_TECHNOLOGIES, \ + .device = MANTIS, \ + .subvendor = (__subven), \ + .subdevice = (__subdev), \ + .driver_data = (unsigned long) (__configptr) \ +} + +enum mantis_i2c_mode { + MANTIS_PAGE_MODE = 0, + MANTIS_BYTE_MODE, +}; + +struct mantis_pci; + +struct mantis_hwconfig { + char *model_name; + char *dev_type; + u32 ts_size; + + enum mantis_baud baud_rate; + enum mantis_parity parity; + u32 bytes; + + irqreturn_t (*irq_handler)(int irq, void *dev_id); + int (*frontend_init)(struct mantis_pci *mantis, struct dvb_frontend *fe); + + u8 power; + u8 reset; + + enum mantis_i2c_mode i2c_mode; +}; + +struct mantis_pci { + unsigned int verbose; + + /* PCI stuff */ + u16 vendor_id; + u16 device_id; + u16 subsystem_vendor; + u16 subsystem_device; + + u8 latency; + + struct pci_dev *pdev; + + unsigned long mantis_addr; + void __iomem *mmio; + + u8 irq; + u8 revision; + + unsigned int num; + + /* RISC Core */ + u32 finished_block; + u32 last_block; + u32 line_bytes; + u32 line_count; + u32 risc_pos; + u8 *buf_cpu; + dma_addr_t buf_dma; + u32 *risc_cpu; + dma_addr_t risc_dma; + + struct tasklet_struct tasklet; + + struct i2c_adapter adapter; + int i2c_rc; + wait_queue_head_t i2c_wq; + struct mutex i2c_lock; + + /* DVB stuff */ + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net dvbnet; + + u8 feeds; + + struct mantis_hwconfig *hwconfig; + + u32 mantis_int_stat; + u32 mantis_int_mask; + + /* board specific */ + u8 mac_address[8]; + u32 sub_vendor_id; + u32 sub_device_id; + + /* A12 A13 A14 */ + u32 gpio_status; + + u32 gpif_status; + + struct mantis_ca *mantis_ca; + + wait_queue_head_t uart_wq; + struct work_struct uart_work; + spinlock_t uart_lock; + + struct input_dev *rc; +}; + +#define MANTIS_HIF_STATUS (mantis->gpio_status) + +#endif /* __MANTIS_COMMON_H */ diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c new file mode 100644 index 000000000000..8113b23ce448 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_core.c @@ -0,0 +1,238 @@ +/* + 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. + + 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. +*/ + +#include "mantis_common.h" +#include "mantis_core.h" +#include "mantis_vp1033.h" +#include "mantis_vp1034.h" +#include "mantis_vp1041.h" +#include "mantis_vp2033.h" +#include "mantis_vp2040.h" +#include "mantis_vp3030.h" + +static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + struct i2c_msg msg[] = { + { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = 1 + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .buf = data, + .len = length + }, + }; + + err = i2c_transfer(&mantis->adapter, msg, 2); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} + +static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) +{ + int err; + + struct i2c_msg msg = { + .addr = 0x50, + .flags = 0, + .buf = data, + .len = length + }; + + err = i2c_transfer(&mantis->adapter, &msg, 1); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, + "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >", + err, length, data[0], data[1]); + + return err; + } + + return 0; +} + +static int get_mac_address(struct mantis_pci *mantis) +{ + int err; + + mantis->mac_address[0] = 0x08; + err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); + + return err; + } + dprintk(verbose, MANTIS_ERROR, 0, + " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n", + mantis->mac_address[0], mantis->mac_address[1], + mantis->mac_address[2], mantis->mac_address[3], + mantis->mac_address[4], mantis->mac_address[5]); + + return 0; +} + +#define MANTIS_MODEL_UNKNOWN "UNKNOWN" +#define MANTIS_DEV_UNKNOWN "UNKNOWN" + +struct mantis_hwconfig unknown_device = { + .model_name = MANTIS_MODEL_UNKNOWN, + .dev_type = MANTIS_DEV_UNKNOWN, +}; + +static void mantis_load_config(struct mantis_pci *mantis) +{ + switch (mantis->subsystem_device) { + case MANTIS_VP_1033_DVB_S: /* VP-1033 */ + mantis->hwconfig = &vp1033_mantis_config; + break; + case MANTIS_VP_1034_DVB_S: /* VP-1034 */ + mantis->hwconfig = &vp1034_mantis_config; + break; + case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ + case TECHNISAT_SKYSTAR_HD2: + mantis->hwconfig = &vp1041_mantis_config; + break; + case MANTIS_VP_2033_DVB_C: /* VP-2033 */ + mantis->hwconfig = &vp2033_mantis_config; + break; + case MANTIS_VP_2040_DVB_C: /* VP-2040 */ + case TERRATEC_CINERGY_C_PCI: /* VP-2040 clone */ + case TECHNISAT_CABLESTAR_HD2: + mantis->hwconfig = &vp2040_mantis_config; + break; + case MANTIS_VP_3030_DVB_T: /* VP-3030 */ + mantis->hwconfig = &vp3030_mantis_config; + break; + default: + mantis->hwconfig = &unknown_device; + break; + } +} + +int mantis_core_init(struct mantis_pci *mantis) +{ + int err = 0; + + mantis_load_config(mantis); + dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + mantis->hwconfig->model_name, mantis->hwconfig->dev_type, + mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); + dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->subsystem_vendor, mantis->subsystem_device); + dprintk(verbose, MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, mantis->latency, + mantis->mantis_addr, mantis->mantis_mmio); + + err = mantis_i2c_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); + return err; + } + err = get_mac_address(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); + return err; + } + err = mantis_dma_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); + return err; + } + err = mantis_dvb_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); + return err; + } + err = mantis_uart_init(mantis); + if (err < 0) { + dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); + return err; + } + + return 0; +} + +int mantis_core_exit(struct mantis_pci *mantis) +{ + mantis_dma_stop(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); + + mantis_uart_exit(mantis); + dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); + + if (mantis_dma_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); + if (mantis_dvb_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); + if (mantis_i2c_exit(mantis) < 0) + dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); + + return 0; +} + +/* Turn the given bit on or off. */ +void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); + udelay(100); +} + +/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ +void mantis_set_direction(struct mantis_pci *mantis, int direction) +{ + u32 reg; + + reg = mmread(0x28); + dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); + if (direction == 0x01) { + /* to CI */ + reg |= 0x04; + mmwrite(reg, 0x28); + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + } else { + reg &= 0xff - 0x04; + mmwrite(reg, 0x28); + reg |= 0x04; + mmwrite(reg, 0x28); + } +} diff --git a/drivers/media/dvb/mantis/mantis_core.h b/drivers/media/dvb/mantis/mantis_core.h new file mode 100644 index 000000000000..833ee42e694e --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_core.h @@ -0,0 +1,57 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_CORE_H +#define __MANTIS_CORE_H + +#include "mantis_common.h" + + +#define FE_TYPE_SAT 0 +#define FE_TYPE_CAB 1 +#define FE_TYPE_TER 2 + +#define FE_TYPE_TS204 0 +#define FE_TYPE_TS188 1 + + +struct vendorname { + u8 *sub_vendor_name; + u32 sub_vendor_id; +}; + +struct devicetype { + u8 *sub_device_name; + u32 sub_device_id; + u8 device_type; + u32 type_flags; +}; + + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); +extern int mantis_core_init(struct mantis_pci *mantis); +extern int mantis_core_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c new file mode 100644 index 000000000000..46202a4012aa --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_dma.c @@ -0,0 +1,256 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> +#include <asm/page.h> +#include <linux/vmalloc.h> +#include <linux/pci.h> + +#include <asm/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_dma.h" + +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_IRQ (0x01 << 24) + +#define RISC_STATUS(status) ((((~status) & 0x0f) << 20) | ((status & 0x0f) << 16)) +#define RISC_FLUSH() (mantis->risc_pos = 0) +#define RISC_INSTR(opcode) (mantis->risc_cpu[mantis->risc_pos++] = cpu_to_le32(opcode)) + +#define MANTIS_BUF_SIZE (64 * 1024) +#define MANTIS_BLOCK_BYTES (MANTIS_BUF_SIZE >> 4) +#define MANTIS_BLOCK_COUNT (1 << 4) +#define MANTIS_RISC_SIZE PAGE_SIZE + +int mantis_dma_exit(struct mantis_pci *mantis) +{ + if (mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, + MANTIS_BUF_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, + mantis->buf_cpu, mantis->buf_dma); + + mantis->buf_cpu = NULL; + } + if (mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, + MANTIS_RISC_SIZE); + + pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, + mantis->risc_cpu, mantis->risc_dma); + + mantis->risc_cpu = NULL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dma_exit); + +static inline int mantis_alloc_buffers(struct mantis_pci *mantis) +{ + if (!mantis->buf_cpu) { + mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_BUF_SIZE, + &mantis->buf_dma); + if (!mantis->buf_cpu) { + dprintk(MANTIS_ERROR, 1, + "DMA buffer allocation failed"); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "DMA=0x%lx cpu=0x%p size=%d", + (unsigned long) mantis->buf_dma, + mantis->buf_cpu, MANTIS_BUF_SIZE); + } + if (!mantis->risc_cpu) { + mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, + MANTIS_RISC_SIZE, + &mantis->risc_dma); + + if (!mantis->risc_cpu) { + dprintk(MANTIS_ERROR, 1, + "RISC program allocation failed"); + + mantis_dma_exit(mantis); + + goto err; + } + dprintk(MANTIS_ERROR, 1, + "RISC=0x%lx cpu=0x%p size=%lx", + (unsigned long) mantis->risc_dma, + mantis->risc_cpu, MANTIS_RISC_SIZE); + } + + return 0; +err: + dprintk(MANTIS_ERROR, 1, "Out of memory (?) ....."); + return -ENOMEM; +} + +static inline int mantis_calc_lines(struct mantis_pci *mantis) +{ + mantis->line_bytes = MANTIS_BLOCK_BYTES; + mantis->line_count = MANTIS_BLOCK_COUNT; + + while (mantis->line_bytes > 4095) { + mantis->line_bytes >>= 1; + mantis->line_count <<= 1; + } + + dprintk(MANTIS_DEBUG, 1, "Mantis RISC block bytes=[%d], line bytes=[%d], line count=[%d]", + MANTIS_BLOCK_BYTES, mantis->line_bytes, mantis->line_count); + + if (mantis->line_count > 255) { + dprintk(MANTIS_ERROR, 1, "Buffer size error"); + return -EINVAL; + } + + return 0; +} + +int mantis_dma_init(struct mantis_pci *mantis) +{ + int err = 0; + + dprintk(MANTIS_DEBUG, 1, "Mantis DMA init"); + if (mantis_alloc_buffers(mantis) < 0) { + dprintk(MANTIS_ERROR, 1, "Error allocating DMA buffer"); + + /* Stop RISC Engine */ + mmwrite(0, MANTIS_DMA_CTL); + + goto err; + } + err = mantis_calc_lines(mantis); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "Mantis calc lines failed"); + + goto err; + } + + return 0; +err: + return err; +} +EXPORT_SYMBOL_GPL(mantis_dma_init); + +static inline void mantis_risc_program(struct mantis_pci *mantis) +{ + u32 buf_pos = 0; + u32 line; + + dprintk(MANTIS_DEBUG, 1, "Mantis create RISC program"); + RISC_FLUSH(); + + dprintk(MANTIS_DEBUG, 1, "risc len lines %u, bytes per line %u", + mantis->line_count, mantis->line_bytes); + + for (line = 0; line < mantis->line_count; line++) { + dprintk(MANTIS_DEBUG, 1, "RISC PROG line=[%d]", line); + if (!(buf_pos % MANTIS_BLOCK_BYTES)) { + RISC_INSTR(RISC_WRITE | + RISC_IRQ | + RISC_STATUS(((buf_pos / MANTIS_BLOCK_BYTES) + + (MANTIS_BLOCK_COUNT - 1)) % + MANTIS_BLOCK_COUNT) | + mantis->line_bytes); + } else { + RISC_INSTR(RISC_WRITE | mantis->line_bytes); + } + RISC_INSTR(mantis->buf_dma + buf_pos); + buf_pos += mantis->line_bytes; + } + RISC_INSTR(RISC_JUMP); + RISC_INSTR(mantis->risc_dma); +} + +void mantis_dma_start(struct mantis_pci *mantis) +{ + dprintk(MANTIS_DEBUG, 1, "Mantis Start DMA engine"); + + mantis_risc_program(mantis); + mmwrite(mantis->risc_dma, MANTIS_RISC_START); + mmwrite(mmread(MANTIS_GPIF_ADDR) | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + mmwrite(0, MANTIS_DMA_CTL); + mantis->last_block = mantis->finished_block = 0; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_RISCI, MANTIS_INT_MASK); + + mmwrite(MANTIS_FIFO_EN | MANTIS_DCAP_EN + | MANTIS_RISC_EN, MANTIS_DMA_CTL); + +} + +void mantis_dma_stop(struct mantis_pci *mantis) +{ + u32 stat = 0, mask = 0; + + stat = mmread(MANTIS_INT_STAT); + mask = mmread(MANTIS_INT_MASK); + dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine"); + + mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR); + + mmwrite((mmread(MANTIS_DMA_CTL) & ~(MANTIS_FIFO_EN | + MANTIS_DCAP_EN | + MANTIS_RISC_EN)), MANTIS_DMA_CTL); + + mmwrite(mmread(MANTIS_INT_STAT), MANTIS_INT_STAT); + + mmwrite(mmread(MANTIS_INT_MASK) & ~(MANTIS_INT_RISCI | + MANTIS_INT_RISCEN), MANTIS_INT_MASK); +} + + +void mantis_dma_xfer(unsigned long data) +{ + struct mantis_pci *mantis = (struct mantis_pci *) data; + struct mantis_hwconfig *config = mantis->hwconfig; + + while (mantis->last_block != mantis->finished_block) { + dprintk(MANTIS_DEBUG, 1, "last block=[%d] finished block=[%d]", + mantis->last_block, mantis->finished_block); + + (config->ts_size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) + (&mantis->demux, &mantis->buf_cpu[mantis->last_block * MANTIS_BLOCK_BYTES], MANTIS_BLOCK_BYTES); + mantis->last_block = (mantis->last_block + 1) % MANTIS_BLOCK_COUNT; + } +} diff --git a/drivers/media/dvb/mantis/mantis_dma.h b/drivers/media/dvb/mantis/mantis_dma.h new file mode 100644 index 000000000000..6be00fa82094 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_dma.h @@ -0,0 +1,30 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_DMA_H +#define __MANTIS_DMA_H + +extern int mantis_dma_init(struct mantis_pci *mantis); +extern int mantis_dma_exit(struct mantis_pci *mantis); +extern void mantis_dma_start(struct mantis_pci *mantis); +extern void mantis_dma_stop(struct mantis_pci *mantis); +extern void mantis_dma_xfer(unsigned long data); + +#endif /* __MANTIS_DMA_H */ diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c new file mode 100644 index 000000000000..99d82eec3b03 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_dvb.c @@ -0,0 +1,296 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> +#include <linux/bitops.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/i2c.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_dma.h" +#include "mantis_ca.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + switch (power) { + case POWER_ON: + dprintk(MANTIS_DEBUG, 1, "Power ON"); + gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + gpio_set_bits(mantis, config->power, POWER_ON); + msleep(100); + break; + + case POWER_OFF: + dprintk(MANTIS_DEBUG, 1, "Power OFF"); + gpio_set_bits(mantis, config->power, POWER_OFF); + msleep(100); + break; + + default: + dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_frontend_power); + +void mantis_frontend_soft_reset(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + + dprintk(MANTIS_DEBUG, 1, "Frontend RESET"); + gpio_set_bits(mantis, config->reset, 0); + msleep(100); + gpio_set_bits(mantis, config->reset, 0); + msleep(100); + gpio_set_bits(mantis, config->reset, 1); + msleep(100); + gpio_set_bits(mantis, config->reset, 1); + msleep(100); + + return; +} +EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset); + +static int mantis_frontend_shutdown(struct mantis_pci *mantis) +{ + int err; + + mantis_frontend_soft_reset(mantis); + err = mantis_frontend_power(mantis, POWER_OFF); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err); + return 1; + } + + return 0; +} + +static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds++; + dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d", mantis->feeds); + + if (mantis->feeds == 1) { + dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); + mantis_dma_start(mantis); + } + + return mantis->feeds; +} + +static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct mantis_pci *mantis = dvbdmx->priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(MANTIS_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + + mantis->feeds--; + if (mantis->feeds == 0) { + dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); + mantis_dma_stop(mantis); + } + + return 0; +} + +int __devinit mantis_dvb_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + int result = -1; + + dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter"); + + result = dvb_register_adapter(&mantis->dvb_adapter, + "Mantis DVB adapter", + THIS_MODULE, + &mantis->pdev->dev, + adapter_nr); + + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "Error registering adapter"); + return -ENODEV; + } + + mantis->dvb_adapter.priv = mantis; + mantis->demux.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + + mantis->demux.priv = mantis; + mantis->demux.filternum = 256; + mantis->demux.feednum = 256; + mantis->demux.start_feed = mantis_dvb_start_feed; + mantis->demux.stop_feed = mantis_dvb_stop_feed; + mantis->demux.write_to_decoder = NULL; + + dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init"); + result = dvb_dmx_init(&mantis->demux); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + + goto err0; + } + + mantis->dmxdev.filternum = 256; + mantis->dmxdev.demux = &mantis->demux.dmx; + mantis->dmxdev.capabilities = 0; + dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init"); + + result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); + goto err1; + } + + mantis->fe_hw.source = DMX_FRONTEND_0; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err2; + } + + mantis->fe_mem.source = DMX_MEMORY_FE; + result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err3; + } + + result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err4; + } + + dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); + tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis); + if (mantis->hwconfig) { + result = config->frontend_init(mantis, mantis->fe); + if (result < 0) { + dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!"); + goto err5; + } else { + if (mantis->fe == NULL) { + dprintk(MANTIS_ERROR, 1, "FE <NULL>"); + goto err5; + } + + if (dvb_register_frontend(&mantis->dvb_adapter, mantis->fe)) { + dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed"); + + if (mantis->fe->ops.release) + mantis->fe->ops.release(mantis->fe); + + mantis->fe = NULL; + goto err5; + } + } + } + + return 0; + + /* Error conditions .. */ +err5: + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); +err4: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + +err3: + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + +err2: + dvb_dmxdev_release(&mantis->dmxdev); + +err1: + dvb_dmx_release(&mantis->demux); + +err0: + dvb_unregister_adapter(&mantis->dvb_adapter); + + return result; +} +EXPORT_SYMBOL_GPL(mantis_dvb_init); + +int __devexit mantis_dvb_exit(struct mantis_pci *mantis) +{ + int err; + + if (mantis->fe) { + /* mantis_ca_exit(mantis); */ + err = mantis_frontend_shutdown(mantis); + if (err != 0) + dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err); + dvb_unregister_frontend(mantis->fe); + dvb_frontend_detach(mantis->fe); + } + + tasklet_kill(&mantis->tasklet); + dvb_net_release(&mantis->dvbnet); + + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); + mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw); + + dvb_dmxdev_release(&mantis->dmxdev); + dvb_dmx_release(&mantis->demux); + + dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter"); + dvb_unregister_adapter(&mantis->dvb_adapter); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_dvb_exit); diff --git a/drivers/media/dvb/mantis/mantis_dvb.h b/drivers/media/dvb/mantis/mantis_dvb.h new file mode 100644 index 000000000000..464199db304e --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_dvb.h @@ -0,0 +1,35 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_DVB_H +#define __MANTIS_DVB_H + +enum mantis_power { + POWER_OFF = 0, + POWER_ON = 1 +}; + +extern int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power); +extern void mantis_frontend_soft_reset(struct mantis_pci *mantis); + +extern int mantis_dvb_init(struct mantis_pci *mantis); +extern int mantis_dvb_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_DVB_H */ diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c new file mode 100644 index 000000000000..a7b369a439d6 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_evm.c @@ -0,0 +1,117 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" +#include "mantis_hif.h" +#include "mantis_reg.h" + +static void mantis_hifevm_work(struct work_struct *work) +{ + struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work); + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat, gpif_mask; + + gpif_stat = mmread(MANTIS_GPIF_STATUS); + gpif_mask = mmread(MANTIS_GPIF_IRQCFG); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + if (gpif_stat & MANTIS_CARD_PLUGIN) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Plugin", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_plugin(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } + } else { + if (gpif_stat & MANTIS_CARD_PLUGOUT) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): CAM Unplug", mantis->num); + mmwrite(0xdada0000, MANTIS_CARD_RESET); + mantis_event_cam_unplug(ca); + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + } + + if (mantis->gpif_status & MANTIS_GPIF_EXTIRQ) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Ext IRQ", mantis->num); + + if (mantis->gpif_status & MANTIS_SBUF_WSTO) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Timeout", mantis->num); + + if (mantis->gpif_status & MANTIS_GPIF_OTHERR) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Alignment Error", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OVFLW) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Overflow", mantis->num); + + if (gpif_stat & MANTIS_GPIF_BRRDY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Read Ready", mantis->num); + + if (gpif_stat & MANTIS_GPIF_INTSTAT) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): GPIF IRQ", mantis->num); + + if (gpif_stat & MANTIS_SBUF_EMPTY) + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer Empty", mantis->num); + + if (gpif_stat & MANTIS_SBUF_OPDONE) { + dprintk(MANTIS_DEBUG, 1, "Event Mgr: Adapter(%d) Slot(0): Smart Buffer operation complete", mantis->num); + ca->sbuf_status = MANTIS_SBUF_DATA_AVAIL; + ca->hif_event = MANTIS_SBUF_OPDONE; + wake_up(&ca->hif_opdone_wq); + } +} + +int mantis_evmgr_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Initializing Mantis Host I/F Event manager"); + INIT_WORK(&ca->hif_evm_work, mantis_hifevm_work); + mantis_pcmcia_init(ca); + schedule_work(&ca->hif_evm_work); + mantis_hif_init(ca); + return 0; +} + +void mantis_evmgr_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); + flush_scheduled_work(); + mantis_hif_exit(ca); + mantis_pcmcia_exit(ca); +} diff --git a/drivers/media/dvb/mantis/mantis_hif.c b/drivers/media/dvb/mantis/mantis_hif.c new file mode 100644 index 000000000000..7477dac628b4 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_hif.c @@ -0,0 +1,240 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" + +#include "mantis_hif.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ + +#include "mantis_reg.h" + + +static int mantis_hif_sbuf_opdone_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + int rc = 0; + + if (wait_event_timeout(ca->hif_opdone_wq, + ca->hif_event & MANTIS_SBUF_OPDONE, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Smart buffer operation timeout !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Smart Buffer Operation complete"); + ca->hif_event &= ~MANTIS_SBUF_OPDONE; + return rc; +} + +static int mantis_hif_write_wait(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 opdone = 0, timeout = 0; + int rc = 0; + + if (wait_event_timeout(ca->hif_write_wq, + mantis->gpif_status & MANTIS_GPIF_WRACK, + msecs_to_jiffies(500)) == -ERESTARTSYS) { + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): Write ACK timed out !", mantis->num); + rc = -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Write Acknowledged"); + mantis->gpif_status &= ~MANTIS_GPIF_WRACK; + while (!opdone) { + opdone = (mmread(MANTIS_GPIF_STATUS) & MANTIS_SBUF_OPDONE); + udelay(500); + timeout++; + if (timeout > 100) { + dprintk(MANTIS_ERROR, 1, "Adater(%d) Slot(0): Write operation timed out!", mantis->num); + rc = -ETIMEDOUT; + break; + } + } + dprintk(MANTIS_DEBUG, 1, "HIF Write success"); + return rc; +} + + +int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0, data, count = 4; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(count, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): GPIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + mutex_unlock(&ca->ca_lock); + dprintk(MANTIS_DEBUG, 1, "Mem Read: 0x%02x", data); + return (data >> 24) & 0xff; +} + +int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF Mem Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(slot->slave_cfg, MANTIS_GPIF_CFGSLA); /* Slot0 alone for now */ + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "Mem Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 data, hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Read", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_BRADDR); + mmwrite(1, MANTIS_GPIF_BRBYTES); + udelay(20); + mmwrite(hif_addr | MANTIS_GPIF_HIFRDWRN, MANTIS_GPIF_ADDR); + + if (mantis_hif_sbuf_opdone_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + data = mmread(MANTIS_GPIF_DIN); + dprintk(MANTIS_DEBUG, 1, "I/O Read: 0x%02x", data); + udelay(50); + mutex_unlock(&ca->ca_lock); + + return (u8) data; +} + +int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 hif_addr = 0; + + dprintk(MANTIS_DEBUG, 1, "Adapter(%d) Slot(0): Request HIF I/O Write", mantis->num); + mutex_lock(&ca->ca_lock); + hif_addr &= ~MANTIS_GPIF_PCMCIAREG; + hif_addr &= ~MANTIS_GPIF_HIFRDWRN; + hif_addr |= MANTIS_GPIF_PCMCIAIOM; + hif_addr |= MANTIS_HIF_STATUS; + hif_addr |= addr; + + mmwrite(hif_addr, MANTIS_GPIF_ADDR); + mmwrite(data, MANTIS_GPIF_DOUT); + + if (mantis_hif_write_wait(ca) != 0) { + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Slot(0): HIF Smart Buffer operation failed", mantis->num); + mutex_unlock(&ca->ca_lock); + return -EREMOTEIO; + } + dprintk(MANTIS_DEBUG, 1, "I/O Write: (0x%02x to 0x%02x)", data, addr); + mutex_unlock(&ca->ca_lock); + udelay(50); + + return 0; +} + +int mantis_hif_init(struct mantis_ca *ca) +{ + struct mantis_slot *slot = ca->slot; + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + slot[0].slave_cfg = 0x70773028; + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Initializing Mantis Host Interface", mantis->num); + + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg = MANTIS_MASK_BRRDY | + MANTIS_MASK_WRACK | + MANTIS_MASK_EXTIRQ | + MANTIS_MASK_WSTO | + MANTIS_MASK_OTHERR | + MANTIS_MASK_OVFLW; + + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); + + return 0; +} + +void mantis_hif_exit(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + u32 irqcfg; + + dprintk(MANTIS_ERROR, 1, "Adapter(%d) Exiting Mantis Host Interface", mantis->num); + mutex_lock(&ca->ca_lock); + irqcfg = mmread(MANTIS_GPIF_IRQCFG); + irqcfg &= ~MANTIS_MASK_BRRDY; + mmwrite(irqcfg, MANTIS_GPIF_IRQCFG); + mutex_unlock(&ca->ca_lock); +} diff --git a/drivers/media/dvb/mantis/mantis_hif.h b/drivers/media/dvb/mantis/mantis_hif.h new file mode 100644 index 000000000000..9094f9ed2362 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_hif.h @@ -0,0 +1,29 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_HIF_H +#define __MANTIS_HIF_H + +#define MANTIS_HIF_MEMRD 1 +#define MANTIS_HIF_MEMWR 2 +#define MANTIS_HIF_IOMRD 3 +#define MANTIS_HIF_IOMWR 4 + +#endif /* __MANTIS_HIF_H */ diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c new file mode 100644 index 000000000000..7870bcf9689a --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_i2c.c @@ -0,0 +1,267 @@ +/* + 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. + + 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. +*/ + +#include <asm/io.h> +#include <linux/ioport.h> +#include <linux/pci.h> +#include <linux/i2c.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_i2c.h" + +#define TRIALS 10000 + +static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + u32 rxd, i, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <R>[ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + rxd = (msg->addr << 25) | (1 << 24) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + rxd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(rxd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + + rxd = mmread(MANTIS_I2CDATA_CTL); + msg->buf[i] = (u8)((rxd >> 8) & 0xFF); + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg) +{ + int i; + u32 txd = 0, stat, trials; + + dprintk(MANTIS_INFO, 0, " %s: Address=[0x%02x] <W>[ ", + __func__, msg->addr); + + for (i = 0; i < msg->len; i++) { + dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]); + txd = (msg->addr << 25) | (msg->buf[i] << 8) + | MANTIS_I2C_RATE_3 + | MANTIS_I2C_STOP + | MANTIS_I2C_PGMODE; + + if (i == (msg->len - 1)) + txd &= ~MANTIS_I2C_STOP; + + mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT); + mmwrite(txd, MANTIS_I2CDATA_CTL); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials); + + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CRACK) + break; + } + + dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials); + } + dprintk(MANTIS_INFO, 0, "]\n"); + + return 0; +} + +static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + int ret = 0, i = 0, trials; + u32 stat, data, txd; + struct mantis_pci *mantis; + struct mantis_hwconfig *config; + + mantis = i2c_get_adapdata(adapter); + BUG_ON(!mantis); + config = mantis->hwconfig; + BUG_ON(!config); + + dprintk(MANTIS_DEBUG, 1, "Messages:%d", num); + mutex_lock(&mantis->i2c_lock); + + while (i < num) { + /* Byte MODE */ + if ((config->i2c_mode & MANTIS_BYTE_MODE) && + ((i + 1) < num) && + (msgs[i].len < 2) && + (msgs[i + 1].len < 2) && + (msgs[i + 1].flags & I2C_M_RD)) { + + dprintk(MANTIS_DEBUG, 0, " Byte MODE:\n"); + + /* Read operation */ + txd = msgs[i].addr << 25 | (0x1 << 24) + | (msgs[i].buf[0] << 16) + | MANTIS_I2C_RATE_3; + + mmwrite(txd, MANTIS_I2CDATA_CTL); + /* wait for xfer completion */ + for (trials = 0; trials < TRIALS; trials++) { + stat = mmread(MANTIS_INT_STAT); + if (stat & MANTIS_INT_I2CDONE) + break; + } + + /* check for xfer completion */ + if (stat & MANTIS_INT_I2CDONE) { + /* check xfer was acknowledged */ + if (stat & MANTIS_INT_I2CRACK) { + data = mmread(MANTIS_I2CDATA_CTL); + msgs[i + 1].buf[0] = (data >> 8) & 0xff; + dprintk(MANTIS_DEBUG, 0, " Byte <%d> RXD=0x%02x [%02x]\n", 0x0, data, msgs[i + 1].buf[0]); + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + } else { + /* I/O error */ + dprintk(MANTIS_ERROR, 1, " I/O error, LINE:%d", __LINE__); + ret = -EIO; + break; + } + i += 2; /* Write/Read operation in one go */ + } + + if (i < num) { + if (msgs[i].flags & I2C_M_RD) + ret = mantis_i2c_read(mantis, &msgs[i]); + else + ret = mantis_i2c_write(mantis, &msgs[i]); + + i++; + if (ret < 0) + goto bail_out; + } + + } + + mutex_unlock(&mantis->i2c_lock); + + return num; + +bail_out: + mutex_unlock(&mantis->i2c_lock); + return ret; +} + +static u32 mantis_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static struct i2c_algorithm mantis_algo = { + .master_xfer = mantis_i2c_xfer, + .functionality = mantis_i2c_func, +}; + +int __devinit mantis_i2c_init(struct mantis_pci *mantis) +{ + u32 intstat, intmask; + struct i2c_adapter *i2c_adapter = &mantis->adapter; + struct pci_dev *pdev = mantis->pdev; + + init_waitqueue_head(&mantis->i2c_wq); + mutex_init(&mantis->i2c_lock); + strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); + i2c_set_adapdata(i2c_adapter, mantis); + + i2c_adapter->owner = THIS_MODULE; + i2c_adapter->class = I2C_CLASS_TV_DIGITAL; + i2c_adapter->algo = &mantis_algo; + i2c_adapter->algo_data = NULL; + i2c_adapter->timeout = 500; + i2c_adapter->retries = 3; + i2c_adapter->dev.parent = &pdev->dev; + + mantis->i2c_rc = i2c_add_adapter(i2c_adapter); + if (mantis->i2c_rc < 0) + return mantis->i2c_rc; + + dprintk(MANTIS_DEBUG, 1, "Initializing I2C .."); + + intstat = mmread(MANTIS_INT_STAT); + intmask = 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); + + return 0; +} +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); + + dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter"); + return i2c_del_adapter(&mantis->adapter); +} +EXPORT_SYMBOL_GPL(mantis_i2c_exit); diff --git a/drivers/media/dvb/mantis/mantis_i2c.h b/drivers/media/dvb/mantis/mantis_i2c.h new file mode 100644 index 000000000000..1342df2faed8 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_i2c.h @@ -0,0 +1,30 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_I2C_H +#define __MANTIS_I2C_H + +#define I2C_STOP (1 << 0) +#define I2C_READ (1 << 1) + +extern int mantis_i2c_init(struct mantis_pci *mantis); +extern int mantis_i2c_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_I2C_H */ diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c new file mode 100644 index 000000000000..6a9df779441f --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_input.c @@ -0,0 +1,148 @@ +/* + 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. + + 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. +*/ + +#include <linux/input.h> +#include <media/ir-common.h> +#include <linux/pci.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +static struct ir_scancode 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 }, +}; + +struct ir_scancode_table ir_mantis = { + .scan = mantis_ir_table, + .size = ARRAY_SIZE(mantis_ir_table), +}; +EXPORT_SYMBOL_GPL(ir_mantis); + +int mantis_input_init(struct mantis_pci *mantis) +{ + struct input_dev *rc; + struct ir_input_state rc_state; + char name[80], dev[80]; + int err; + + rc = input_allocate_device(); + if (!rc) { + dprintk(MANTIS_ERROR, 1, "Input device allocate failed"); + return -ENOMEM; + } + + sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name); + sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev)); + + rc->name = name; + rc->phys = dev; + + ir_input_init(rc, &rc_state, IR_TYPE_OTHER); + + rc->id.bustype = BUS_PCI; + rc->id.vendor = mantis->vendor_id; + rc->id.product = mantis->device_id; + rc->id.version = 1; + rc->dev = mantis->pdev->dev; + + err = ir_input_register(rc, &ir_mantis); + if (err) { + dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err); + input_free_device(rc); + return -ENODEV; + } + + mantis->rc = rc; + + return 0; +} + +int mantis_exit(struct mantis_pci *mantis) +{ + struct input_dev *rc = mantis->rc; + + ir_input_unregister(rc); + + return 0; +} diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c new file mode 100644 index 000000000000..de148ded52d8 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_ioc.c @@ -0,0 +1,130 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_ioc.h" + +static int read_eeprom_bytes(struct mantis_pci *mantis, u8 reg, u8 *data, u8 length) +{ + struct i2c_adapter *adapter = &mantis->adapter; + int err; + u8 buf = reg; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = &buf, .len = 1 }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = data, .len = length }, + }; + + err = i2c_transfer(adapter, msg, 2); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", + err, data[0], data[1]); + + return err; + } + + return 0; +} +int mantis_get_mac(struct mantis_pci *mantis) +{ + int err; + u8 mac_addr[6] = {0}; + + err = read_eeprom_bytes(mantis, 0x08, mac_addr, 6); + if (err < 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Mantis EEPROM read error <%d>", err); + + return err; + } + + dprintk(MANTIS_ERROR, 0, + " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n", + mac_addr[0], + mac_addr[1], + mac_addr[2], + mac_addr[3], + mac_addr[4], + mac_addr[5]); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_get_mac); + +/* Turn the given bit on or off. */ +void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) +{ + u32 cur; + + dprintk(MANTIS_DEBUG, 1, "Set Bit <%d> to <%d>", bitpos, value); + cur = mmread(MANTIS_GPIF_ADDR); + if (value) + mantis->gpio_status = cur | (1 << bitpos); + else + mantis->gpio_status = cur & (~(1 << bitpos)); + + dprintk(MANTIS_DEBUG, 1, "GPIO Value <%02x>", mantis->gpio_status); + mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); + mmwrite(0x00, MANTIS_GPIF_DOUT); +} +EXPORT_SYMBOL_GPL(gpio_set_bits); + +int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl) +{ + u32 reg; + + reg = mmread(MANTIS_CONTROL); + switch (stream_ctl) { + case STREAM_TO_HIF: + dprintk(MANTIS_DEBUG, 1, "Set stream to HIF"); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + + case STREAM_TO_CAM: + dprintk(MANTIS_DEBUG, 1, "Set stream to CAM"); + reg |= MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + reg &= 0xff - MANTIS_BYPASS; + mmwrite(reg, MANTIS_CONTROL); + break; + default: + dprintk(MANTIS_ERROR, 1, "Unknown MODE <%02x>", stream_ctl); + return -1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_stream_control); diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h new file mode 100644 index 000000000000..188fe5a81614 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_ioc.h @@ -0,0 +1,51 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_IOC_H +#define __MANTIS_IOC_H + +#define GPIF_A00 0x00 +#define GPIF_A01 0x01 +#define GPIF_A02 0x02 +#define GPIF_A03 0x03 +#define GPIF_A04 0x04 +#define GPIF_A05 0x05 +#define GPIF_A06 0x06 +#define GPIF_A07 0x07 +#define GPIF_A08 0x08 +#define GPIF_A09 0x09 +#define GPIF_A10 0x0a +#define GPIF_A11 0x0b + +#define GPIF_A12 0x0c +#define GPIF_A13 0x0d +#define GPIF_A14 0x0e + +enum mantis_stream_control { + STREAM_TO_HIF = 0, + STREAM_TO_CAM +}; + +extern int mantis_get_mac(struct mantis_pci *mantis); +extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value); + +extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl); + +#endif /* __MANTIS_IOC_H */ diff --git a/drivers/media/dvb/mantis/mantis_link.h b/drivers/media/dvb/mantis/mantis_link.h new file mode 100644 index 000000000000..2a814774a001 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_link.h @@ -0,0 +1,83 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_LINK_H +#define __MANTIS_LINK_H + +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include "dvb_ca_en50221.h" + +enum mantis_sbuf_status { + MANTIS_SBUF_DATA_AVAIL = 1, + MANTIS_SBUF_DATA_EMPTY = 2, + MANTIS_SBUF_DATA_OVFLW = 3 +}; + +struct mantis_slot { + u32 timeout; + u32 slave_cfg; + u32 bar; +}; + +/* Physical layer */ +enum mantis_slot_state { + MODULE_INSERTED = 3, + MODULE_XTRACTED = 4 +}; + +struct mantis_ca { + struct mantis_slot slot[4]; + + struct work_struct hif_evm_work; + + u32 hif_event; + wait_queue_head_t hif_opdone_wq; + wait_queue_head_t hif_brrdyw_wq; + wait_queue_head_t hif_data_wq; + wait_queue_head_t hif_write_wq; /* HIF Write op */ + + enum mantis_sbuf_status sbuf_status; + + enum mantis_slot_state slot_state; + + void *ca_priv; + + struct dvb_ca_en50221 en50221; + struct mutex ca_lock; +}; + +/* CA */ +extern void mantis_event_cam_plugin(struct mantis_ca *ca); +extern void mantis_event_cam_unplug(struct mantis_ca *ca); +extern int mantis_pcmcia_init(struct mantis_ca *ca); +extern void mantis_pcmcia_exit(struct mantis_ca *ca); +extern int mantis_evmgr_init(struct mantis_ca *ca); +extern void mantis_evmgr_exit(struct mantis_ca *ca); + +/* HIF */ +extern int mantis_hif_init(struct mantis_ca *ca); +extern void mantis_hif_exit(struct mantis_ca *ca); +extern int mantis_hif_read_mem(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_mem(struct mantis_ca *ca, u32 addr, u8 data); +extern int mantis_hif_read_iom(struct mantis_ca *ca, u32 addr); +extern int mantis_hif_write_iom(struct mantis_ca *ca, u32 addr, u8 data); + +#endif /* __MANTIS_LINK_H */ diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c new file mode 100644 index 000000000000..6c7534af6b44 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_pci.c @@ -0,0 +1,177 @@ +/* + 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. + + 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. +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <linux/kmod.h> +#include <linux/vmalloc.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/pci.h> + +#include <asm/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include <asm/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_pci.h" + +#define DRIVER_NAME "Mantis Core" + +int __devinit mantis_pci_init(struct mantis_pci *mantis) +{ + u8 revision, latency; + struct mantis_hwconfig *config = mantis->hwconfig; + struct pci_dev *pdev = mantis->pdev; + int err, ret = 0; + + dprintk(MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", + config->model_name, + config->dev_type, + mantis->pdev->bus->number, + PCI_SLOT(mantis->pdev->devfn), + PCI_FUNC(mantis->pdev->devfn)); + + err = pci_enable_device(pdev); + if (err != 0) { + ret = -ENODEV; + dprintk(MANTIS_ERROR, 1, "ERROR: PCI enable failed <%i>", err); + goto fail0; + } + + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (err != 0) { + dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); + ret = -ENOMEM; + goto fail1; + } + + pci_set_master(pdev); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + DRIVER_NAME)) { + + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 Request failed !"); + ret = -ENODEV; + goto fail1; + } + + mantis->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + if (!mantis->mmio) { + dprintk(MANTIS_ERROR, 1, "ERROR: BAR0 remap failed !"); + ret = -ENODEV; + goto fail2; + } + + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + mantis->latency = latency; + mantis->revision = revision; + + dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", + mantis->revision, + mantis->pdev->subsystem_vendor, + mantis->pdev->subsystem_device); + + dprintk(MANTIS_ERROR, 0, + "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", + mantis->pdev->irq, + mantis->latency, + mantis->mantis_addr, + mantis->mmio); + + err = request_irq(pdev->irq, + config->irq_handler, + IRQF_SHARED, + DRIVER_NAME, + mantis); + + if (err != 0) { + + dprintk(MANTIS_ERROR, 1, "ERROR: IRQ registration failed ! <%d>", err); + ret = -ENODEV; + goto fail3; + } + + pci_set_drvdata(pdev, mantis); + return ret; + + /* Error conditions */ +fail3: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> I/O unmap", ret); + if (mantis->mmio) + iounmap(mantis->mmio); + +fail2: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> releasing regions", ret); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + +fail1: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> disabling device", ret); + pci_disable_device(pdev); + +fail0: + dprintk(MANTIS_ERROR, 1, "ERROR: <%d> exiting", ret); + pci_set_drvdata(pdev, NULL); + return ret; +} +EXPORT_SYMBOL_GPL(mantis_pci_init); + +void mantis_pci_exit(struct mantis_pci *mantis) +{ + struct pci_dev *pdev = mantis->pdev; + + dprintk(MANTIS_NOTICE, 1, " mem: 0x%p", mantis->mmio); + free_irq(pdev->irq, mantis); + if (mantis->mmio) { + iounmap(mantis->mmio); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + } + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} +EXPORT_SYMBOL_GPL(mantis_pci_exit); + +MODULE_DESCRIPTION("Mantis PCI DTV bridge driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/mantis/mantis_pci.h b/drivers/media/dvb/mantis/mantis_pci.h new file mode 100644 index 000000000000..65f004519086 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_pci.h @@ -0,0 +1,27 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_PCI_H +#define __MANTIS_PCI_H + +extern int mantis_pci_init(struct mantis_pci *mantis); +extern void mantis_pci_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_PCI_H */ diff --git a/drivers/media/dvb/mantis/mantis_pcmcia.c b/drivers/media/dvb/mantis/mantis_pcmcia.c new file mode 100644 index 000000000000..5cb545b913f6 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_pcmcia.c @@ -0,0 +1,120 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_link.h" /* temporary due to physical layer stuff */ +#include "mantis_reg.h" + +/* + * If Slot state is already PLUG_IN event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_plugin(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_XTRACTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Plugged IN: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0xda000000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGOUT; + gpif_irqcfg &= ~MANTIS_MASK_PLUGIN; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_INSERTED; + } + udelay(100); +} + +/* + * If Slot state is already UN_PLUG event and we are called + * again, definitely it is jitter alone + */ +void mantis_event_cam_unplug(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_irqcfg; + + if (ca->slot_state == MODULE_INSERTED) { + dprintk(MANTIS_DEBUG, 1, "Event: CAM Unplugged: Adapter(%d) Slot(0)", mantis->num); + udelay(50); + mmwrite(0x00da0000, MANTIS_CARD_RESET); + gpif_irqcfg = mmread(MANTIS_GPIF_IRQCFG); + gpif_irqcfg |= MANTIS_MASK_PLUGIN; + gpif_irqcfg &= ~MANTIS_MASK_PLUGOUT; + mmwrite(gpif_irqcfg, MANTIS_GPIF_IRQCFG); + udelay(500); + ca->slot_state = MODULE_XTRACTED; + } + udelay(100); +} + +int mantis_pcmcia_init(struct mantis_ca *ca) +{ + struct mantis_pci *mantis = ca->ca_priv; + + u32 gpif_stat, card_stat; + + mmwrite(mmread(MANTIS_INT_MASK) | MANTIS_INT_IRQ0, MANTIS_INT_MASK); + gpif_stat = mmread(MANTIS_GPIF_STATUS); + card_stat = mmread(MANTIS_GPIF_IRQCFG); + + if (gpif_stat & MANTIS_GPIF_DETSTAT) { + dprintk(MANTIS_DEBUG, 1, "CAM found on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGOUT, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_INSERTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_INSERTED); + } else { + dprintk(MANTIS_DEBUG, 1, "Empty Slot on Adapter(%d) Slot(0)", mantis->num); + mmwrite(card_stat | MANTIS_MASK_PLUGIN, MANTIS_GPIF_IRQCFG); + ca->slot_state = MODULE_XTRACTED; + dvb_ca_en50221_camchange_irq(&ca->en50221, + 0, + DVB_CA_EN50221_CAMCHANGE_REMOVED); + } + + return 0; +} + +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); +} diff --git a/drivers/media/dvb/mantis/mantis_reg.h b/drivers/media/dvb/mantis/mantis_reg.h new file mode 100644 index 000000000000..7761f9dc7fe0 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_reg.h @@ -0,0 +1,197 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_REG_H +#define __MANTIS_REG_H + +/* Interrupts */ +#define MANTIS_INT_STAT 0x00 +#define MANTIS_INT_MASK 0x04 + +#define MANTIS_INT_RISCSTAT (0x0f << 28) +#define MANTIS_INT_RISCEN (0x01 << 27) +#define MANTIS_INT_I2CRACK (0x01 << 26) + +/* #define MANTIS_INT_GPIF (0xff << 12) */ + +#define MANTIS_INT_PCMCIA7 (0x01 << 19) +#define MANTIS_INT_PCMCIA6 (0x01 << 18) +#define MANTIS_INT_PCMCIA5 (0x01 << 17) +#define MANTIS_INT_PCMCIA4 (0x01 << 16) +#define MANTIS_INT_PCMCIA3 (0x01 << 15) +#define MANTIS_INT_PCMCIA2 (0x01 << 14) +#define MANTIS_INT_PCMCIA1 (0x01 << 13) +#define MANTIS_INT_PCMCIA0 (0x01 << 12) +#define MANTIS_INT_IRQ1 (0x01 << 11) +#define MANTIS_INT_IRQ0 (0x01 << 10) +#define MANTIS_INT_OCERR (0x01 << 8) +#define MANTIS_INT_PABORT (0x01 << 7) +#define MANTIS_INT_RIPERR (0x01 << 6) +#define MANTIS_INT_PPERR (0x01 << 5) +#define MANTIS_INT_FTRGT (0x01 << 3) +#define MANTIS_INT_RISCI (0x01 << 1) +#define MANTIS_INT_I2CDONE (0x01 << 0) + +/* DMA */ +#define MANTIS_DMA_CTL 0x08 +#define MANTIS_GPIF_RD (0xff << 24) +#define MANTIS_GPIF_WR (0xff << 16) +#define MANTIS_CPU_DO (0x01 << 10) +#define MANTIS_DRV_DO (0x01 << 9) +#define MANTIS_I2C_RD (0x01 << 7) +#define MANTIS_I2C_WR (0x01 << 6) +#define MANTIS_DCAP_MODE (0x01 << 5) +#define MANTIS_FIFO_TP_4 (0x00 << 3) +#define MANTIS_FIFO_TP_8 (0x01 << 3) +#define MANTIS_FIFO_TP_16 (0x02 << 3) +#define MANTIS_FIFO_EN (0x01 << 2) +#define MANTIS_DCAP_EN (0x01 << 1) +#define MANTIS_RISC_EN (0x01 << 0) + +/* DEBUG */ +#define MANTIS_DEBUGREG 0x0c +#define MANTIS_DATINV (0x0e << 7) +#define MANTIS_TOP_DEBUGSEL (0x07 << 4) +#define MANTIS_PCMCIA_DEBUGSEL (0x0f << 0) + +#define MANTIS_RISC_START 0x10 +#define MANTIS_RISC_PC 0x14 + +/* I2C */ +#define MANTIS_I2CDATA_CTL 0x18 +#define MANTIS_I2C_RATE_1 (0x00 << 6) +#define MANTIS_I2C_RATE_2 (0x01 << 6) +#define MANTIS_I2C_RATE_3 (0x02 << 6) +#define MANTIS_I2C_RATE_4 (0x03 << 6) +#define MANTIS_I2C_STOP (0x01 << 5) +#define MANTIS_I2C_PGMODE (0x01 << 3) + +/* DATA */ +#define MANTIS_CMD_DATA_R1 0x20 +#define MANTIS_CMD_DATA_3 (0xff << 24) +#define MANTIS_CMD_DATA_2 (0xff << 16) +#define MANTIS_CMD_DATA_1 (0xff << 8) +#define MANTIS_CMD_DATA_0 (0xff << 0) + +#define MANTIS_CMD_DATA_R2 0x24 +#define MANTIS_CMD_DATA_7 (0xff << 24) +#define MANTIS_CMD_DATA_6 (0xff << 16) +#define MANTIS_CMD_DATA_5 (0xff << 8) +#define MANTIS_CMD_DATA_4 (0xff << 0) + +#define MANTIS_CONTROL 0x28 +#define MANTIS_DET (0x01 << 7) +#define MANTIS_DAT_CF_EN (0x01 << 6) +#define MANTIS_ACS (0x03 << 4) +#define MANTIS_VCCEN (0x01 << 3) +#define MANTIS_BYPASS (0x01 << 2) +#define MANTIS_MRST (0x01 << 1) +#define MANTIS_CRST_INT (0x01 << 0) + +#define MANTIS_GPIF_CFGSLA 0x84 +#define MANTIS_GPIF_WAITSMPL (0x07 << 28) +#define MANTIS_GPIF_BYTEADDRSUB (0x01 << 25) +#define MANTIS_GPIF_WAITPOL (0x01 << 24) +#define MANTIS_GPIF_NCDELAY (0x07 << 20) +#define MANTIS_GPIF_RW2CSDELAY (0x07 << 16) +#define MANTIS_GPIF_SLFTIMEDMODE (0x01 << 15) +#define MANTIS_GPIF_SLFTIMEDDELY (0x7f << 8) +#define MANTIS_GPIF_DEVTYPE (0x07 << 4) +#define MANTIS_GPIF_BIGENDIAN (0x01 << 3) +#define MANTIS_GPIF_FETCHCMD (0x03 << 1) +#define MANTIS_GPIF_HWORDDEV (0x01 << 0) + +#define MANTIS_GPIF_WSTOPER 0x90 +#define MANTIS_GPIF_WSTOPERWREN3 (0x01 << 31) +#define MANTIS_GPIF_PARBOOTN (0x01 << 29) +#define MANTIS_GPIF_WSTOPERSLID3 (0x1f << 24) +#define MANTIS_GPIF_WSTOPERWREN2 (0x01 << 23) +#define MANTIS_GPIF_WSTOPERSLID2 (0x1f << 16) +#define MANTIS_GPIF_WSTOPERWREN1 (0x01 << 15) +#define MANTIS_GPIF_WSTOPERSLID1 (0x1f << 8) +#define MANTIS_GPIF_WSTOPERWREN0 (0x01 << 7) +#define MANTIS_GPIF_WSTOPERSLID0 (0x1f << 0) + +#define MANTIS_GPIF_CS2RW 0x94 +#define MANTIS_GPIF_CS2RWWREN3 (0x01 << 31) +#define MANTIS_GPIF_CS2RWDELY3 (0x3f << 24) +#define MANTIS_GPIF_CS2RWWREN2 (0x01 << 23) +#define MANTIS_GPIF_CS2RWDELY2 (0x3f << 16) +#define MANTIS_GPIF_CS2RWWREN1 (0x01 << 15) +#define MANTIS_GPIF_CS2RWDELY1 (0x3f << 8) +#define MANTIS_GPIF_CS2RWWREN0 (0x01 << 7) +#define MANTIS_GPIF_CS2RWDELY0 (0x3f << 0) + +#define MANTIS_GPIF_IRQCFG 0x98 +#define MANTIS_GPIF_IRQPOL (0x01 << 8) +#define MANTIS_MASK_WRACK (0x01 << 7) +#define MANTIS_MASK_BRRDY (0x01 << 6) +#define MANTIS_MASK_OVFLW (0x01 << 5) +#define MANTIS_MASK_OTHERR (0x01 << 4) +#define MANTIS_MASK_WSTO (0x01 << 3) +#define MANTIS_MASK_EXTIRQ (0x01 << 2) +#define MANTIS_MASK_PLUGIN (0x01 << 1) +#define MANTIS_MASK_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_STATUS 0x9c +#define MANTIS_SBUF_KILLOP (0x01 << 15) +#define MANTIS_SBUF_OPDONE (0x01 << 14) +#define MANTIS_SBUF_EMPTY (0x01 << 13) +#define MANTIS_GPIF_DETSTAT (0x01 << 9) +#define MANTIS_GPIF_INTSTAT (0x01 << 8) +#define MANTIS_GPIF_WRACK (0x01 << 7) +#define MANTIS_GPIF_BRRDY (0x01 << 6) +#define MANTIS_SBUF_OVFLW (0x01 << 5) +#define MANTIS_GPIF_OTHERR (0x01 << 4) +#define MANTIS_SBUF_WSTO (0x01 << 3) +#define MANTIS_GPIF_EXTIRQ (0x01 << 2) +#define MANTIS_CARD_PLUGIN (0x01 << 1) +#define MANTIS_CARD_PLUGOUT (0x01 << 0) + +#define MANTIS_GPIF_BRADDR 0xa0 +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_BR_ADDR (0xfffffff << 0) + +#define MANTIS_GPIF_BRBYTES 0xa4 +#define MANTIS_GPIF_BRCNT (0xfff << 0) + +#define MANTIS_PCMCIA_RESET 0xa8 +#define MANTIS_PCMCIA_RSTVAL (0xff << 0) + +#define MANTIS_CARD_RESET 0xac + +#define MANTIS_GPIF_ADDR 0xb0 +#define MANTIS_GPIF_HIFRDWRN (0x01 << 31) +#define MANTIS_GPIF_PCMCIAREG (0x01 << 27) +#define MANTIS_GPIF_PCMCIAIOM (0x01 << 26) +#define MANTIS_GPIF_HIFADDR (0xfffffff << 0) + +#define MANTIS_GPIF_DOUT 0xb4 +#define MANTIS_GPIF_HIFDOUT (0xfffffff << 0) + +#define MANTIS_GPIF_DIN 0xb8 +#define MANTIS_GPIF_HIFDIN (0xfffffff << 0) + +#define MANTIS_GPIF_SPARE 0xbc +#define MANTIS_GPIF_LOGICRD (0xffff << 16) +#define MANTIS_GPIF_LOGICRW (0xffff << 0) + +#endif /* __MANTIS_REG_H */ diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c new file mode 100644 index 000000000000..7d2f2398fa8b --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_uart.c @@ -0,0 +1,186 @@ +/* + 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. + + 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. +*/ + +#include <linux/kernel.h> +#include <linux/spinlock.h> + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_reg.h" +#include "mantis_uart.h" + +struct mantis_uart_params { + enum mantis_baud baud_rate; + enum mantis_parity parity; +}; + +static struct { + char string[7]; +} rates[5] = { + { "9600" }, + { "19200" }, + { "38400" }, + { "57600" }, + { "115200" } +}; + +static struct { + char string[5]; +} parity[3] = { + { "NONE" }, + { "ODD" }, + { "EVEN" } +}; + +#define UART_MAX_BUF 16 + +int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + u32 stat = 0, i; + + /* get data */ + for (i = 0; i < (config->bytes + 1); i++) { + + 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, 1, "Reading ... <%02x>", data[i] & 0x3f); + + if (data[i] & (1 << 7)) { + dprintk(MANTIS_ERROR, 1, "UART framing error"); + return -EINVAL; + } + if (data[i] & (1 << 6)) { + dprintk(MANTIS_ERROR, 1, "UART parity error"); + return -EINVAL; + } + } + + return 0; +} + +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; + + mantis_uart_read(mantis, buf); + + for (i = 0; i < (config->bytes + 1); i++) + dprintk(MANTIS_INFO, 1, "UART BUF:%d <%02x> ", i, buf[i]); + + dprintk(MANTIS_DEBUG, 0, "\n"); +} + +static int mantis_uart_setup(struct mantis_pci *mantis, + struct mantis_uart_params *params) +{ + u32 reg; + + mmwrite((mmread(MANTIS_UART_CTL) | (params->parity & 0x3)), MANTIS_UART_CTL); + + reg = mmread(MANTIS_UART_BAUD); + + switch (params->baud_rate) { + case MANTIS_BAUD_9600: + reg |= 0xd8; + break; + case MANTIS_BAUD_19200: + reg |= 0x6c; + break; + case MANTIS_BAUD_38400: + reg |= 0x36; + break; + case MANTIS_BAUD_57600: + reg |= 0x23; + break; + case MANTIS_BAUD_115200: + reg |= 0x11; + break; + default: + return -EINVAL; + } + + mmwrite(reg, MANTIS_UART_BAUD); + + return 0; +} + +int mantis_uart_init(struct mantis_pci *mantis) +{ + struct mantis_hwconfig *config = mantis->hwconfig; + struct mantis_uart_params params; + + /* default parity: */ + params.baud_rate = config->baud_rate; + params.parity = config->parity; + dprintk(MANTIS_INFO, 1, "Initializing UART @ %sbps parity:%s", + 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 */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); + + mantis_uart_setup(mantis, ¶ms); + + /* default 1 byte */ + mmwrite((mmread(MANTIS_UART_BAUD) | (config->bytes << 8)), MANTIS_UART_BAUD); + + /* flush buffer */ + 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); + + schedule_work(&mantis->uart_work); + dprintk(MANTIS_DEBUG, 1, "UART succesfully initialized"); + + return 0; +} +EXPORT_SYMBOL_GPL(mantis_uart_init); + +void mantis_uart_exit(struct mantis_pci *mantis) +{ + /* disable interrupt */ + mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); +} +EXPORT_SYMBOL_GPL(mantis_uart_exit); diff --git a/drivers/media/dvb/mantis/mantis_uart.h b/drivers/media/dvb/mantis/mantis_uart.h new file mode 100644 index 000000000000..ffb62a0a5a13 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_uart.h @@ -0,0 +1,58 @@ +/* + 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. + + 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. +*/ + +#ifndef __MANTIS_UART_H +#define __MANTIS_UART_H + +#define MANTIS_UART_CTL 0xe0 +#define MANTIS_UART_RXINT (1 << 4) +#define MANTIS_UART_RXFLUSH (1 << 2) + +#define MANTIS_UART_RXD 0xe8 +#define MANTIS_UART_BAUD 0xec + +#define MANTIS_UART_STAT 0xf0 +#define MANTIS_UART_RXFIFO_DATA (1 << 7) +#define MANTIS_UART_RXFIFO_EMPTY (1 << 6) +#define MANTIS_UART_RXFIFO_FULL (1 << 3) +#define MANTIS_UART_FRAME_ERR (1 << 2) +#define MANTIS_UART_PARITY_ERR (1 << 1) +#define MANTIS_UART_RXTHRESH_INT (1 << 0) + +enum mantis_baud { + MANTIS_BAUD_9600 = 0, + MANTIS_BAUD_19200, + MANTIS_BAUD_38400, + MANTIS_BAUD_57600, + MANTIS_BAUD_115200 +}; + +enum mantis_parity { + MANTIS_PARITY_NONE = 0, + MANTIS_PARITY_EVEN, + MANTIS_PARITY_ODD, +}; + +struct mantis_pci; + +extern int mantis_uart_init(struct mantis_pci *mantis); +extern void mantis_uart_exit(struct mantis_pci *mantis); + +#endif /* __MANTIS_UART_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c new file mode 100644 index 000000000000..4a723bda0031 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1033.c @@ -0,0 +1,212 @@ +/* + Mantis VP-1033 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "stv0299.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1033.h" +#include "mantis_reg.h" + +u8 lgtdqcs001f_inittab[] = { + 0x01, 0x15, + 0x02, 0x00, + 0x03, 0x00, + 0x04, 0x2a, + 0x05, 0x85, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0x00, + 0x0c, 0x01, + 0x0d, 0x81, + 0x0e, 0x44, + 0x0f, 0x94, + 0x10, 0x3c, + 0x11, 0x84, + 0x12, 0xb9, + 0x13, 0xb5, + 0x14, 0x4f, + 0x15, 0xc9, + 0x16, 0x80, + 0x17, 0x36, + 0x18, 0xfb, + 0x19, 0xcf, + 0x1a, 0xbc, + 0x1c, 0x2b, + 0x1d, 0x27, + 0x1e, 0x00, + 0x1f, 0x0b, + 0x20, 0xa1, + 0x21, 0x60, + 0x22, 0x00, + 0x23, 0x00, + 0x28, 0x00, + 0x29, 0x28, + 0x2a, 0x14, + 0x2b, 0x0f, + 0x2c, 0x09, + 0x2d, 0x05, + 0x31, 0x1f, + 0x32, 0x19, + 0x33, 0xfc, + 0x34, 0x13, + 0xff, 0xff, +}; + +#define MANTIS_MODEL_NAME "VP-1033" +#define MANTIS_DEV_TYPE "DVB-S/DSS" + +int lgtdqcs001f_tuner_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[4]; + u32 div; + + + struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)}; + + div = params->frequency / 250; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x83; + buf[3] = 0xc0; + + if (params->frequency < 1531000) + buf[3] |= 0x04; + else + buf[3] &= ~0x04; + if (i2c_transfer(adapter, &msg, 1) < 0) { + dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed"); + return -EIO; + } + msleep_interruptible(100); + + return 0; +} + +int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; + + if (srate < 1500000) { + aclk = 0xb7; + bclk = 0x47; + } else if (srate < 3000000) { + aclk = 0xb7; + bclk = 0x4b; + } else if (srate < 7000000) { + aclk = 0xb7; + bclk = 0x4f; + } else if (srate < 14000000) { + aclk = 0xb7; + bclk = 0x53; + } else if (srate < 30000000) { + aclk = 0xb6; + bclk = 0x53; + } else if (srate < 45000000) { + aclk = 0xb4; + bclk = 0x51; + } + stv0299_writereg(fe, 0x13, aclk); + stv0299_writereg(fe, 0x14, bclk); + + stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg(fe, 0x21, ratio & 0xf0); + + return 0; +} + +struct stv0299_config lgtdqcs001f_config = { + .demod_address = 0x68, + .inittab = lgtdqcs001f_inittab, + .mclk = 88000000UL, + .invert = 0, + .skip_reinit = 0, + .volt13_op0_op1 = STV0299_VOLT13_OP0, + .min_delay_ms = 100, + .set_symbol_rate = lgtdqcs001f_set_symbol_rate, +}; + +static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)"); + fe = stv0299_attach(&lgtdqcs001f_config, adapter); + + if (fe) { + fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set; + dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x", + lgtdqcs001f_config.demod_address); + + dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp1033.h b/drivers/media/dvb/mantis/mantis_vp1033.h new file mode 100644 index 000000000000..7daaa1bf127d --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1033.h @@ -0,0 +1,30 @@ +/* + Mantis VP-1033 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. + + 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. +*/ + +#ifndef __MANTIS_VP1033_H +#define __MANTIS_VP1033_H + +#include "mantis_common.h" + +#define MANTIS_VP_1033_DVB_S 0x0016 + +extern struct mantis_hwconfig vp1033_config; + +#endif /* __MANTIS_VP1033_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c new file mode 100644 index 000000000000..8e6ae558ee57 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1034.c @@ -0,0 +1,119 @@ +/* + Mantis VP-1034 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mb86a16.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1034.h" +#include "mantis_reg.h" + +struct mb86a16_config vp1034_mb86a16_config = { + .demod_address = 0x08, + .set_voltage = vp1034_set_voltage, +}; + +#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) +{ + struct mantis_pci *mantis = fe->dvb->priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(MANTIS_ERROR, 1, "Polarization=[13V]"); + gpio_set_bits(mantis, 13, 1); + gpio_set_bits(mantis, 14, 0); + break; + case SEC_VOLTAGE_18: + dprintk(MANTIS_ERROR, 1, "Polarization=[18V]"); + gpio_set_bits(mantis, 13, 1); + gpio_set_bits(mantis, 14, 1); + break; + case SEC_VOLTAGE_OFF: + dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN"); + break; + default: + dprintk(MANTIS_ERROR, 1, "Invalid = (%d)", (u32) voltage); + return -EINVAL; + } + mmwrite(0x00, MANTIS_GPIF_DOUT); + + return 0; +} + +static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); + fe = mb86a16_attach(&vp1034_mb86a16_config, adapter); + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found MB86A16 DVB-S/DSS frontend @0x%02x", + vp1034_mb86a16_config.demod_address); + + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1034_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1034_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp1034.h b/drivers/media/dvb/mantis/mantis_vp1034.h new file mode 100644 index 000000000000..323f38ef8e3d --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1034.h @@ -0,0 +1,33 @@ +/* + Mantis VP-1034 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. + + 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. +*/ + +#ifndef __MANTIS_VP1034_H +#define __MANTIS_VP1034_H + +#include "dvb_frontend.h" +#include "mantis_common.h" + + +#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); + +#endif /* __MANTIS_VP1034_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c new file mode 100644 index 000000000000..515346dd31d0 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1041.c @@ -0,0 +1,358 @@ +/* + Mantis VP-1041 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp1041.h" +#include "stb0899_reg.h" +#include "stb0899_drv.h" +#include "stb0899_cfg.h" +#include "stb6100_cfg.h" +#include "stb6100.h" +#include "lnbp21.h" + +#define MANTIS_MODEL_NAME "VP-1041" +#define MANTIS_DEV_TYPE "DSS/DVB-S/DVB-S2" + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_1[] = { + + /* 0x0000000b, *//* SYSREG */ + { STB0899_DEV_ID , 0x30 }, + { STB0899_DISCNTRL1 , 0x32 }, + { STB0899_DISCNTRL2 , 0x80 }, + { STB0899_DISRX_ST0 , 0x04 }, + { STB0899_DISRX_ST1 , 0x00 }, + { STB0899_DISPARITY , 0x00 }, + { STB0899_DISFIFO , 0x00 }, + { STB0899_DISSTATUS , 0x20 }, + { STB0899_DISF22 , 0x99 }, + { STB0899_DISF22RX , 0xa8 }, + /* SYSREG ? */ + { STB0899_ACRPRESC , 0x11 }, + { STB0899_ACRDIV1 , 0x0a }, + { STB0899_ACRDIV2 , 0x05 }, + { STB0899_DACR1 , 0x00 }, + { STB0899_DACR2 , 0x00 }, + { STB0899_OUTCFG , 0x00 }, + { STB0899_MODECFG , 0x00 }, + { STB0899_IRQSTATUS_3 , 0xfe }, + { STB0899_IRQSTATUS_2 , 0x03 }, + { STB0899_IRQSTATUS_1 , 0x7c }, + { STB0899_IRQSTATUS_0 , 0xf4 }, + { STB0899_IRQMSK_3 , 0xf3 }, + { STB0899_IRQMSK_2 , 0xfc }, + { STB0899_IRQMSK_1 , 0xff }, + { STB0899_IRQMSK_0 , 0xff }, + { STB0899_IRQCFG , 0x00 }, + { STB0899_I2CCFG , 0x88 }, + { STB0899_I2CRPT , 0x58 }, + { STB0899_IOPVALUE5 , 0x00 }, + { STB0899_IOPVALUE4 , 0x33 }, + { STB0899_IOPVALUE3 , 0x6d }, + { STB0899_IOPVALUE2 , 0x90 }, + { STB0899_IOPVALUE1 , 0x60 }, + { STB0899_IOPVALUE0 , 0x00 }, + { STB0899_GPIO00CFG , 0x82 }, + { STB0899_GPIO01CFG , 0x82 }, + { STB0899_GPIO02CFG , 0x82 }, + { STB0899_GPIO03CFG , 0x82 }, + { STB0899_GPIO04CFG , 0x82 }, + { STB0899_GPIO05CFG , 0x82 }, + { STB0899_GPIO06CFG , 0x82 }, + { STB0899_GPIO07CFG , 0x82 }, + { STB0899_GPIO08CFG , 0x82 }, + { STB0899_GPIO09CFG , 0x82 }, + { STB0899_GPIO10CFG , 0x82 }, + { STB0899_GPIO11CFG , 0x82 }, + { STB0899_GPIO12CFG , 0x82 }, + { STB0899_GPIO13CFG , 0x82 }, + { STB0899_GPIO14CFG , 0x82 }, + { STB0899_GPIO15CFG , 0x82 }, + { STB0899_GPIO16CFG , 0x82 }, + { STB0899_GPIO17CFG , 0x82 }, + { STB0899_GPIO18CFG , 0x82 }, + { STB0899_GPIO19CFG , 0x82 }, + { STB0899_GPIO20CFG , 0x82 }, + { STB0899_SDATCFG , 0xb8 }, + { STB0899_SCLTCFG , 0xba }, + { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ + { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ + { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ + { STB0899_DIRCLKCFG , 0x82 }, + { STB0899_CLKOUT27CFG , 0x7e }, + { STB0899_STDBYCFG , 0x82 }, + { STB0899_CS0CFG , 0x82 }, + { STB0899_CS1CFG , 0x82 }, + { STB0899_DISEQCOCFG , 0x20 }, + { STB0899_GPIO32CFG , 0x82 }, + { STB0899_GPIO33CFG , 0x82 }, + { STB0899_GPIO34CFG , 0x82 }, + { STB0899_GPIO35CFG , 0x82 }, + { STB0899_GPIO36CFG , 0x82 }, + { STB0899_GPIO37CFG , 0x82 }, + { STB0899_GPIO38CFG , 0x82 }, + { STB0899_GPIO39CFG , 0x82 }, + { STB0899_NCOARSE , 0x17 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ + { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ + { STB0899_FILTCTRL , 0x00 }, + { STB0899_SYSCTRL , 0x01 }, + { STB0899_STOPCLK1 , 0x20 }, + { STB0899_STOPCLK2 , 0x00 }, + { STB0899_INTBUFSTATUS , 0x00 }, + { STB0899_INTBUFCTRL , 0x0a }, + { 0xffff , 0xff }, +}; + +static const struct stb0899_s1_reg vp1041_stb0899_s1_init_3[] = { + { STB0899_DEMOD , 0x00 }, + { STB0899_RCOMPC , 0xc9 }, + { STB0899_AGC1CN , 0x01 }, + { STB0899_AGC1REF , 0x10 }, + { STB0899_RTC , 0x23 }, + { STB0899_TMGCFG , 0x4e }, + { STB0899_AGC2REF , 0x34 }, + { STB0899_TLSR , 0x84 }, + { STB0899_CFD , 0xf7 }, + { STB0899_ACLC , 0x87 }, + { STB0899_BCLC , 0x94 }, + { STB0899_EQON , 0x41 }, + { STB0899_LDT , 0xf1 }, + { STB0899_LDT2 , 0xe3 }, + { STB0899_EQUALREF , 0xb4 }, + { STB0899_TMGRAMP , 0x10 }, + { STB0899_TMGTHD , 0x30 }, + { STB0899_IDCCOMP , 0xfd }, + { STB0899_QDCCOMP , 0xff }, + { STB0899_POWERI , 0x0c }, + { STB0899_POWERQ , 0x0f }, + { STB0899_RCOMP , 0x6c }, + { STB0899_AGCIQIN , 0x80 }, + { STB0899_AGC2I1 , 0x06 }, + { STB0899_AGC2I2 , 0x00 }, + { STB0899_TLIR , 0x30 }, + { STB0899_RTF , 0x7f }, + { STB0899_DSTATUS , 0x00 }, + { STB0899_LDI , 0xbc }, + { STB0899_CFRM , 0xea }, + { STB0899_CFRL , 0x31 }, + { STB0899_NIRM , 0x2b }, + { STB0899_NIRL , 0x80 }, + { STB0899_ISYMB , 0x1d }, + { STB0899_QSYMB , 0xa6 }, + { STB0899_SFRH , 0x2f }, + { STB0899_SFRM , 0x68 }, + { STB0899_SFRL , 0x40 }, + { STB0899_SFRUPH , 0x2f }, + { STB0899_SFRUPM , 0x68 }, + { STB0899_SFRUPL , 0x40 }, + { STB0899_EQUAI1 , 0x02 }, + { STB0899_EQUAQ1 , 0xff }, + { STB0899_EQUAI2 , 0x04 }, + { STB0899_EQUAQ2 , 0x05 }, + { STB0899_EQUAI3 , 0x02 }, + { STB0899_EQUAQ3 , 0xfd }, + { STB0899_EQUAI4 , 0x03 }, + { STB0899_EQUAQ4 , 0x07 }, + { STB0899_EQUAI5 , 0x08 }, + { STB0899_EQUAQ5 , 0xf5 }, + { STB0899_DSTATUS2 , 0x00 }, + { STB0899_VSTATUS , 0x00 }, + { STB0899_VERROR , 0x86 }, + { STB0899_IQSWAP , 0x2a }, + { STB0899_ECNT1M , 0x00 }, + { STB0899_ECNT1L , 0x00 }, + { STB0899_ECNT2M , 0x00 }, + { STB0899_ECNT2L , 0x00 }, + { STB0899_ECNT3M , 0x0a }, + { STB0899_ECNT3L , 0xad }, + { STB0899_FECAUTO1 , 0x06 }, + { STB0899_FECM , 0x01 }, + { STB0899_VTH12 , 0xb0 }, + { STB0899_VTH23 , 0x7a }, + { STB0899_VTH34 , 0x58 }, + { STB0899_VTH56 , 0x38 }, + { STB0899_VTH67 , 0x34 }, + { STB0899_VTH78 , 0x24 }, + { STB0899_PRVIT , 0xff }, + { STB0899_VITSYNC , 0x19 }, + { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ + { STB0899_TSULC , 0x42 }, + { STB0899_RSLLC , 0x41 }, + { STB0899_TSLPL , 0x12 }, + { STB0899_TSCFGH , 0x0c }, + { STB0899_TSCFGM , 0x00 }, + { STB0899_TSCFGL , 0x00 }, + { STB0899_TSOUT , 0x69 }, /* 0x0d for CAM */ + { STB0899_RSSYNCDEL , 0x00 }, + { STB0899_TSINHDELH , 0x02 }, + { STB0899_TSINHDELM , 0x00 }, + { STB0899_TSINHDELL , 0x00 }, + { STB0899_TSLLSTKM , 0x1b }, + { STB0899_TSLLSTKL , 0xb3 }, + { STB0899_TSULSTKM , 0x00 }, + { STB0899_TSULSTKL , 0x00 }, + { STB0899_PCKLENUL , 0xbc }, + { STB0899_PCKLENLL , 0xcc }, + { STB0899_RSPCKLEN , 0xbd }, + { STB0899_TSSTATUS , 0x90 }, + { STB0899_ERRCTRL1 , 0xb6 }, + { STB0899_ERRCTRL2 , 0x95 }, + { STB0899_ERRCTRL3 , 0x8d }, + { STB0899_DMONMSK1 , 0x27 }, + { STB0899_DMONMSK0 , 0x03 }, + { STB0899_DEMAPVIT , 0x5c }, + { STB0899_PLPARM , 0x19 }, + { STB0899_PDELCTRL , 0x48 }, + { STB0899_PDELCTRL2 , 0x00 }, + { STB0899_BBHCTRL1 , 0x00 }, + { STB0899_BBHCTRL2 , 0x00 }, + { STB0899_HYSTTHRESH , 0x77 }, + { STB0899_MATCSTM , 0x00 }, + { STB0899_MATCSTL , 0x00 }, + { STB0899_UPLCSTM , 0x00 }, + { STB0899_UPLCSTL , 0x00 }, + { STB0899_DFLCSTM , 0x00 }, + { STB0899_DFLCSTL , 0x00 }, + { STB0899_SYNCCST , 0x00 }, + { STB0899_SYNCDCSTM , 0x00 }, + { STB0899_SYNCDCSTL , 0x00 }, + { STB0899_ISI_ENTRY , 0x00 }, + { STB0899_ISI_BIT_EN , 0x00 }, + { STB0899_MATSTRM , 0xf0 }, + { STB0899_MATSTRL , 0x02 }, + { STB0899_UPLSTRM , 0x45 }, + { STB0899_UPLSTRL , 0x60 }, + { STB0899_DFLSTRM , 0xe3 }, + { STB0899_DFLSTRL , 0x00 }, + { STB0899_SYNCSTR , 0x47 }, + { STB0899_SYNCDSTRM , 0x05 }, + { STB0899_SYNCDSTRL , 0x18 }, + { STB0899_CFGPDELSTATUS1 , 0x19 }, + { STB0899_CFGPDELSTATUS2 , 0x2b }, + { STB0899_BBFERRORM , 0x00 }, + { STB0899_BBFERRORL , 0x01 }, + { STB0899_UPKTERRORM , 0x00 }, + { STB0899_UPKTERRORL , 0x00 }, + { 0xffff , 0xff }, +}; + +struct stb0899_config vp1041_stb0899_config = { + .init_dev = vp1041_stb0899_s1_init_1, + .init_s2_demod = stb0899_s2_init_2, + .init_s1_demod = vp1041_stb0899_s1_init_3, + .init_s2_fec = stb0899_s2_init_4, + .init_tst = stb0899_s1_init_5, + + .demod_address = 0x68, /* 0xd0 >> 1 */ + + .xtal_freq = 27000000, + .inversion = IQ_SWAP_ON, /* 1 */ + + .lo_clk = 76500000, + .hi_clk = 99000000, + + .esno_ave = STB0899_DVBS2_ESNO_AVE, + .esno_quant = STB0899_DVBS2_ESNO_QUANT, + .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, + .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, + .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, + .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, + .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, + .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, + .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, + + .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, + .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, + .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, + .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, + + .tuner_get_frequency = stb6100_get_frequency, + .tuner_set_frequency = stb6100_set_frequency, + .tuner_set_bandwidth = stb6100_set_bandwidth, + .tuner_get_bandwidth = stb6100_get_bandwidth, + .tuner_set_rfsiggain = NULL, +}; + +struct stb6100_config vp1041_stb6100_config = { + .tuner_address = 0x60, + .refclock = 27000000, +}; + +static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter); + if (mantis->fe) { + dprintk(MANTIS_ERROR, 1, + "found STB0899 DVB-S/DVB-S2 frontend @0x%02x", + vp1041_stb0899_config.demod_address); + + if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) { + if (!lnbp21_attach(mantis->fe, adapter, 0, 0)) + dprintk(MANTIS_ERROR, 1, "No LNBP21 found!"); + } + } else { + return -EREMOTEIO; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp1041_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp1041_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp1041.h b/drivers/media/dvb/mantis/mantis_vp1041.h new file mode 100644 index 000000000000..1ae5b3de8081 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp1041.h @@ -0,0 +1,33 @@ +/* + Mantis VP-1041 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. + + 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. +*/ + +#ifndef __MANTIS_VP1041_H +#define __MANTIS_VP1041_H + +#include "mantis_common.h" + +#define MANTIS_VP_1041_DVB_S2 0x0031 +#define SKYSTAR_HD2_10 0x0001 +#define SKYSTAR_HD2_20 0x0003 +#define CINERGY_S2_PCI_HD 0x1179 + +extern struct mantis_hwconfig vp1041_config; + +#endif /* __MANTIS_VP1041_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c new file mode 100644 index 000000000000..10ce81790a8c --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp2033.c @@ -0,0 +1,187 @@ +/* + Mantis VP-2033 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2033.h" + +#define MANTIS_MODEL_NAME "VP-2033" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2033_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2033_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = tda10021_attach(&vp2033_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } else { + fe = tda10023_attach(&vp2033_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2033_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2033_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2033_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp2033.h b/drivers/media/dvb/mantis/mantis_vp2033.h new file mode 100644 index 000000000000..c55242b79d54 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp2033.h @@ -0,0 +1,30 @@ +/* + Mantis VP-2033 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. + + 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. +*/ + +#ifndef __MANTIS_VP2033_H +#define __MANTIS_VP2033_H + +#include "mantis_common.h" + +#define MANTIS_VP_2033_DVB_C 0x0008 + +extern struct mantis_hwconfig vp2033_config; + +#endif /* __MANTIS_VP2033_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c new file mode 100644 index 000000000000..a7ca233e800b --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp2040.c @@ -0,0 +1,186 @@ +/* + Mantis VP-2040 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "tda1002x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp2040.h" + +#define MANTIS_MODEL_NAME "VP-2040" +#define MANTIS_DEV_TYPE "DVB-C" + +struct tda1002x_config vp2040_tda1002x_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +struct tda10023_config vp2040_tda10023_cu1216_config = { + .demod_address = 0x18 >> 1, + .invert = 1, +}; + +static int tda1002x_cu1216_tuner_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct mantis_pci *mantis = fe->dvb->priv; + struct i2c_adapter *adapter = &mantis->adapter; + + u8 buf[6]; + struct i2c_msg msg = {.addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf)}; + int i; + +#define CU1216_IF 36125000 +#define TUNER_MUL 62500 + + u32 div = (params->frequency + CU1216_IF + TUNER_MUL / 2) / TUNER_MUL; + + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0xce; + buf[3] = (params->frequency < 150000000 ? 0x01 : + params->frequency < 445000000 ? 0x02 : 0x04); + buf[4] = 0xde; + buf[5] = 0x20; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + /* wait for the pll lock */ + msg.flags = I2C_M_RD; + msg.len = 1; + for (i = 0; i < 20; i++) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) == 1 && (buf[0] & 0x40)) + break; + + msleep(10); + } + + /* switch the charge pump to the lower current */ + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[2]; + buf[2] &= ~0x40; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + if (i2c_transfer(adapter, &msg, 1) != 1) + return -EIO; + + return 0; +} + +static u8 read_pwm(struct mantis_pci *mantis) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + u8 b = 0xff; + u8 pwm; + struct i2c_msg msg[] = { + {.addr = 0x50, .flags = 0, .buf = &b, .len = 1}, + {.addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} + }; + + if ((i2c_transfer(adapter, msg, 2) != 2) + || (pwm == 0xff)) + pwm = 0x48; + + return pwm; +} + +static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + + int err = 0; + + err = mantis_frontend_power(mantis, POWER_ON); + if (err == 0) { + mantis_frontend_soft_reset(mantis); + msleep(250); + + dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)"); + fe = tda10021_attach(&vp2040_tda1002x_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } else { + fe = tda10023_attach(&vp2040_tda10023_cu1216_config, + adapter, + read_pwm(mantis)); + + if (fe) { + dprintk(MANTIS_ERROR, 1, + "found Philips CU1216 DVB-C frontend (TDA10023) @ 0x%02x", + vp2040_tda1002x_cu1216_config.demod_address); + } + } + + if (fe) { + fe->ops.tuner_ops.set_params = tda1002x_cu1216_tuner_set; + dprintk(MANTIS_ERROR, 1, "Mantis DVB-C Philips CU1216 frontend attach success"); + } else { + return -1; + } + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + } + mantis->fe = fe; + dprintk(MANTIS_DEBUG, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp2040_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_204, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp2040_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp2040.h b/drivers/media/dvb/mantis/mantis_vp2040.h new file mode 100644 index 000000000000..d125e219b685 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp2040.h @@ -0,0 +1,32 @@ +/* + Mantis VP-2040 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. + + 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. +*/ + +#ifndef __MANTIS_VP2040_H +#define __MANTIS_VP2040_H + +#include "mantis_common.h" + +#define MANTIS_VP_2040_DVB_C 0x0043 +#define CINERGY_C 0x1178 +#define CABLESTAR_HD2 0x0002 + +extern struct mantis_hwconfig vp2040_config; + +#endif /* __MANTIS_VP2040_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp3028.c b/drivers/media/dvb/mantis/mantis_vp3028.c new file mode 100644 index 000000000000..4155c838a18a --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp3028.c @@ -0,0 +1,38 @@ +/* + Mantis VP-3028 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. + + 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. +*/ + +#include "mantis_common.h" +#include "mantis_vp3028.h" + +struct zl10353_config mantis_vp3028_config = { + .demod_address = 0x0f, +}; + +#define MANTIS_MODEL_NAME "VP-3028" +#define MANTIS_DEV_TYPE "DVB-T" + +struct mantis_hwconfig vp3028_mantis_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, +}; diff --git a/drivers/media/dvb/mantis/mantis_vp3028.h b/drivers/media/dvb/mantis/mantis_vp3028.h new file mode 100644 index 000000000000..b07be6adc522 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp3028.h @@ -0,0 +1,33 @@ +/* + Mantis VP-3028 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. + + 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. +*/ + +#ifndef __MANTIS_VP3028_H +#define __MANTIS_VP3028_H + +#include "dvb_frontend.h" +#include "mantis_common.h" +#include "zl10353.h" + +#define MANTIS_VP_3028_DVB_T 0x0028 + +extern struct zl10353_config mantis_vp3028_config; +extern struct mantis_hwconfig vp3028_mantis_config; + +#endif /* __MANTIS_VP3028_H */ diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c new file mode 100644 index 000000000000..1f4334214953 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp3030.c @@ -0,0 +1,105 @@ +/* + Mantis VP-3030 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. + + 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. +*/ + +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#include "zl10353.h" +#include "tda665x.h" +#include "mantis_common.h" +#include "mantis_ioc.h" +#include "mantis_dvb.h" +#include "mantis_vp3030.h" + +struct zl10353_config mantis_vp3030_config = { + .demod_address = 0x0f, +}; + +struct tda665x_config env57h12d5_config = { + .name = "ENV57H12D5 (ET-50DT)", + .addr = 0x60, + .frequency_min = 47000000, + .frequency_max = 862000000, + .frequency_offst = 3616667, + .ref_multiplier = 6, /* 1/6 MHz */ + .ref_divider = 100000, /* 1/6 MHz */ +}; + +#define MANTIS_MODEL_NAME "VP-3030" +#define MANTIS_DEV_TYPE "DVB-T" + + +static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe) +{ + struct i2c_adapter *adapter = &mantis->adapter; + struct mantis_hwconfig *config = mantis->hwconfig; + int err = 0; + + gpio_set_bits(mantis, config->reset, 0); + msleep(100); + err = mantis_frontend_power(mantis, POWER_ON); + msleep(100); + gpio_set_bits(mantis, config->reset, 1); + + if (err == 0) { + msleep(250); + dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)"); + fe = zl10353_attach(&mantis_vp3030_config, adapter); + + if (!fe) + return -1; + + tda665x_attach(fe, &env57h12d5_config, adapter); + } else { + dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>", + adapter->name, + err); + + return -EIO; + + } + mantis->fe = fe; + dprintk(MANTIS_ERROR, 1, "Done!"); + + return 0; +} + +struct mantis_hwconfig vp3030_config = { + .model_name = MANTIS_MODEL_NAME, + .dev_type = MANTIS_DEV_TYPE, + .ts_size = MANTIS_TS_188, + + .baud_rate = MANTIS_BAUD_9600, + .parity = MANTIS_PARITY_NONE, + .bytes = 0, + + .frontend_init = vp3030_frontend_init, + .power = GPIF_A12, + .reset = GPIF_A13, + + .i2c_mode = MANTIS_BYTE_MODE +}; diff --git a/drivers/media/dvb/mantis/mantis_vp3030.h b/drivers/media/dvb/mantis/mantis_vp3030.h new file mode 100644 index 000000000000..5f12c4266277 --- /dev/null +++ b/drivers/media/dvb/mantis/mantis_vp3030.h @@ -0,0 +1,30 @@ +/* + Mantis VP-3030 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. + + 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. +*/ + +#ifndef __MANTIS_VP3030_H +#define __MANTIS_VP3030_H + +#include "mantis_common.h" + +#define MANTIS_VP_3030_DVB_T 0x0024 + +extern struct mantis_hwconfig vp3030_config; + +#endif /* __MANTIS_VP3030_H */ diff --git a/drivers/media/dvb/siano/smsdvb.c b/drivers/media/dvb/siano/smsdvb.c index 266033ae2784..68bf9fbd8fed 100644 --- a/drivers/media/dvb/siano/smsdvb.c +++ b/drivers/media/dvb/siano/smsdvb.c @@ -662,7 +662,7 @@ adapter_error: return rc; } -int smsdvb_module_init(void) +static int __init smsdvb_module_init(void) { int rc; @@ -676,7 +676,7 @@ int smsdvb_module_init(void) return rc; } -void smsdvb_module_exit(void) +static void __exit smsdvb_module_exit(void) { smscore_unregister_hotplug(smsdvb_hotplug); diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c index 24206cbda264..195244a3e69b 100644 --- a/drivers/media/dvb/siano/smssdio.c +++ b/drivers/media/dvb/siano/smssdio.c @@ -48,7 +48,7 @@ #define SMSSDIO_INT 0x04 #define SMSSDIO_BLOCK_SIZE 128 -static const struct sdio_device_id smssdio_ids[] = { +static const struct sdio_device_id smssdio_ids[] __devinitconst = { {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR), .driver_data = SMS1XXX_BOARD_SIANO_STELLAR}, {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0), @@ -222,7 +222,7 @@ static void smssdio_interrupt(struct sdio_func *func) smscore_onresponse(smsdev->coredev, cb); } -static int smssdio_probe(struct sdio_func *func, +static int __devinit smssdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { int ret; @@ -338,7 +338,7 @@ static struct sdio_driver smssdio_driver = { /* Module functions */ /*******************************************************************/ -int smssdio_module_init(void) +static int __init smssdio_module_init(void) { int ret = 0; @@ -350,7 +350,7 @@ int smssdio_module_init(void) return ret; } -void smssdio_module_exit(void) +static void __exit smssdio_module_exit(void) { sdio_unregister_driver(&smssdio_driver); } diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c index 8f88a586b0dd..5eac27287d9c 100644 --- a/drivers/media/dvb/siano/smsusb.c +++ b/drivers/media/dvb/siano/smsusb.c @@ -390,7 +390,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) return rc; } -static int smsusb_probe(struct usb_interface *intf, +static int __devinit smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); @@ -484,7 +484,7 @@ static int smsusb_resume(struct usb_interface *intf) return 0; } -struct usb_device_id smsusb_id_table[] = { +static const struct usb_device_id smsusb_id_table[] __devinitconst = { { USB_DEVICE(0x187f, 0x0010), .driver_info = SMS1XXX_BOARD_SIANO_STELLAR }, { USB_DEVICE(0x187f, 0x0100), @@ -533,8 +533,18 @@ struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xb910), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb980), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xb990), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xc000), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc010), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc080), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x2040, 0xc090), + .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { } /* Terminating entry */ }; @@ -550,7 +560,7 @@ static struct usb_driver smsusb_driver = { .resume = smsusb_resume, }; -int smsusb_module_init(void) +static int __init smsusb_module_init(void) { int rc = usb_register(&smsusb_driver); if (rc) @@ -561,7 +571,7 @@ int smsusb_module_init(void) return rc; } -void smsusb_module_exit(void) +static void __exit smsusb_module_exit(void) { /* Regular USB Cleanup */ usb_deregister(&smsusb_driver); diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index 7d193ebc0aea..9782e0593733 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -190,12 +190,13 @@ static int msp430_ir_init(struct budget_ci *budget_ci) struct saa7146_dev *saa = budget_ci->budget.dev; struct input_dev *input_dev = budget_ci->ir.dev; int error; + struct ir_scancode_table *ir_codes; + budget_ci->ir.dev = input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "budget_ci: IR interface initialisation failed\n"); - error = -ENOMEM; - goto out1; + return -ENOMEM; } snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name), @@ -217,6 +218,11 @@ static int msp430_ir_init(struct budget_ci *budget_ci) } input_dev->dev.parent = &saa->pci->dev; + if (rc5_device < 0) + budget_ci->ir.rc5_device = IR_DEVICE_ANY; + else + budget_ci->ir.rc5_device = rc5_device; + /* Select keymap and address */ switch (budget_ci->budget.dev->pci->subsystem_device) { case 0x100c: @@ -224,53 +230,34 @@ static int msp430_ir_init(struct budget_ci *budget_ci) case 0x1011: case 0x1012: /* The hauppauge keymap is a superset of these remotes */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_hauppauge_new_table); - if (error < 0) - goto out2; + ir_codes = &ir_codes_hauppauge_new_table; if (rc5_device < 0) budget_ci->ir.rc5_device = 0x1f; - else - budget_ci->ir.rc5_device = rc5_device; break; case 0x1010: case 0x1017: case 0x101a: /* for the Technotrend 1500 bundled remote */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_tt_1500_table); - if (error < 0) - goto out2; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; + ir_codes = &ir_codes_tt_1500_table; break; default: /* unknown remote */ - error = ir_input_init(input_dev, &budget_ci->ir.state, - IR_TYPE_RC5, &ir_codes_budget_ci_old_table); - if (error < 0) - goto out2; - - if (rc5_device < 0) - budget_ci->ir.rc5_device = IR_DEVICE_ANY; - else - budget_ci->ir.rc5_device = rc5_device; + ir_codes = &ir_codes_budget_ci_old_table; break; } + ir_input_init(input_dev, &budget_ci->ir.state, IR_TYPE_RC5); + /* initialise the key-up timeout handler */ init_timer(&budget_ci->ir.timer_keyup); budget_ci->ir.timer_keyup.function = msp430_ir_keyup; budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir; budget_ci->ir.last_raw = 0xffff; /* An impossible value */ - error = input_register_device(input_dev); + error = ir_input_register(input_dev, ir_codes); if (error) { printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error); - goto out2; + return error; } /* note: these must be after input_register_device */ @@ -284,12 +271,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci) saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); return 0; - -out2: - ir_input_free(input_dev); - input_free_device(input_dev); -out1: - return error; } static void msp430_ir_deinit(struct budget_ci *budget_ci) @@ -304,8 +285,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) del_timer_sync(&dev->timer); ir_input_nokey(dev, &budget_ci->ir.state); - ir_input_free(dev); - input_unregister_device(dev); + ir_input_unregister(dev); } static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 4c2b8a246772..3f40f375981b 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -215,13 +215,10 @@ config RADIO_MIROPCM20 module will be called radio-miropcm20. config RADIO_SF16FMI - tristate "SF16FMI Radio" + tristate "SF16-FMI/SF16-FMP Radio" depends on ISA && VIDEO_V4L2 ---help--- - Choose Y here if you have one of these FM radio cards. If you - compile the driver into the kernel and your card is not PnP one, you - have to add "sf16fm=<io>" to the kernel command line (I/O address is - 0x284 or 0x384). + Choose Y here if you have one of these FM radio cards. In order to control your radio card, you will need to use programs that are compatible with the Video For Linux API. Information on diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 35edee009ba8..5bf4985daede 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -268,6 +268,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct rtrack *rt = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; rt_setfreq(rt, f->frequency); return 0; } @@ -277,6 +279,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct rtrack *rt = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; return 0; diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 8daf809eb01a..c22311393624 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -254,6 +254,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct aztech *az = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; az_setfreq(az, f->frequency); return 0; } @@ -263,6 +265,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct aztech *az = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = az->curfreq; return 0; diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index c6cf11661868..000f4d34087c 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct gemtek_pci *card = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (f->frequency < GEMTEK_PCI_RANGE_LOW || f->frequency > GEMTEK_PCI_RANGE_HIGH) return -EINVAL; @@ -253,6 +255,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct gemtek_pci *card = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = card->current_frequency; return 0; diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index 64d737c35acf..f8213b7c8ddc 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -200,6 +200,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct maestro *dev = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; mutex_lock(&dev->lock); @@ -213,6 +215,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct maestro *dev = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; mutex_lock(&dev->lock); f->frequency = BITS2FREQ(radio_bits_get(dev)); diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index 3da51fe8fb93..44b4dbedb322 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -262,6 +262,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct maxiradio *dev = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", f->frequency / 16000, @@ -285,6 +287,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct maxiradio *dev = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = dev->freq; diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 949f60513d9e..02a9cefc9a00 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -374,6 +374,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct amradio_device *radio = file->private_data; + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; return amradio_setfreq(radio, f->frequency); } @@ -383,6 +385,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct amradio_device *radio = file->private_data; + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = radio->curfreq; diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 9cb193fa6e33..a79296aac9a9 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -167,6 +167,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct rtrack2 *rt = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; rt_setfreq(rt, f->frequency); return 0; } @@ -176,6 +178,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct rtrack2 *rt = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; return 0; diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 49c4aab95dab..985359d18aa5 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -1,4 +1,4 @@ -/* SF16FMI radio driver for Linux radio support +/* SF16-FMI and SF16-FMP radio driver for Linux radio support * heavily based on rtrack driver... * (c) 1997 M. Kirkwood * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz @@ -11,7 +11,7 @@ * * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); * No volume control - only mute/unmute - you have to use line volume - * control on SB-part of SF16FMI + * control on SB-part of SF16-FMI/SF16-FMP * * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> */ @@ -30,14 +30,14 @@ #include <media/v4l2-ioctl.h> MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); -MODULE_DESCRIPTION("A driver for the SF16MI radio."); +MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio."); MODULE_LICENSE("GPL"); static int io = -1; static int radio_nr = -1; module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); +MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)"); module_param(radio_nr, int, 0); #define RADIO_VERSION KERNEL_VERSION(0, 0, 2) @@ -47,13 +47,14 @@ struct fmi struct v4l2_device v4l2_dev; struct video_device vdev; int io; - int curvol; /* 1 or 0 */ + bool mute; unsigned long curfreq; /* freq in kHz */ struct mutex lock; }; static struct fmi fmi_card; static struct pnp_dev *dev; +bool pnp_attached; /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ /* It is only useful to give freq in interval of 800 (=0.05Mhz), @@ -105,7 +106,7 @@ static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) outbits(8, 0xC0, fmi->io); msleep(143); /* was schedule_timeout(HZ/7) */ mutex_unlock(&fmi->lock); - if (fmi->curvol) + if (!fmi->mute) fmi_unmute(fmi); return 0; } @@ -116,7 +117,7 @@ static inline int fmi_getsigstr(struct fmi *fmi) int res; mutex_lock(&fmi->lock); - val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */ + val = fmi->mute ? 0x00 : 0x08; /* mute/unmute */ outb(val, fmi->io); outb(val | 0x10, fmi->io); msleep(143); /* was schedule_timeout(HZ/7) */ @@ -168,6 +169,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct fmi *fmi = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (f->frequency < RSF16_MINFREQ || f->frequency > RSF16_MAXFREQ) return -EINVAL; @@ -182,6 +185,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct fmi *fmi = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = fmi->curfreq; return 0; @@ -204,7 +209,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = fmi->curvol; + ctrl->value = fmi->mute; return 0; } return -EINVAL; @@ -221,7 +226,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, fmi_mute(fmi); else fmi_unmute(fmi); - fmi->curvol = ctrl->value; + fmi->mute = ctrl->value; return 0; } return -EINVAL; @@ -316,26 +321,54 @@ static int __init fmi_init(void) { struct fmi *fmi = &fmi_card; struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; - int res; + int res, i; + int probe_ports[] = { 0, 0x284, 0x384 }; + + if (io < 0) { + for (i = 0; i < ARRAY_SIZE(probe_ports); i++) { + io = probe_ports[i]; + if (io == 0) { + io = isapnp_fmi_probe(); + if (io < 0) + continue; + pnp_attached = 1; + } + if (!request_region(io, 2, "radio-sf16fmi")) { + if (pnp_attached) + pnp_device_detach(dev); + io = -1; + continue; + } + if (pnp_attached || + ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0)) + break; + release_region(io, 2); + io = -1; + } + } else { + if (!request_region(io, 2, "radio-sf16fmi")) { + printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io); + return -EBUSY; + } + if (inb(io) == 0xff) { + printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io); + release_region(io, 2); + return -ENODEV; + } + } + if (io < 0) { + printk(KERN_ERR "radio-sf16fmi: no cards found\n"); + return -ENODEV; + } - if (io < 0) - io = isapnp_fmi_probe(); strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); fmi->io = io; - if (fmi->io < 0) { - v4l2_err(v4l2_dev, "No PnP card found.\n"); - return fmi->io; - } - if (!request_region(io, 2, "radio-sf16fmi")) { - v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io); - pnp_device_detach(dev); - return -EBUSY; - } res = v4l2_device_register(NULL, v4l2_dev); if (res < 0) { release_region(fmi->io, 2); - pnp_device_detach(dev); + if (pnp_attached) + pnp_device_detach(dev); v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); return res; } @@ -352,7 +385,8 @@ static int __init fmi_init(void) if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { v4l2_device_unregister(v4l2_dev); release_region(fmi->io, 2); - pnp_device_detach(dev); + if (pnp_attached) + pnp_device_detach(dev); return -EINVAL; } @@ -369,7 +403,7 @@ static void __exit fmi_exit(void) video_unregister_device(&fmi->vdev); v4l2_device_unregister(&fmi->v4l2_dev); release_region(fmi->io, 2); - if (dev) + if (dev && pnp_attached) pnp_device_detach(dev); } diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index a11414f648d4..52c7bbb32b8b 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -251,6 +251,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct fmr2 *fmr2 = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (f->frequency < RSF16_MINFREQ || f->frequency > RSF16_MAXFREQ) return -EINVAL; @@ -272,6 +274,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct fmr2 *fmr2 = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = fmr2->curfreq; return 0; diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 3cd76dddb6aa..8e718bfcdad3 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -314,7 +314,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (v->index > 0) return -EINVAL; - memset(v, 0, sizeof(v)); + memset(v, 0, sizeof(*v)); strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; tea5764_i2c_read(radio); @@ -349,7 +349,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct tea5764_device *radio = video_drvdata(file); - if (f->tuner != 0) + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; if (f->frequency == 0) { /* We special case this as a power down control. */ @@ -370,8 +370,10 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct tea5764_device *radio = video_drvdata(file); struct tea5764_regs *r = &radio->regs; + if (f->tuner != 0) + return -EINVAL; tea5764_i2c_read(radio); - memset(f, 0, sizeof(f)); + memset(f, 0, sizeof(*f)); f->type = V4L2_TUNER_RADIO; if (r->tnctrl & TEA5764_TNCTRL_PUPD0) f->frequency = (tea5764_get_freq(radio) * 2) / 125; @@ -458,12 +460,8 @@ static int vidioc_s_audio(struct file *file, void *priv, static int tea5764_open(struct file *file) { /* Currently we support only one device */ - int minor = video_devdata(file)->minor; struct tea5764_device *radio = video_drvdata(file); - if (radio->videodev->minor != minor) - return -ENODEV; - mutex_lock(&radio->mutex); /* Only exclusive access */ if (radio->users) { diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 699db9acaaf7..fc1c860fd438 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -240,6 +240,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct terratec *tt = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; tt_setfreq(tt, f->frequency); return 0; } @@ -249,6 +251,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct terratec *tt = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = tt->curfreq; return 0; diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index 6f9ecc359356..9d6dcf8af5b0 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -239,6 +239,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct trust *tr = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; tr_setfreq(tr, f->frequency); return 0; } @@ -248,6 +250,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct trust *tr = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = tr->curfreq; return 0; diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 3a98f1399495..03439282dfce 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -207,6 +207,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct typhoon *dev = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = dev->curfreq; return 0; @@ -217,6 +219,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct typhoon *dev = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; dev->curfreq = f->frequency; typhoon_setfreq(dev, dev->curfreq); return 0; diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 80e98b6422fe..f31eab99c943 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -266,6 +266,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct zoltrix *zol = video_drvdata(file); + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; if (zol_setfreq(zol, f->frequency) != 0) return -EINVAL; return 0; @@ -276,6 +278,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct zoltrix *zol = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; f->type = V4L2_TUNER_RADIO; f->frequency = zol->curfreq; return 0; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index f33315f2c543..4da0f150c6e2 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -426,6 +426,104 @@ int si470x_rds_on(struct si470x_device *radio) /************************************************************************** + * File Operations Interface + **************************************************************************/ + +/* + * si470x_fops_read - read RDS data + */ +static ssize_t si470x_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + unsigned int block_count = 0; + + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + /* block if no new data available */ + while (radio->wr_index == radio->rd_index) { + if (file->f_flags & O_NONBLOCK) { + retval = -EWOULDBLOCK; + goto done; + } + if (wait_event_interruptible(radio->read_queue, + radio->wr_index != radio->rd_index) < 0) { + retval = -EINTR; + goto done; + } + } + + /* calculate block count from byte count */ + count /= 3; + + /* copy RDS block out of internal buffer and to user buffer */ + mutex_lock(&radio->lock); + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + + /* always transfer rds complete blocks */ + if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; + + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; + } + mutex_unlock(&radio->lock); + +done: + return retval; +} + + +/* + * si470x_fops_poll - poll RDS data + */ +static unsigned int si470x_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si470x_device *radio = video_drvdata(file); + int retval = 0; + + /* switch on rds reception */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + si470x_rds_on(radio); + + poll_wait(file, &radio->read_queue, pts); + + if (radio->rd_index != radio->wr_index) + retval = POLLIN | POLLRDNORM; + + return retval; +} + + +/* + * si470x_fops - file operations interface + */ +static const struct v4l2_file_operations si470x_fops = { + .owner = THIS_MODULE, + .read = si470x_fops_read, + .poll = si470x_fops_poll, + .ioctl = video_ioctl2, + .open = si470x_fops_open, + .release = si470x_fops_release, +}; + + + +/************************************************************************** * Video4Linux Interface **************************************************************************/ diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 2d53b6a9409b..5466015346a1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -22,22 +22,17 @@ */ -/* - * ToDo: - * - RDS support - */ - - /* driver definitions */ #define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 0) +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 1) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.0" +#define DRIVER_VERSION "1.0.1" /* kernel includes */ #include <linux/i2c.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include "radio-si470x.h" @@ -62,6 +57,20 @@ static int radio_nr = -1; module_param(radio_nr, int, 0444); MODULE_PARM_DESC(radio_nr, "Radio Nr"); +/* RDS buffer blocks */ +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0444); +MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); + +/* RDS maximum block errors */ +static unsigned short max_rds_errors = 1; +/* 0 means 0 errors requiring correction */ +/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ +/* 2 means 3-5 errors requiring correction */ +/* 3 means 6+ errors or errors in checkword, correction not possible */ +module_param(max_rds_errors, ushort, 0644); +MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); + /************************************************************************** @@ -173,7 +182,7 @@ int si470x_disconnect_check(struct si470x_device *radio) /* * si470x_fops_open - file open */ -static int si470x_fops_open(struct file *file) +int si470x_fops_open(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval = 0; @@ -181,12 +190,21 @@ static int si470x_fops_open(struct file *file) mutex_lock(&radio->lock); radio->users++; - if (radio->users == 1) + if (radio->users == 1) { /* start radio */ retval = si470x_start(radio); + if (retval < 0) + goto done; + + /* enable RDS interrupt */ + radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN; + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2; + radio->registers[SYSCONFIG1] |= 0x1 << 2; + retval = si470x_set_register(radio, SYSCONFIG1); + } +done: mutex_unlock(&radio->lock); - return retval; } @@ -194,7 +212,7 @@ static int si470x_fops_open(struct file *file) /* * si470x_fops_release - file release */ -static int si470x_fops_release(struct file *file) +int si470x_fops_release(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval = 0; @@ -215,17 +233,6 @@ static int si470x_fops_release(struct file *file) } -/* - * si470x_fops - file operations interface - */ -const struct v4l2_file_operations si470x_fops = { - .owner = THIS_MODULE, - .ioctl = video_ioctl2, - .open = si470x_fops_open, - .release = si470x_fops_release, -}; - - /************************************************************************** * Video4Linux Interface @@ -253,6 +260,105 @@ int si470x_vidioc_querycap(struct file *file, void *priv, **************************************************************************/ /* + * si470x_i2c_interrupt_work - rds processing function + */ +static void si470x_i2c_interrupt_work(struct work_struct *work) +{ + struct si470x_device *radio = container_of(work, + struct si470x_device, radio_work); + unsigned char regnr; + unsigned char blocknum; + unsigned short bler; /* rds block errors */ + unsigned short rds; + unsigned char tmpbuf[3]; + int retval = 0; + + /* safety checks */ + if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) + return; + + /* Update RDS registers */ + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { + retval = si470x_get_register(radio, STATUSRSSI + regnr); + if (retval < 0) + return; + } + + /* get rds blocks */ + if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) + /* No RDS group ready, better luck next time */ + return; + + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + put_unaligned_le16(rds, &tmpbuf); + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + } + } + + if (radio->wr_index != radio->rd_index) + wake_up_interruptible(&radio->read_queue); +} + + +/* + * si470x_i2c_interrupt - interrupt handler + */ +static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) +{ + struct si470x_device *radio = dev_id; + + if (!work_pending(&radio->radio_work)) + schedule_work(&radio->radio_work); + + return IRQ_HANDLED; +} + + +/* * si470x_i2c_probe - probe for the device */ static int __devinit si470x_i2c_probe(struct i2c_client *client, @@ -268,6 +374,8 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, retval = -ENOMEM; goto err_initial; } + + INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work); radio->users = 0; radio->client = client; mutex_init(&radio->lock); @@ -319,6 +427,26 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ + /* rds buffer allocation */ + radio->buf_size = rds_buf * 3; + radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); + if (!radio->buffer) { + retval = -EIO; + goto err_video; + } + + /* rds buffer configuration */ + radio->wr_index = 0; + radio->rd_index = 0; + init_waitqueue_head(&radio->read_queue); + + retval = request_irq(client->irq, si470x_i2c_interrupt, + IRQF_TRIGGER_FALLING, DRIVER_NAME, radio); + if (retval) { + dev_err(&client->dev, "Failed to register interrupt\n"); + goto err_rds; + } + /* register video device */ retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); @@ -330,6 +458,9 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, return 0; err_all: + free_irq(client->irq, radio); +err_rds: + kfree(radio->buffer); err_video: video_device_release(radio->videodev); err_radio: @@ -346,6 +477,8 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) { struct si470x_device *radio = i2c_get_clientdata(client); + free_irq(client->irq, radio); + cancel_work_sync(&radio->radio_work); video_unregister_device(radio->videodev); kfree(radio); i2c_set_clientdata(client, NULL); @@ -354,6 +487,44 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) } +#ifdef CONFIG_PM +/* + * si470x_i2c_suspend - suspend the device + */ +static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power down */ + radio->registers[POWERCFG] |= POWERCFG_DISABLE; + if (si470x_set_register(radio, POWERCFG) < 0) + return -EIO; + + return 0; +} + + +/* + * si470x_i2c_resume - resume the device + */ +static int si470x_i2c_resume(struct i2c_client *client) +{ + struct si470x_device *radio = i2c_get_clientdata(client); + + /* power up : need 110ms */ + radio->registers[POWERCFG] |= POWERCFG_ENABLE; + if (si470x_set_register(radio, POWERCFG) < 0) + return -EIO; + msleep(110); + + return 0; +} +#else +#define si470x_i2c_suspend NULL +#define si470x_i2c_resume NULL +#endif + + /* * si470x_i2c_driver - i2c driver interface */ @@ -364,6 +535,8 @@ static struct i2c_driver si470x_i2c_driver = { }, .probe = si470x_i2c_probe, .remove = __devexit_p(si470x_i2c_remove), + .suspend = si470x_i2c_suspend, + .resume = si470x_i2c_resume, .id_table = si470x_i2c_id, }; diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index f2d0e1ddb301..a96e1b9dd646 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -509,89 +509,9 @@ resubmit: **************************************************************************/ /* - * si470x_fops_read - read RDS data - */ -static ssize_t si470x_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - unsigned int block_count = 0; - - /* switch on rds reception */ - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - si470x_rds_on(radio); - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) { - retval = -EWOULDBLOCK; - goto done; - } - if (wait_event_interruptible(radio->read_queue, - radio->wr_index != radio->rd_index) < 0) { - retval = -EINTR; - goto done; - } - } - - /* calculate block count from byte count */ - count /= 3; - - /* copy RDS block out of internal buffer and to user buffer */ - mutex_lock(&radio->lock); - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer rds complete blocks */ - if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) - /* retval = -EFAULT; */ - break; - - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += 3; - retval += 3; - } - mutex_unlock(&radio->lock); - -done: - return retval; -} - - -/* - * si470x_fops_poll - poll RDS data - */ -static unsigned int si470x_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct si470x_device *radio = video_drvdata(file); - int retval = 0; - - /* switch on rds reception */ - if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) - si470x_rds_on(radio); - - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - retval = POLLIN | POLLRDNORM; - - return retval; -} - - -/* * si470x_fops_open - file open */ -static int si470x_fops_open(struct file *file) +int si470x_fops_open(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval; @@ -645,7 +565,7 @@ done: /* * si470x_fops_release - file release */ -static int si470x_fops_release(struct file *file) +int si470x_fops_release(struct file *file) { struct si470x_device *radio = video_drvdata(file); int retval = 0; @@ -688,19 +608,6 @@ done: } -/* - * si470x_fops - file operations interface - */ -const struct v4l2_file_operations si470x_fops = { - .owner = THIS_MODULE, - .read = si470x_fops_read, - .poll = si470x_fops_poll, - .ioctl = video_ioctl2, - .open = si470x_fops_open, - .release = si470x_fops_release, -}; - - /************************************************************************** * Video4Linux Interface diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index d0af194d194c..3cd0a29cd6e7 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/smp_lock.h> #include <linux/input.h> @@ -181,6 +182,7 @@ struct si470x_device { #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) struct i2c_client *client; + struct work_struct radio_work; #endif }; @@ -212,7 +214,6 @@ struct si470x_device { /************************************************************************** * Common Functions **************************************************************************/ -extern const struct v4l2_file_operations si470x_fops; extern struct video_device si470x_viddev_template; int si470x_get_register(struct si470x_device *radio, int regnr); int si470x_set_register(struct si470x_device *radio, int regnr); @@ -221,5 +222,7 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq); int si470x_start(struct si470x_device *radio); int si470x_stop(struct si470x_device *radio); int si470x_rds_on(struct si470x_device *radio); +int si470x_fops_open(struct file *file); +int si470x_fops_release(struct file *file); int si470x_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *capability); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 9dc74c93bf24..2f83be766d9f 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -37,10 +37,6 @@ config VIDEO_BTCX depends on PCI tristate -config VIDEO_IR - tristate - depends on INPUT - config VIDEO_TVEEPROM tristate depends on I2C @@ -840,6 +836,12 @@ config SOC_CAMERA_MT9T031 help This driver supports MT9T031 cameras from Micron. +config SOC_CAMERA_MT9T112 + tristate "mt9t112 support" + depends on SOC_CAMERA && I2C + help + This driver supports MT9T112 cameras from Aptina. + config SOC_CAMERA_MT9V022 tristate "mt9v022 support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 7a2dcc34111c..2af68ee84122 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -75,6 +75,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o +obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o @@ -149,7 +150,7 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o -obj-$(CONFIG_SOC_CAMERA) += soc_camera.o +obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o # soc-camera host drivers have to be linked after camera drivers obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index d137bac84511..a356d6bd3131 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -767,7 +767,6 @@ static struct video_device ar_template = { .name = "Colour AR VGA", .fops = &ar_fops, .release = ar_release, - .minor = -1, }; #define ALIGN4(x) ((((int)(x)) & 0x3) == 0) @@ -860,8 +859,8 @@ static int __init ar_init(void) goto out_dev; } - printk("video%d: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", - ar->vdev->num, M32R_IRQ_INT3, freq); + printk("%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", + video_device_node_name(ar->vdev), M32R_IRQ_INT3, freq); return 0; diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 1485aee18d58..dc67bc40f36f 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c @@ -40,7 +40,6 @@ #include "au0828.h" #include "au0828-reg.h" -static LIST_HEAD(au0828_devlist); static DEFINE_MUTEX(au0828_sysfs_lock); #define AU0828_VERSION_CODE KERNEL_VERSION(0, 0, 1) @@ -693,10 +692,8 @@ void au0828_analog_unregister(struct au0828_dev *dev) dprintk(1, "au0828_release_resources called\n"); mutex_lock(&au0828_sysfs_lock); - if (dev->vdev) { - list_del(&dev->au0828list); + if (dev->vdev) video_unregister_device(dev->vdev); - } if (dev->vbi_dev) video_unregister_device(dev->vbi_dev); @@ -737,29 +734,15 @@ static void res_free(struct au0828_fh *fh) static int au0828_v4l2_open(struct file *filp) { - int minor = video_devdata(filp)->minor; int ret = 0; - struct au0828_dev *h, *dev = NULL; + struct au0828_dev *dev = video_drvdata(filp); struct au0828_fh *fh; - int type = 0; - struct list_head *list; - - list_for_each(list, &au0828_devlist) { - h = list_entry(list, struct au0828_dev, au0828list); - if (h->vdev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } + int type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + #ifdef VBI_IS_WORKING - if (h->vbi_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } + if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER) + type = V4L2_BUF_TYPE_VBI_CAPTURE; #endif - } - - if (NULL == dev) - return -ENODEV; fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL); if (NULL == fh) { @@ -1587,7 +1570,6 @@ static const struct video_device au0828_video_template = { .fops = &au0828_v4l_fops, .release = video_device_release, .ioctl_ops = &video_ioctl_ops, - .minor = -1, .tvnorms = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M, }; @@ -1676,25 +1658,23 @@ int au0828_analog_register(struct au0828_dev *dev, strcpy(dev->vbi_dev->name, "au0828a vbi"); #endif - list_add_tail(&dev->au0828list, &au0828_devlist); - /* Register the v4l2 device */ + video_set_drvdata(dev->vdev, dev); retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1); if (retval != 0) { dprintk(1, "unable to register video device (error = %d).\n", retval); - list_del(&dev->au0828list); video_device_release(dev->vdev); return -ENODEV; } #ifdef VBI_IS_WORKING /* Register the vbi device */ + video_set_drvdata(dev->vbi_dev, dev); retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1); if (retval != 0) { dprintk(1, "unable to register vbi device (error = %d).\n", retval); - list_del(&dev->au0828list); video_device_release(dev->vbi_dev); video_device_release(dev->vdev); return -ENODEV; diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h index b977915efbd0..207f32dec6a6 100644 --- a/drivers/media/video/au0828/au0828.h +++ b/drivers/media/video/au0828/au0828.h @@ -192,7 +192,6 @@ struct au0828_dev { struct au0828_dvb dvb; /* Analog */ - struct list_head au0828list; struct v4l2_device v4l2_dev; int users; unsigned int stream_on:1; /* Locks streams */ diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index a6724019c66f..3182a406bdd1 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -3206,24 +3206,24 @@ err: static int bttv_open(struct file *file) { - int minor = video_devdata(file)->minor; + struct video_device *vdev = video_devdata(file); struct bttv *btv = video_drvdata(file); struct bttv_fh *fh; enum v4l2_buf_type type = 0; - dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); + dprintk(KERN_DEBUG "bttv: open dev=%s\n", video_device_node_name(vdev)); - lock_kernel(); - if (btv->video_dev->minor == minor) { + if (vdev->vfl_type == VFL_TYPE_GRABBER) { type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } else if (btv->vbi_dev->minor == minor) { + } else if (vdev->vfl_type == VFL_TYPE_VBI) { type = V4L2_BUF_TYPE_VBI_CAPTURE; } else { WARN_ON(1); - unlock_kernel(); return -ENODEV; } + lock_kernel(); + dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", btv->c.nr,v4l2_type_names[type]); @@ -3397,7 +3397,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { static struct video_device bttv_video_template = { .fops = &bttv_fops, - .minor = -1, .ioctl_ops = &bttv_ioctl_ops, .tvnorms = BTTV_NORMS, .current_norm = V4L2_STD_PAL, @@ -3408,18 +3407,13 @@ static struct video_device bttv_video_template = { static int radio_open(struct file *file) { - int minor = video_devdata(file)->minor; + struct video_device *vdev = video_devdata(file); struct bttv *btv = video_drvdata(file); struct bttv_fh *fh; - dprintk("bttv: open minor=%d\n",minor); + dprintk("bttv: open dev=%s\n", video_device_node_name(vdev)); lock_kernel(); - WARN_ON(btv->radio_dev && btv->radio_dev->minor != minor); - if (!btv->radio_dev || btv->radio_dev->minor != minor) { - unlock_kernel(); - return -ENODEV; - } dprintk("bttv%d: open called (radio)\n",btv->c.nr); @@ -3640,7 +3634,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static struct video_device radio_template = { .fops = &radio_fops, - .minor = -1, .ioctl_ops = &radio_ioctl_ops, }; @@ -4208,21 +4201,21 @@ static struct video_device *vdev_init(struct bttv *btv, static void bttv_unregister_video(struct bttv *btv) { if (btv->video_dev) { - if (-1 != btv->video_dev->minor) + if (video_is_registered(btv->video_dev)) video_unregister_device(btv->video_dev); else video_device_release(btv->video_dev); btv->video_dev = NULL; } if (btv->vbi_dev) { - if (-1 != btv->vbi_dev->minor) + if (video_is_registered(btv->vbi_dev)) video_unregister_device(btv->vbi_dev); else video_device_release(btv->vbi_dev); btv->vbi_dev = NULL; } if (btv->radio_dev) { - if (-1 != btv->radio_dev->minor) + if (video_is_registered(btv->radio_dev)) video_unregister_device(btv->radio_dev); else video_device_release(btv->radio_dev); @@ -4244,8 +4237,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device video%d\n", - btv->c.nr, btv->video_dev->num); + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->video_dev)); if (device_create_file(&btv->video_dev->dev, &dev_attr_card)<0) { printk(KERN_ERR "bttv%d: device_create_file 'card' " @@ -4261,8 +4254,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device vbi%d\n", - btv->c.nr, btv->vbi_dev->num); + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->vbi_dev)); if (!btv->has_radio) return 0; @@ -4273,8 +4266,8 @@ static int __devinit bttv_register_video(struct bttv *btv) if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; - printk(KERN_INFO "bttv%d: registered device radio%d\n", - btv->c.nr, btv->radio_dev->num); + printk(KERN_INFO "bttv%d: registered device %s\n", + btv->c.nr, video_device_node_name(btv->radio_dev)); /* all done */ return 0; diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c index beda363418b0..63aa31a041e8 100644 --- a/drivers/media/video/bt8xx/bttv-i2c.c +++ b/drivers/media/video/bt8xx/bttv-i2c.c @@ -40,7 +40,7 @@ static int i2c_debug; static int i2c_hw; static int i2c_scan; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_hw,"configure i2c debug level"); +MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); module_param(i2c_hw, int, 0444); MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " "instead of software bitbang"); @@ -400,7 +400,7 @@ int __devinit init_bttv_i2c(struct bttv *btv) That's why we probe 0x1a (~0x34) first. CB */ const unsigned short addr_list[] = { - 0x1a, 0x18, 0x4b, 0x64, 0x30, + 0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71, I2C_CLIENT_END }; diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 84a957e52c4b..277a092e1214 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -368,7 +368,7 @@ int bttv_input_init(struct bttv *btv) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(btv->c.pci)); - err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + err = ir_input_init(input_dev, &ir->ir, ir_type); if (err < 0) goto err_out_free; @@ -389,7 +389,7 @@ int bttv_input_init(struct bttv *btv) bttv_ir_start(btv, ir); /* all done */ - err = input_register_device(btv->remote->dev); + err = ir_input_register(btv->remote->dev, ir_codes); if (err) goto err_out_stop; @@ -403,8 +403,6 @@ int bttv_input_init(struct bttv *btv) bttv_ir_stop(btv); btv->remote = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -415,8 +413,7 @@ void bttv_input_fini(struct bttv *btv) return; bttv_ir_stop(btv); - ir_input_free(btv->remote->dev); - input_unregister_device(btv->remote->dev); + ir_input_unregister(btv->remote->dev); kfree(btv->remote); btv->remote = NULL; } diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 85cf1778827a..e2cbebab959b 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -809,8 +809,8 @@ static int init_cqcam(struct parport *port) return -ENODEV; } - printk(KERN_INFO "video%d: Colour QuickCam found on %s\n", - qcam->vdev.num, qcam->pport->name); + printk(KERN_INFO "%s: Colour QuickCam found on %s\n", + video_device_node_name(&qcam->vdev), qcam->pport->name); qcams[num_cams++] = qcam; diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 10230cb3d210..7bb9c1ec7819 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1723,7 +1723,6 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { static struct video_device cafe_v4l_template = { .name = "cafe", - .minor = -1, /* Get one dynamically */ .tvnorms = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 2377313c041a..551ddf216a4b 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -32,6 +32,7 @@ #include <linux/fs.h> #include <linux/vmalloc.h> #include <linux/sched.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/proc_fs.h> #include <linux/ctype.h> @@ -244,72 +245,67 @@ static void rvfree(void *mem, unsigned long size) #ifdef CONFIG_PROC_FS static struct proc_dir_entry *cpia_proc_root=NULL; -static int cpia_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int cpia_proc_show(struct seq_file *m, void *v) { - char *out = page; - int len, tmp; - struct cam_data *cam = data; + struct cam_data *cam = m->private; + int tmp; char tmpstr[29]; - /* IMPORTANT: This output MUST be kept under PAGE_SIZE - * or we need to get more sophisticated. */ - - out += sprintf(out, "read-only\n-----------------------\n"); - out += sprintf(out, "V4L Driver version: %d.%d.%d\n", + seq_printf(m, "read-only\n-----------------------\n"); + seq_printf(m, "V4L Driver version: %d.%d.%d\n", CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER); - out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n", + seq_printf(m, "CPIA Version: %d.%02d (%d.%d)\n", cam->params.version.firmwareVersion, cam->params.version.firmwareRevision, cam->params.version.vcVersion, cam->params.version.vcRevision); - out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n", + seq_printf(m, "CPIA PnP-ID: %04x:%04x:%04x\n", cam->params.pnpID.vendor, cam->params.pnpID.product, cam->params.pnpID.deviceRevision); - out += sprintf(out, "VP-Version: %d.%d %04x\n", + seq_printf(m, "VP-Version: %d.%d %04x\n", cam->params.vpVersion.vpVersion, cam->params.vpVersion.vpRevision, cam->params.vpVersion.cameraHeadID); - out += sprintf(out, "system_state: %#04x\n", + seq_printf(m, "system_state: %#04x\n", cam->params.status.systemState); - out += sprintf(out, "grab_state: %#04x\n", + seq_printf(m, "grab_state: %#04x\n", cam->params.status.grabState); - out += sprintf(out, "stream_state: %#04x\n", + seq_printf(m, "stream_state: %#04x\n", cam->params.status.streamState); - out += sprintf(out, "fatal_error: %#04x\n", + seq_printf(m, "fatal_error: %#04x\n", cam->params.status.fatalError); - out += sprintf(out, "cmd_error: %#04x\n", + seq_printf(m, "cmd_error: %#04x\n", cam->params.status.cmdError); - out += sprintf(out, "debug_flags: %#04x\n", + seq_printf(m, "debug_flags: %#04x\n", cam->params.status.debugFlags); - out += sprintf(out, "vp_status: %#04x\n", + seq_printf(m, "vp_status: %#04x\n", cam->params.status.vpStatus); - out += sprintf(out, "error_code: %#04x\n", + seq_printf(m, "error_code: %#04x\n", cam->params.status.errorCode); /* QX3 specific entries */ if (cam->params.qx3.qx3_detected) { - out += sprintf(out, "button: %4d\n", + seq_printf(m, "button: %4d\n", cam->params.qx3.button); - out += sprintf(out, "cradled: %4d\n", + seq_printf(m, "cradled: %4d\n", cam->params.qx3.cradled); } - out += sprintf(out, "video_size: %s\n", + seq_printf(m, "video_size: %s\n", cam->params.format.videoSize == VIDEOSIZE_CIF ? "CIF " : "QCIF"); - out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n", + seq_printf(m, "roi: (%3d, %3d) to (%3d, %3d)\n", cam->params.roi.colStart*8, cam->params.roi.rowStart*4, cam->params.roi.colEnd*8, cam->params.roi.rowEnd*4); - out += sprintf(out, "actual_fps: %3d\n", cam->fps); - out += sprintf(out, "transfer_rate: %4dkB/s\n", + seq_printf(m, "actual_fps: %3d\n", cam->fps); + seq_printf(m, "transfer_rate: %4dkB/s\n", cam->transfer_rate); - out += sprintf(out, "\nread-write\n"); - out += sprintf(out, "----------------------- current min" + seq_printf(m, "\nread-write\n"); + seq_printf(m, "----------------------- current min" " max default comment\n"); - out += sprintf(out, "brightness: %8d %8d %8d %8d\n", + seq_printf(m, "brightness: %8d %8d %8d %8d\n", cam->params.colourParams.brightness, 0, 100, 50); if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) @@ -318,26 +314,26 @@ static int cpia_read_proc(char *page, char **start, off_t off, else tmp = 96; - out += sprintf(out, "contrast: %8d %8d %8d %8d" + seq_printf(m, "contrast: %8d %8d %8d %8d" " steps of 8\n", cam->params.colourParams.contrast, 0, tmp, 48); - out += sprintf(out, "saturation: %8d %8d %8d %8d\n", + seq_printf(m, "saturation: %8d %8d %8d %8d\n", cam->params.colourParams.saturation, 0, 100, 50); tmp = (25000+5000*cam->params.sensorFps.baserate)/ (1<<cam->params.sensorFps.divisor); - out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n", + seq_printf(m, "sensor_fps: %4d.%03d %8d %8d %8d\n", tmp/1000, tmp%1000, 3, 30, 15); - out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n", + seq_printf(m, "stream_start_line: %8d %8d %8d %8d\n", 2*cam->params.streamStartLine, 0, cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144, cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120); - out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n", + seq_printf(m, "sub_sample: %8s %8s %8s %8s\n", cam->params.format.subSample == SUBSAMPLE_420 ? "420" : "422", "420", "422", "422"); - out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n", + seq_printf(m, "yuv_order: %8s %8s %8s %8s\n", cam->params.format.yuvOrder == YUVORDER_YUYV ? "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV"); - out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n", + seq_printf(m, "ecp_timing: %8s %8s %8s %8s\n", cam->params.ecpTiming ? "slow" : "normal", "slow", "normal", "normal"); @@ -346,13 +342,13 @@ static int cpia_read_proc(char *page, char **start, off_t off, } else { sprintf(tmpstr, "manual"); } - out += sprintf(out, "color_balance_mode: %8s %8s %8s" + seq_printf(m, "color_balance_mode: %8s %8s %8s" " %8s\n", tmpstr, "manual", "auto", "auto"); - out += sprintf(out, "red_gain: %8d %8d %8d %8d\n", + seq_printf(m, "red_gain: %8d %8d %8d %8d\n", cam->params.colourBalance.redGain, 0, 212, 32); - out += sprintf(out, "green_gain: %8d %8d %8d %8d\n", + seq_printf(m, "green_gain: %8d %8d %8d %8d\n", cam->params.colourBalance.greenGain, 0, 212, 6); - out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n", + seq_printf(m, "blue_gain: %8d %8d %8d %8d\n", cam->params.colourBalance.blueGain, 0, 212, 92); if (cam->params.version.firmwareVersion == 1 && @@ -363,10 +359,10 @@ static int cpia_read_proc(char *page, char **start, off_t off, sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2); if (cam->params.exposure.gainMode == 0) - out += sprintf(out, "max_gain: unknown %28s" + seq_printf(m, "max_gain: unknown %28s" " powers of 2\n", tmpstr); else - out += sprintf(out, "max_gain: %8d %28s" + seq_printf(m, "max_gain: %8d %28s" " 1,2,4 or 8 \n", 1<<(cam->params.exposure.gainMode-1), tmpstr); @@ -382,12 +378,12 @@ static int cpia_read_proc(char *page, char **start, off_t off, sprintf(tmpstr, "unknown"); break; } - out += sprintf(out, "exposure_mode: %8s %8s %8s" + seq_printf(m, "exposure_mode: %8s %8s %8s" " %8s\n", tmpstr, "manual", "auto", "auto"); - out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n", + seq_printf(m, "centre_weight: %8s %8s %8s %8s\n", (2-cam->params.exposure.centreWeight) ? "on" : "off", "off", "on", "on"); - out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", + seq_printf(m, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n", 1<<cam->params.exposure.gain, 1, 1); if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) @@ -396,7 +392,7 @@ static int cpia_read_proc(char *page, char **start, off_t off, else tmp = 510; - out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n", + seq_printf(m, "fine_exp: %8d %8d %8d %8d\n", cam->params.exposure.fineExp*2, 0, tmp, 0); if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) @@ -405,127 +401,122 @@ static int cpia_read_proc(char *page, char **start, off_t off, else tmp = MAX_EXP; - out += sprintf(out, "coarse_exp: %8d %8d %8d" + seq_printf(m, "coarse_exp: %8d %8d %8d" " %8d\n", cam->params.exposure.coarseExpLo+ 256*cam->params.exposure.coarseExpHi, 0, tmp, 185); - out += sprintf(out, "red_comp: %8d %8d %8d %8d\n", + seq_printf(m, "red_comp: %8d %8d %8d %8d\n", cam->params.exposure.redComp, COMP_RED, 255, COMP_RED); - out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n", + seq_printf(m, "green1_comp: %8d %8d %8d %8d\n", cam->params.exposure.green1Comp, COMP_GREEN1, 255, COMP_GREEN1); - out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n", + seq_printf(m, "green2_comp: %8d %8d %8d %8d\n", cam->params.exposure.green2Comp, COMP_GREEN2, 255, COMP_GREEN2); - out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n", + seq_printf(m, "blue_comp: %8d %8d %8d %8d\n", cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE); - out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n", + seq_printf(m, "apcor_gain1: %#8x %#8x %#8x %#8x\n", cam->params.apcor.gain1, 0, 0xff, 0x1c); - out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n", + seq_printf(m, "apcor_gain2: %#8x %#8x %#8x %#8x\n", cam->params.apcor.gain2, 0, 0xff, 0x1a); - out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n", + seq_printf(m, "apcor_gain4: %#8x %#8x %#8x %#8x\n", cam->params.apcor.gain4, 0, 0xff, 0x2d); - out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n", + seq_printf(m, "apcor_gain8: %#8x %#8x %#8x %#8x\n", cam->params.apcor.gain8, 0, 0xff, 0x2a); - out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n", + seq_printf(m, "vl_offset_gain1: %8d %8d %8d %8d\n", cam->params.vlOffset.gain1, 0, 255, 24); - out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n", + seq_printf(m, "vl_offset_gain2: %8d %8d %8d %8d\n", cam->params.vlOffset.gain2, 0, 255, 28); - out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n", + seq_printf(m, "vl_offset_gain4: %8d %8d %8d %8d\n", cam->params.vlOffset.gain4, 0, 255, 30); - out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n", + seq_printf(m, "vl_offset_gain8: %8d %8d %8d %8d\n", cam->params.vlOffset.gain8, 0, 255, 30); - out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n", + seq_printf(m, "flicker_control: %8s %8s %8s %8s\n", cam->params.flickerControl.flickerMode ? "on" : "off", "off", "on", "off"); - out += sprintf(out, "mains_frequency: %8d %8d %8d %8d" + seq_printf(m, "mains_frequency: %8d %8d %8d %8d" " only 50/60\n", cam->mainsFreq ? 60 : 50, 50, 60, 50); if(cam->params.flickerControl.allowableOverExposure < 0) - out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n", + seq_printf(m, "allowable_overexposure: %4dauto auto %8d auto\n", -cam->params.flickerControl.allowableOverExposure, 255); else - out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n", + seq_printf(m, "allowable_overexposure: %8d auto %8d auto\n", cam->params.flickerControl.allowableOverExposure, 255); - out += sprintf(out, "compression_mode: "); + seq_printf(m, "compression_mode: "); switch(cam->params.compression.mode) { case CPIA_COMPRESSION_NONE: - out += sprintf(out, "%8s", "none"); + seq_printf(m, "%8s", "none"); break; case CPIA_COMPRESSION_AUTO: - out += sprintf(out, "%8s", "auto"); + seq_printf(m, "%8s", "auto"); break; case CPIA_COMPRESSION_MANUAL: - out += sprintf(out, "%8s", "manual"); + seq_printf(m, "%8s", "manual"); break; default: - out += sprintf(out, "%8s", "unknown"); + seq_printf(m, "%8s", "unknown"); break; } - out += sprintf(out, " none,auto,manual auto\n"); - out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n", + seq_printf(m, " none,auto,manual auto\n"); + seq_printf(m, "decimation_enable: %8s %8s %8s %8s\n", cam->params.compression.decimation == DECIMATION_ENAB ? "on":"off", "off", "on", "off"); - out += sprintf(out, "compression_target: %9s %9s %9s %9s\n", + seq_printf(m, "compression_target: %9s %9s %9s %9s\n", cam->params.compressionTarget.frTargeting == CPIA_COMPRESSION_TARGET_FRAMERATE ? "framerate":"quality", "framerate", "quality", "quality"); - out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n", + seq_printf(m, "target_framerate: %8d %8d %8d %8d\n", cam->params.compressionTarget.targetFR, 1, 30, 15); - out += sprintf(out, "target_quality: %8d %8d %8d %8d\n", + seq_printf(m, "target_quality: %8d %8d %8d %8d\n", cam->params.compressionTarget.targetQ, 1, 64, 5); - out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n", + seq_printf(m, "y_threshold: %8d %8d %8d %8d\n", cam->params.yuvThreshold.yThreshold, 0, 31, 6); - out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n", + seq_printf(m, "uv_threshold: %8d %8d %8d %8d\n", cam->params.yuvThreshold.uvThreshold, 0, 31, 6); - out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n", + seq_printf(m, "hysteresis: %8d %8d %8d %8d\n", cam->params.compressionParams.hysteresis, 0, 255, 3); - out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n", + seq_printf(m, "threshold_max: %8d %8d %8d %8d\n", cam->params.compressionParams.threshMax, 0, 255, 11); - out += sprintf(out, "small_step: %8d %8d %8d %8d\n", + seq_printf(m, "small_step: %8d %8d %8d %8d\n", cam->params.compressionParams.smallStep, 0, 255, 1); - out += sprintf(out, "large_step: %8d %8d %8d %8d\n", + seq_printf(m, "large_step: %8d %8d %8d %8d\n", cam->params.compressionParams.largeStep, 0, 255, 3); - out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n", + seq_printf(m, "decimation_hysteresis: %8d %8d %8d %8d\n", cam->params.compressionParams.decimationHysteresis, 0, 255, 2); - out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n", + seq_printf(m, "fr_diff_step_thresh: %8d %8d %8d %8d\n", cam->params.compressionParams.frDiffStepThresh, 0, 255, 5); - out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n", + seq_printf(m, "q_diff_step_thresh: %8d %8d %8d %8d\n", cam->params.compressionParams.qDiffStepThresh, 0, 255, 3); - out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", + seq_printf(m, "decimation_thresh_mod: %8d %8d %8d %8d\n", cam->params.compressionParams.decimationThreshMod, 0, 255, 2); /* QX3 specific entries */ if (cam->params.qx3.qx3_detected) { - out += sprintf(out, "toplight: %8s %8s %8s %8s\n", + seq_printf(m, "toplight: %8s %8s %8s %8s\n", cam->params.qx3.toplight ? "on" : "off", "off", "on", "off"); - out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n", + seq_printf(m, "bottomlight: %8s %8s %8s %8s\n", cam->params.qx3.bottomlight ? "on" : "off", "off", "on", "off"); } - len = out - page; - len -= off; - if (len < count) { - *eof = 1; - if (len <= 0) return 0; - } else - len = count; - - *start = page + off; - return len; + return 0; } +static int cpia_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, cpia_proc_show, PDE(inode)->data); +} -static int match(char *checkstr, char **buffer, unsigned long *count, +static int match(char *checkstr, char **buffer, size_t *count, int *find_colon, int *err) { int ret, colon_found = 1; @@ -551,7 +542,7 @@ static int match(char *checkstr, char **buffer, unsigned long *count, return ret; } -static unsigned long int value(char **buffer, unsigned long *count, int *err) +static unsigned long int value(char **buffer, size_t *count, int *err) { char *p; unsigned long int ret; @@ -565,10 +556,10 @@ static unsigned long int value(char **buffer, unsigned long *count, int *err) return ret; } -static int cpia_write_proc(struct file *file, const char __user *buf, - unsigned long count, void *data) +static ssize_t cpia_proc_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) { - struct cam_data *cam = data; + struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data; struct cam_params new_params; char *page, *buffer; int retval, find_colon; @@ -582,7 +573,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf, * from the comx driver */ if (count > PAGE_SIZE) { - printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE); + printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE); return -ENOSPC; } @@ -1340,23 +1331,28 @@ out: return retval; } +static const struct file_operations cpia_proc_fops = { + .owner = THIS_MODULE, + .open = cpia_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = cpia_proc_write, +}; + static void create_proc_cpia_cam(struct cam_data *cam) { - char name[5 + 1 + 10 + 1]; struct proc_dir_entry *ent; if (!cpia_proc_root || !cam) return; - snprintf(name, sizeof(name), "video%d", cam->vdev.num); - - ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root); + ent = proc_create_data(video_device_node_name(&cam->vdev), + S_IRUGO|S_IWUSR, cpia_proc_root, + &cpia_proc_fops, cam); if (!ent) return; - ent->data = cam; - ent->read_proc = cpia_read_proc; - ent->write_proc = cpia_write_proc; /* size of the proc entry is 3736 bytes for the standard webcam; the extra features of the QX3 microscope add 189 bytes. @@ -1368,13 +1364,10 @@ static void create_proc_cpia_cam(struct cam_data *cam) static void destroy_proc_cpia_cam(struct cam_data *cam) { - char name[5 + 1 + 10 + 1]; - if (!cam || !cam->proc_entry) return; - snprintf(name, sizeof(name), "video%d", cam->vdev.num); - remove_proc_entry(name, cpia_proc_root); + remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root); cam->proc_entry = NULL; } @@ -3999,7 +3992,7 @@ void cpia_unregister_camera(struct cam_data *cam) } #ifdef CONFIG_PROC_FS - DBG("destroying /proc/cpia/video%d\n", cam->vdev.num); + DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev)); destroy_proc_cpia_cam(cam); #endif if (!cam->open_count) { diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 0b4a8f309cfa..6f91415eb7b4 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -38,17 +38,12 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/videodev.h> +#include <linux/stringify.h> #include <media/v4l2-ioctl.h> #include "cpia2.h" #include "cpia2dev.h" - -//#define _CPIA2_DEBUG_ - -#define MAKE_STRING_1(x) #x -#define MAKE_STRING(x) MAKE_STRING_1(x) - static int video_nr = -1; module_param(video_nr, int, 0); MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); @@ -60,26 +55,26 @@ MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k) static int num_buffers = 3; module_param(num_buffers, int, 0); MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" - MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); + __stringify(VIDEO_MAX_FRAME) ", default 3)"); static int alternate = DEFAULT_ALT; module_param(alternate, int, 0); -MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" - MAKE_STRING(USBIF_ISO_6) ", default " - MAKE_STRING(DEFAULT_ALT) ")"); +MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-" + __stringify(USBIF_ISO_6) ", default " + __stringify(DEFAULT_ALT) ")"); static int flicker_freq = 60; module_param(flicker_freq, int, 0); -MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" - MAKE_STRING(60) ", default " - MAKE_STRING(60) ")"); +MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or" + __stringify(60) ", default " + __stringify(60) ")"); static int flicker_mode = NEVER_FLICKER; module_param(flicker_mode, int, 0); MODULE_PARM_DESC(flicker_mode, - "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" - MAKE_STRING(ANTI_FLICKER_ON) ", default " - MAKE_STRING(NEVER_FLICKER) ")"); + "Flicker supression (" __stringify(NEVER_FLICKER) "or" + __stringify(ANTI_FLICKER_ON) ", default " + __stringify(NEVER_FLICKER) ")"); MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); @@ -1926,7 +1921,6 @@ static const struct v4l2_file_operations fops_template = { static struct video_device cpia2_template = { /* I could not find any place for the old .initialize initializer?? */ .name= "CPiA2 Camera", - .minor= -1, .fops= &fops_template, .release= video_device_release, }; @@ -1967,9 +1961,9 @@ void cpia2_unregister_camera(struct camera_data *cam) if (!cam->open_count) { video_unregister_device(cam->vdev); } else { - LOG("/dev/video%d removed while open, " - "deferring video_unregister_device\n", - cam->vdev->num); + LOG("%s removed while open, deferring " + "video_unregister_device\n", + video_device_node_name(cam->vdev)); } } diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c index 4e278db31cc9..c0885c69fd89 100644 --- a/drivers/media/video/cx18/cx18-fileops.c +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -758,8 +758,8 @@ int cx18_v4l2_open(struct file *filp) mutex_lock(&cx->serialize_lock); if (cx18_init_on_first_open(cx)) { - CX18_ERR("Failed to initialize on minor %d\n", - video_dev->minor); + CX18_ERR("Failed to initialize on %s\n", + video_device_node_name(video_dev)); mutex_unlock(&cx->serialize_lock); return -ENXIO; } diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index c398651dd74c..987a9308d938 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c @@ -219,6 +219,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; int vfl_type = cx18_stream_info[type].vfl_type; + const char *name; int num, ret; /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? @@ -258,31 +259,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type) s->video_dev = NULL; return ret; } - num = s->video_dev->num; + + name = video_device_node_name(s->video_dev); switch (vfl_type) { case VFL_TYPE_GRABBER: - CX18_INFO("Registered device video%d for %s " - "(%d x %d.%02d kB)\n", - num, s->name, cx->stream_buffers[type], + CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", + name, s->name, cx->stream_buffers[type], cx->stream_buf_size[type] / 1024, (cx->stream_buf_size[type] * 100 / 1024) % 100); break; case VFL_TYPE_RADIO: - CX18_INFO("Registered device radio%d for %s\n", - num, s->name); + CX18_INFO("Registered device %s for %s\n", name, s->name); break; case VFL_TYPE_VBI: if (cx->stream_buffers[type]) - CX18_INFO("Registered device vbi%d for %s " + CX18_INFO("Registered device %s for %s " "(%d x %d bytes)\n", - num, s->name, cx->stream_buffers[type], + name, s->name, cx->stream_buffers[type], cx->stream_buf_size[type]); else - CX18_INFO("Registered device vbi%d for %s\n", - num, s->name); + CX18_INFO("Registered device %s for %s\n", + name, s->name); break; } diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 319c459459e0..a54908235009 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -68,19 +68,19 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, .amux = CX231XX_AMUX_VIDEO, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, @@ -107,19 +107,19 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, .amux = CX231XX_AMUX_VIDEO, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, @@ -147,19 +147,19 @@ struct cx231xx_board cx231xx_boards[] = { .type = CX231XX_VMUX_TELEVISION, .vmux = CX231XX_VIN_3_1, .amux = CX231XX_AMUX_VIDEO, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_COMPOSITE1, .vmux = CX231XX_VIN_2_1, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, }, { .type = CX231XX_VMUX_SVIDEO, .vmux = CX231XX_VIN_1_1 | (CX231XX_VIN_1_2 << 8) | CX25840_SVIDEO_ON, .amux = CX231XX_AMUX_LINE_IN, - .gpio = 0, + .gpio = NULL, } }, }, @@ -856,8 +856,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface) if (dev->users) { cx231xx_warn - ("device /dev/video%d is open! Deregistration and memory " - "deallocation are deferred on close.\n", dev->vdev->num); + ("device %s is open! Deregistration and memory " + "deallocation are deferred on close.\n", + video_device_node_name(dev->vdev)); dev->state |= DEV_MISCONFIGURED; cx231xx_uninit_isoc(dev); diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c index 0d333e679f70..4a60dfbc347d 100644 --- a/drivers/media/video/cx231xx/cx231xx-core.c +++ b/drivers/media/video/cx231xx/cx231xx-core.c @@ -66,32 +66,6 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); static LIST_HEAD(cx231xx_devlist); static DEFINE_MUTEX(cx231xx_devlist_mutex); -struct cx231xx *cx231xx_get_device(int minor, - enum v4l2_buf_type *fh_type, int *has_radio) -{ - struct cx231xx *h, *dev = NULL; - - *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - *has_radio = 0; - - mutex_lock(&cx231xx_devlist_mutex); - list_for_each_entry(h, &cx231xx_devlist, devlist) { - if (h->vdev->minor == minor) - dev = h; - if (h->vbi_dev->minor == minor) { - dev = h; - *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && h->radio_dev->minor == minor) { - dev = h; - *has_radio = 1; - } - } - mutex_unlock(&cx231xx_devlist_mutex); - - return dev; -} - /* * cx231xx_realease_resources() * unregisters the v4l2,i2c and usb devices diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c index cd135f01b9c1..15826f98b688 100644 --- a/drivers/media/video/cx231xx/cx231xx-input.c +++ b/drivers/media/video/cx231xx/cx231xx-input.c @@ -197,8 +197,7 @@ int cx231xx_ir_init(struct cx231xx *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, - dev->board.ir_codes); + err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); if (err < 0) goto err_out_free; @@ -217,7 +216,7 @@ int cx231xx_ir_init(struct cx231xx *dev) cx231xx_ir_start(ir); /* all done */ - err = input_register_device(ir->input); + err = ir_input_register(ir->input, dev->board.ir_codes); if (err) goto err_out_stop; @@ -226,8 +225,6 @@ err_out_stop: cx231xx_ir_stop(ir); dev->ir = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -241,8 +238,7 @@ int cx231xx_ir_fini(struct cx231xx *dev) return 0; cx231xx_ir_stop(ir); - ir_input_free(ir->input); - input_unregister_device(ir->input); + ir_input_unregister(ir->input); kfree(ir); /* done */ diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c index d095aa0d6d19..d4f546f11d74 100644 --- a/drivers/media/video/cx231xx/cx231xx-video.c +++ b/drivers/media/video/cx231xx/cx231xx-video.c @@ -1916,20 +1916,29 @@ static int radio_queryctrl(struct file *file, void *priv, */ static int cx231xx_v4l2_open(struct file *filp) { - int minor = video_devdata(filp)->minor; int errCode = 0, radio = 0; - struct cx231xx *dev = NULL; + struct video_device *vdev = video_devdata(filp); + struct cx231xx *dev = video_drvdata(filp); struct cx231xx_fh *fh; enum v4l2_buf_type fh_type = 0; - dev = cx231xx_get_device(minor, &fh_type, &radio); - if (NULL == dev) - return -ENODEV; + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } mutex_lock(&dev->lock); - cx231xx_videodbg("open minor=%d type=%s users=%d\n", - minor, v4l2_type_names[fh_type], dev->users); + cx231xx_videodbg("open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[fh_type], + dev->users); #if 0 errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); @@ -2020,25 +2029,25 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) /*FIXME: I2C IR should be disconnected */ if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) + if (video_is_registered(dev->radio_dev)) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; } if (dev->vbi_dev) { - cx231xx_info("V4L2 device /dev/vbi%d deregistered\n", - dev->vbi_dev->num); - if (-1 != dev->vbi_dev->minor) + cx231xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vbi_dev)); + if (video_is_registered(dev->vbi_dev)) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->vdev) { - cx231xx_info("V4L2 device /dev/video%d deregistered\n", - dev->vdev->num); - if (-1 != dev->vdev->minor) + cx231xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vdev)); + if (video_is_registered(dev->vdev)) video_unregister_device(dev->vdev); else video_device_release(dev->vdev); @@ -2268,7 +2277,6 @@ static const struct video_device cx231xx_video_template = { .fops = &cx231xx_v4l_fops, .release = video_device_release, .ioctl_ops = &video_ioctl_ops, - .minor = -1, .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, }; @@ -2303,7 +2311,6 @@ static struct video_device cx231xx_radio_template = { .name = "cx231xx-radio", .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, - .minor = -1, }; /******************************** usb interface ******************************/ @@ -2319,13 +2326,13 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); + video_set_drvdata(vfd, dev); return vfd; } @@ -2374,8 +2381,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) return ret; } - cx231xx_info("%s/0: registered device video%d [v4l2]\n", - dev->name, dev->vdev->num); + cx231xx_info("%s/0: registered device %s [v4l2]\n", + dev->name, video_device_node_name(dev->vdev)); /* Initialize VBI template */ memcpy(&cx231xx_vbi_template, &cx231xx_video_template, @@ -2393,8 +2400,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) return ret; } - cx231xx_info("%s/0: registered device vbi%d\n", - dev->name, dev->vbi_dev->num); + cx231xx_info("%s/0: registered device %s\n", + dev->name, video_device_node_name(dev->vbi_dev)); if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) { dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template, @@ -2409,12 +2416,13 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) cx231xx_errdev("can't register radio device\n"); return ret; } - cx231xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->num); + cx231xx_info("Registered radio device as %s\n", + video_device_node_name(dev->radio_dev)); } - cx231xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", - dev->vdev->num, dev->vbi_dev->num); + cx231xx_info("V4L2 device registered as %s and %s\n", + video_device_node_name(dev->vdev), + video_device_node_name(dev->vbi_dev)); return 0; } diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h index 64e2ddd3c401..17d4d1a800ce 100644 --- a/drivers/media/video/cx231xx/cx231xx.h +++ b/drivers/media/video/cx231xx/cx231xx.h @@ -689,8 +689,6 @@ void cx231xx_release_analog_resources(struct cx231xx *dev); int cx231xx_register_analog_devices(struct cx231xx *dev); void cx231xx_remove_from_devlist(struct cx231xx *dev); void cx231xx_add_into_devlist(struct cx231xx *dev); -struct cx231xx *cx231xx_get_device(int minor, - enum v4l2_buf_type *fh_type, int *has_radio); void cx231xx_init_extension(struct cx231xx *dev); void cx231xx_close_extension(struct cx231xx *dev); diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c index c04222ffb286..d4a9d2c5947c 100644 --- a/drivers/media/video/cx23885/cimax2.c +++ b/drivers/media/video/cx23885/cimax2.c @@ -53,6 +53,8 @@ #define NETUP_CI_CTL 0x04 #define NETUP_CI_RD 1 +#define NETUP_IRQ_DETAM 0x1 +#define NETUP_IRQ_IRQAM 0x4 static unsigned int ci_dbg; module_param(ci_dbg, int, 0644); @@ -73,6 +75,9 @@ struct netup_ci_state { int status; struct work_struct work; void *priv; + u8 current_irq_mode; + int current_ci_flag; + unsigned long next_status_checked_time; }; @@ -169,24 +174,26 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, if (0 != slot) return -EINVAL; - ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &store, 1); - if (ret != 0) - return ret; + if (state->current_ci_flag != flag) { + ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &store, 1); + if (ret != 0) + return ret; - store &= ~0x0c; - store |= flag; + store &= ~0x0c; + store |= flag; - ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &store, 1); - if (ret != 0) - return ret; + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &store, 1); + if (ret != 0) + return ret; + }; + state->current_ci_flag = flag; mutex_lock(&dev->gpio_lock); /* write addr */ cx_write(MC417_OEN, NETUP_EN_ALL); - msleep(2); cx_write(MC417_RWD, NETUP_CTRL_OFF | NETUP_ADLO | (0xff & addr)); cx_clear(MC417_RWD, NETUP_ADLO); @@ -196,7 +203,6 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, if (read) { /* data in */ cx_write(MC417_OEN, NETUP_EN_ALL | NETUP_DATA); - msleep(2); } else /* data out */ cx_write(MC417_RWD, NETUP_CTRL_OFF | data); @@ -213,8 +219,8 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, if (mem < 0) return -EREMOTEIO; - ci_dbg_print("%s: %s: addr=[0x%02x], %s=%x\n", __func__, - (read) ? "read" : "write", addr, + ci_dbg_print("%s: %s: chipaddr=[0x%x] addr=[0x%02x], %s=%x\n", __func__, + (read) ? "read" : "write", state->ci_i2c_addr, addr, (flag == NETUP_CI_CTL) ? "ctl" : "mem", (read) ? mem : data); @@ -283,14 +289,39 @@ int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) return 0; } +int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) +{ + struct netup_ci_state *state = en50221->data; + int ret; + + if (irq_mode == state->current_irq_mode) + return 0; + + ci_dbg_print("%s: chipaddr=[0x%x] setting ci IRQ to [0x%x] \n", + __func__, state->ci_i2c_addr, irq_mode); + ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, + 0x1b, &irq_mode, 1); + + if (ret != 0) + return ret; + + state->current_irq_mode = irq_mode; + + return 0; +} + int netup_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) { struct netup_ci_state *state = en50221->data; - u8 buf = 0x60; + u8 buf; if (0 != slot) return -EINVAL; + netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf, 1); + buf |= 0x60; + return netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, 0, &buf, 1); } @@ -303,21 +334,35 @@ static void netup_read_ci_status(struct work_struct *work) u8 buf[33]; int ret; - ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, - 0, &buf[0], 33); + /* CAM module IRQ processing. fast operation */ + dvb_ca_en50221_frda_irq(&state->ca, 0); - if (ret != 0) - return; + /* CAM module INSERT/REMOVE processing. slow operation because of i2c + * transfers */ + if (time_after(jiffies, state->next_status_checked_time) + || !state->status) { + ret = netup_read_i2c(state->i2c_adap, state->ci_i2c_addr, + 0, &buf[0], 33); + + state->next_status_checked_time = jiffies + + msecs_to_jiffies(1000); + + if (ret != 0) + return; - ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, " - "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0], - buf[32]); + ci_dbg_print("%s: Slot Status Addr=[0x%04x], " + "Reg=[0x%02x], data=%02x, " + "TS config = %02x\n", __func__, + state->ci_i2c_addr, 0, buf[0], + buf[0]); - if (buf[0] & 1) - state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | - DVB_CA_EN50221_POLL_CAM_READY; - else - state->status = 0; + + if (buf[0] & 1) + state->status = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + else + state->status = 0; + }; } /* CI irq handler */ @@ -347,6 +392,9 @@ int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open if (0 != slot) return -EINVAL; + netup_ci_set_irq(en50221, open ? (NETUP_IRQ_DETAM | NETUP_IRQ_IRQAM) + : NETUP_IRQ_DETAM); + return state->status; } @@ -381,8 +429,8 @@ int netup_ci_init(struct cx23885_tsport *port) 0x01, /* power on (use it like store place) */ 0x00, /* RFU */ 0x00, /* int status read only */ - 0x01, /* all int unmasked */ - 0x04, /* int config */ + NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM, /* DETAM, IRQAM unmasked */ + 0x05, /* EXTINT=active-high, INT=push-pull */ 0x00, /* USCG1 */ 0x04, /* ack active low */ 0x00, /* LOCK = 0 */ @@ -422,6 +470,7 @@ int netup_ci_init(struct cx23885_tsport *port) state->ca.poll_slot_status = netup_poll_ci_slot_status; state->ca.data = state; state->priv = port; + state->current_irq_mode = NETUP_IRQ_IRQAM | NETUP_IRQ_DETAM; ret = netup_write_i2c(state->i2c_adap, state->ci_i2c_addr, 0, &cimax_init[0], 34); diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c index 0eed852c61e9..88c0d2481118 100644 --- a/drivers/media/video/cx23885/cx23885-417.c +++ b/drivers/media/video/cx23885/cx23885-417.c @@ -1568,28 +1568,11 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int mpeg_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct cx23885_dev *h, *dev = NULL; - struct list_head *list; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; dprintk(2, "%s()\n", __func__); - lock_kernel(); - list_for_each(list, &cx23885_devlist) { - h = list_entry(list, struct cx23885_dev, devlist); - if (h->v4l_device && - h->v4l_device->minor == minor) { - dev = h; - break; - } - } - - if (dev == NULL) { - unlock_kernel(); - return -ENODEV; - } - /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { @@ -1597,6 +1580,8 @@ static int mpeg_open(struct file *file) return -ENOMEM; } + lock_kernel(); + file->private_data = fh; fh->dev = dev; @@ -1736,7 +1721,6 @@ static struct video_device cx23885_mpeg_template = { .name = "cx23885", .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, - .minor = -1, .tvnorms = CX23885_NORMS, .current_norm = V4L2_STD_NTSC_M, }; @@ -1746,7 +1730,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev) dprintk(1, "%s()\n", __func__); if (dev->v4l_device) { - if (-1 != dev->v4l_device->minor) + if (video_is_registered(dev->v4l_device)) video_unregister_device(dev->v4l_device); else video_device_release(dev->v4l_device); @@ -1803,6 +1787,7 @@ int cx23885_417_register(struct cx23885_dev *dev) /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); + video_set_drvdata(dev->v4l_device, dev); err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { @@ -1810,8 +1795,8 @@ int cx23885_417_register(struct cx23885_dev *dev) return err; } - printk(KERN_INFO "%s: registered device video%d [mpeg]\n", - dev->name, dev->v4l_device->num); + printk(KERN_INFO "%s: registered device %s [mpeg]\n", + dev->name, video_device_node_name(dev->v4l_device)); return 0; } diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c index 04b12d27bc13..0dde57e96d30 100644 --- a/drivers/media/video/cx23885/cx23885-core.c +++ b/drivers/media/video/cx23885/cx23885-core.c @@ -55,9 +55,6 @@ MODULE_PARM_DESC(card, "card type"); static unsigned int cx23885_devcount; -static DEFINE_MUTEX(devlist); -LIST_HEAD(cx23885_devlist); - #define NO_SYNC_LINE (-1U) /* FIXME, these allocations will change when @@ -785,10 +782,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->nr = cx23885_devcount++; sprintf(dev->name, "cx23885[%d]", dev->nr); - mutex_lock(&devlist); - list_add_tail(&dev->devlist, &cx23885_devlist); - mutex_unlock(&devlist); - /* Configure the internal memory */ if (dev->pci->device == 0x8880) { /* Could be 887 or 888, assume a default */ @@ -2008,10 +2001,6 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev) /* unregister stuff */ free_irq(pci_dev->irq, dev); - mutex_lock(&devlist); - list_del(&dev->devlist); - mutex_unlock(&devlist); - cx23885_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); kfree(dev); diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 469e083dd5f8..768eec92ccf9 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -377,7 +377,7 @@ int cx23885_input_init(struct cx23885_dev *dev) cx23885_boards[dev->board].name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); - ret = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + ret = ir_input_init(input_dev, &ir->ir, ir_type); if (ret < 0) goto err_out_free; @@ -397,7 +397,7 @@ int cx23885_input_init(struct cx23885_dev *dev) dev->ir_input = ir; cx23885_input_ir_start(dev); - ret = input_register_device(ir->dev); + ret = ir_input_register(ir->dev, ir_codes); if (ret) goto err_out_stop; @@ -407,8 +407,6 @@ err_out_stop: cx23885_input_ir_stop(dev); dev->ir_input = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return ret; } @@ -420,8 +418,7 @@ void cx23885_input_fini(struct cx23885_dev *dev) if (dev->ir_input == NULL) return; - ir_input_free(dev->ir_input->dev); - input_unregister_device(dev->ir_input->dev); + ir_input_unregister(dev->ir_input->dev); kfree(dev->ir_input); dev->ir_input = NULL; } diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c index 8b372b4f0de2..8934d61cf660 100644 --- a/drivers/media/video/cx23885/cx23885-video.c +++ b/drivers/media/video/cx23885/cx23885-video.c @@ -318,11 +318,11 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx23885_boards[dev->board].name); + video_set_drvdata(vfd, dev); return vfd; } @@ -716,46 +716,34 @@ static int get_resource(struct cx23885_fh *fh) static int video_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct cx23885_dev *h, *dev = NULL; + struct video_device *vdev = video_devdata(file); + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fh *fh; - struct list_head *list; enum v4l2_buf_type type = 0; int radio = 0; - lock_kernel(); - list_for_each(list, &cx23885_devlist) { - h = list_entry(list, struct cx23885_dev, devlist); - if (h->video_dev && - h->video_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev && - h->vbi_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } - } - if (NULL == dev) { - unlock_kernel(); - return -ENODEV; + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; } - dprintk(1, "open minor=%d radio=%d type=%s\n", - minor, radio, v4l2_type_names[type]); + dprintk(1, "open dev=%s radio=%d type=%s\n", + video_device_node_name(vdev), radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - unlock_kernel(); + if (NULL == fh) return -ENOMEM; - } + + lock_kernel(); + file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1441,7 +1429,6 @@ static struct video_device cx23885_vbi_template; static struct video_device cx23885_video_template = { .name = "cx23885-video", .fops = &video_fops, - .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX23885_NORMS, .current_norm = V4L2_STD_NTSC_M, @@ -1461,7 +1448,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) cx_clear(PCI_INT_MSK, 1); if (dev->video_dev) { - if (-1 != dev->video_dev->minor) + if (video_is_registered(dev->video_dev)) video_unregister_device(dev->video_dev); else video_device_release(dev->video_dev); @@ -1532,8 +1519,8 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->num); + printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + dev->name, video_device_node_name(dev->video_dev)); /* initial device configuration */ mutex_lock(&dev->lock); cx23885_set_tvnorm(dev, dev->tvnorm); diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index fa744764dc8b..08b3f6b136a0 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -303,7 +303,6 @@ struct cx23885_tsport { }; struct cx23885_dev { - struct list_head devlist; atomic_t refcount; struct v4l2_device v4l2_dev; @@ -399,8 +398,6 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev) extern struct v4l2_subdev *cx23885_find_hw(struct cx23885_dev *dev, u32 hw); -extern struct list_head cx23885_devlist; - #define SRAM_CH01 0 /* Video A */ #define SRAM_CH02 1 /* VBI A */ #define SRAM_CH03 2 /* Video B */ diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c index 3ccc8afeccf3..2bf57a4527d3 100644 --- a/drivers/media/video/cx23885/cx23888-ir.c +++ b/drivers/media/video/cx23885/cx23888-ir.c @@ -124,15 +124,12 @@ struct cx23888_ir_state { atomic_t rxclk_divider; atomic_t rx_invert; - struct kfifo *rx_kfifo; + struct kfifo rx_kfifo; spinlock_t rx_kfifo_lock; struct v4l2_subdev_ir_parameters tx_params; struct mutex tx_params_lock; atomic_t txclk_divider; - - struct kfifo *tx_kfifo; - spinlock_t tx_kfifo_lock; }; static inline struct cx23888_ir_state *to_state(struct v4l2_subdev *sd) @@ -522,6 +519,7 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, { struct cx23888_ir_state *state = to_state(sd); struct cx23885_dev *dev = state->dev; + unsigned long flags; u32 cntrl = cx23888_ir_read4(dev, CX23888_IR_CNTRL_REG); u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG); @@ -594,8 +592,9 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, if (i == 0) break; j = i * sizeof(u32); - k = kfifo_put(state->rx_kfifo, - (unsigned char *) rx_data, j); + k = kfifo_in_locked(&state->rx_kfifo, + (unsigned char *) rx_data, j, + &state->rx_kfifo_lock); if (k != j) kror++; /* rx_kfifo over run */ } @@ -631,8 +630,11 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status, cx23888_ir_write4(dev, CX23888_IR_CNTRL_REG, cntrl); *handled = true; } - if (kfifo_len(state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) + + spin_lock_irqsave(&state->rx_kfifo_lock, flags); + if (kfifo_len(&state->rx_kfifo) >= CX23888_IR_RX_KFIFO_SIZE / 2) events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ; + spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); if (events) v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events); @@ -657,7 +659,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count, return 0; } - n = kfifo_get(state->rx_kfifo, buf, n); + n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock); n /= sizeof(u32); *num = n * sizeof(u32); @@ -785,7 +787,12 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd, o->interrupt_enable = p->interrupt_enable; o->enable = p->enable; if (p->enable) { - kfifo_reset(state->rx_kfifo); + unsigned long flags; + + spin_lock_irqsave(&state->rx_kfifo_lock, flags); + kfifo_reset(&state->rx_kfifo); + /* reset tx_fifo too if there is one... */ + spin_unlock_irqrestore(&state->rx_kfifo_lock, flags); if (p->interrupt_enable) irqenable_rx(dev, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE); control_rx_enable(dev, p->enable); @@ -892,7 +899,6 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd, o->interrupt_enable = p->interrupt_enable; o->enable = p->enable; if (p->enable) { - kfifo_reset(state->tx_kfifo); if (p->interrupt_enable) irqenable_tx(dev, IRQEN_TSE); control_tx_enable(dev, p->enable); @@ -1168,18 +1174,8 @@ int cx23888_ir_probe(struct cx23885_dev *dev) return -ENOMEM; spin_lock_init(&state->rx_kfifo_lock); - state->rx_kfifo = kfifo_alloc(CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL, - &state->rx_kfifo_lock); - if (state->rx_kfifo == NULL) - return -ENOMEM; - - spin_lock_init(&state->tx_kfifo_lock); - state->tx_kfifo = kfifo_alloc(CX23888_IR_TX_KFIFO_SIZE, GFP_KERNEL, - &state->tx_kfifo_lock); - if (state->tx_kfifo == NULL) { - kfifo_free(state->rx_kfifo); + if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) return -ENOMEM; - } state->dev = dev; state->id = V4L2_IDENT_CX23888_IR; @@ -1211,8 +1207,7 @@ int cx23888_ir_probe(struct cx23885_dev *dev) sizeof(struct v4l2_subdev_ir_parameters)); v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params); } else { - kfifo_free(state->rx_kfifo); - kfifo_free(state->tx_kfifo); + kfifo_free(&state->rx_kfifo); } return ret; } @@ -1231,8 +1226,7 @@ int cx23888_ir_remove(struct cx23885_dev *dev) state = to_state(sd); v4l2_device_unregister_subdev(sd); - kfifo_free(state->rx_kfifo); - kfifo_free(state->tx_kfifo); + kfifo_free(&state->rx_kfifo); kfree(state); /* Nothing more to free() as state held the actual v4l2_subdev object */ return 0; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index fbdc1cde56a6..6fe30e6c4262 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -1048,21 +1048,15 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) static int mpeg_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct cx8802_dev *dev = NULL; + struct video_device *vdev = video_devdata(file); + struct cx8802_dev *dev = video_drvdata(file); struct cx8802_fh *fh; struct cx8802_driver *drv = NULL; int err; - lock_kernel(); - dev = cx8802_get_device(minor); - dprintk( 1, "%s\n", __func__); - if (dev == NULL) { - unlock_kernel(); - return -ENODEV; - } + lock_kernel(); /* Make sure we can acquire the hardware */ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); @@ -1081,7 +1075,7 @@ static int mpeg_open(struct file *file) unlock_kernel(); return -EINVAL; } - dprintk(1,"open minor=%d\n",minor); + dprintk(1, "open dev=%s\n", video_device_node_name(vdev)); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); @@ -1129,10 +1123,6 @@ static int mpeg_release(struct file *file) kfree(fh); /* Make sure we release the hardware */ - dev = cx8802_get_device(video_devdata(file)->minor); - if (dev == NULL) - return -ENODEV; - drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); if (drv) drv->request_release(drv); @@ -1220,7 +1210,6 @@ static struct video_device cx8802_mpeg_template = { .name = "cx8802", .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, - .minor = -1, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, }; @@ -1276,7 +1265,7 @@ static int cx8802_blackbird_advise_release(struct cx8802_driver *drv) static void blackbird_unregister_video(struct cx8802_dev *dev) { if (dev->mpeg_dev) { - if (-1 != dev->mpeg_dev->minor) + if (video_is_registered(dev->mpeg_dev)) video_unregister_device(dev->mpeg_dev); else video_device_release(dev->mpeg_dev); @@ -1290,14 +1279,15 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, &cx8802_mpeg_template,"mpeg"); + video_set_drvdata(dev->mpeg_dev, dev); err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); if (err < 0) { printk(KERN_INFO "%s/2: can't register mpeg device\n", dev->core->name); return err; } - printk(KERN_INFO "%s/2: registered device video%d [mpeg]\n", - dev->core->name, dev->mpeg_dev->num); + printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", + dev->core->name, video_device_node_name(dev->mpeg_dev)); return 0; } diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 92b8cdf9fb81..f9fda18b410c 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -360,7 +360,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name); snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci)); - err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + err = ir_input_init(input_dev, &ir->ir, ir_type); if (err < 0) goto err_out_free; @@ -383,7 +383,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) cx88_ir_start(core, ir); /* all done */ - err = input_register_device(ir->input); + err = ir_input_register(ir->input, ir_codes); if (err) goto err_out_stop; @@ -393,8 +393,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) cx88_ir_stop(core, ir); core->ir = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -408,8 +406,7 @@ int cx88_ir_fini(struct cx88_core *core) return 0; cx88_ir_stop(core, ir); - ir_input_free(ir->input); - input_unregister_device(ir->input); + ir_input_unregister(ir->input); kfree(ir); /* done */ diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index de9ff0fc741f..bb5104893411 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -580,21 +580,6 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) return 0; } -#if defined(CONFIG_VIDEO_CX88_BLACKBIRD) || \ - defined(CONFIG_VIDEO_CX88_BLACKBIRD_MODULE) -struct cx8802_dev *cx8802_get_device(int minor) -{ - struct cx8802_dev *dev; - - list_for_each_entry(dev, &cx8802_devlist, devlist) - if (dev->mpeg_dev && dev->mpeg_dev->minor == minor) - return dev; - - return NULL; -} -EXPORT_SYMBOL(cx8802_get_device); -#endif - struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) { struct cx8802_driver *d; diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index d7e8fcee559c..48c450f4a85a 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -75,10 +75,6 @@ MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes"); #define dprintk(level,fmt, arg...) if (video_debug >= level) \ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) -/* ------------------------------------------------------------------ */ - -static LIST_HEAD(cx8800_devlist); - /* ------------------------------------------------------------------- */ /* static data */ @@ -753,38 +749,31 @@ static int get_ressource(struct cx8800_fh *fh) static int video_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct cx8800_dev *h,*dev = NULL; + struct video_device *vdev = video_devdata(file); + struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core; struct cx8800_fh *fh; enum v4l2_buf_type type = 0; int radio = 0; - lock_kernel(); - list_for_each_entry(h, &cx8800_devlist, devlist) { - if (h->video_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } - } - if (NULL == dev) { - unlock_kernel(); - return -ENODEV; + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; } + lock_kernel(); + core = dev->core; - dprintk(1,"open minor=%d radio=%d type=%s\n", - minor,radio,v4l2_type_names[type]); + dprintk(1, "open dev=%s radio=%d type=%s\n", + video_device_node_name(vdev), radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); @@ -1733,7 +1722,6 @@ static struct video_device cx8800_vbi_template; static struct video_device cx8800_video_template = { .name = "cx8800-video", .fops = &video_fops, - .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, @@ -1769,7 +1757,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static struct video_device cx8800_radio_template = { .name = "cx8800-radio", .fops = &radio_fops, - .minor = -1, .ioctl_ops = &radio_ioctl_ops, }; @@ -1778,21 +1765,21 @@ static struct video_device cx8800_radio_template = { static void cx8800_unregister_video(struct cx8800_dev *dev) { if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) + if (video_is_registered(dev->radio_dev)) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; } if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) + if (video_is_registered(dev->vbi_dev)) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->video_dev) { - if (-1 != dev->video_dev->minor) + if (video_is_registered(dev->video_dev)) video_unregister_device(dev->video_dev); else video_device_release(dev->video_dev); @@ -1909,6 +1896,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); + video_set_drvdata(dev->video_dev, dev); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { @@ -1916,10 +1904,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device video%d [v4l2]\n", - core->name, dev->video_dev->num); + printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", + core->name, video_device_node_name(dev->video_dev)); dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi"); + video_set_drvdata(dev->vbi_dev, dev); err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { @@ -1927,12 +1916,13 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device vbi%d\n", - core->name, dev->vbi_dev->num); + printk(KERN_INFO "%s/0: registered device %s\n", + core->name, video_device_node_name(dev->vbi_dev)); if (core->board.radio.type == CX88_RADIO) { dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); + video_set_drvdata(dev->radio_dev, dev); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { @@ -1940,12 +1930,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, core->name); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device radio%d\n", - core->name, dev->radio_dev->num); + printk(KERN_INFO "%s/0: registered device %s\n", + core->name, video_device_node_name(dev->radio_dev)); } /* everything worked */ - list_add_tail(&dev->devlist,&cx8800_devlist); pci_set_drvdata(pci_dev,dev); /* initial device configuration */ @@ -2001,7 +1990,6 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev) /* free memory */ btcx_riscmem_free(dev->pci,&dev->vidq.stopper); - list_del(&dev->devlist); cx88_core_put(core,dev->pci); kfree(dev); } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e1c521710103..b1499bf604ea 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -423,7 +423,6 @@ struct cx8800_suspend_state { struct cx8800_dev { struct cx88_core *core; - struct list_head devlist; spinlock_t slock; /* various device info */ @@ -670,7 +669,6 @@ int cx88_audio_thread(void *data); int cx8802_register_driver(struct cx8802_driver *drv); int cx8802_unregister_driver(struct cx8802_driver *drv); -struct cx8802_dev *cx8802_get_device(int minor); struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); /* ----------------------------------------------------------- */ diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c index 12a1b3d7132d..de22bc9faf21 100644 --- a/drivers/media/video/davinci/vpfe_capture.c +++ b/drivers/media/video/davinci/vpfe_capture.c @@ -70,7 +70,6 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> -#include <linux/version.h> #include <media/v4l2-common.h> #include <linux/io.h> #include <media/davinci/vpfe_capture.h> @@ -1967,7 +1966,6 @@ static __init int vpfe_probe(struct platform_device *pdev) vfd->release = video_device_release; vfd->fops = &vpfe_fops; vfd->ioctl_ops = &vpfe_ioctl_ops; - vfd->minor = -1; vfd->tvnorms = 0; vfd->current_norm = V4L2_STD_PAL; vfd->v4l2_dev = &vpfe_dev->v4l2_dev; @@ -2071,7 +2069,7 @@ probe_out_video_unregister: probe_out_v4l2_unregister: v4l2_device_unregister(&vpfe_dev->v4l2_dev); probe_out_video_release: - if (vpfe_dev->video_dev->minor == -1) + if (!video_is_registered(vpfe_dev->video_dev)) video_device_release(vpfe_dev->video_dev); probe_out_release_irq: free_irq(vpfe_dev->ccdc_irq0, vpfe_dev); @@ -2091,7 +2089,7 @@ probe_free_dev_mem: /* * vpfe_remove : It un-register device from V4L2 driver */ -static int vpfe_remove(struct platform_device *pdev) +static int __devexit vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe_dev = platform_get_drvdata(pdev); struct resource *res; @@ -2127,7 +2125,7 @@ vpfe_resume(struct device *dev) return -1; } -static struct dev_pm_ops vpfe_dev_pm_ops = { +static const struct dev_pm_ops vpfe_dev_pm_ops = { .suspend = vpfe_suspend, .resume = vpfe_resume, }; diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index 3b8eac31ecae..1f532e31cd49 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -266,7 +266,7 @@ fail: return status; } -static int vpif_remove(struct platform_device *pdev) +static int __devexit vpif_remove(struct platform_device *pdev) { iounmap(vpif_base); release_mem_region(res->start, res_len); diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index d947ee5e4eb4..78130721f578 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -2107,7 +2107,7 @@ vpif_resume(struct device *dev) return -1; } -static struct dev_pm_ops vpif_dev_pm_ops = { +static const struct dev_pm_ops vpif_dev_pm_ops = { .suspend = vpif_suspend, .resume = vpif_resume, }; diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index d14cfb200ed0..dfddef7228dd 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -1347,7 +1347,6 @@ static const struct v4l2_file_operations vpif_fops = { static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, - .minor = -1, .ioctl_ops = &vpif_ioctl_ops, .tvnorms = DM646X_V4L2_STD, .current_norm = V4L2_STD_625_50, diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c index 453236bd7559..7ee72ecd3d81 100644 --- a/drivers/media/video/davinci/vpss.c +++ b/drivers/media/video/davinci/vpss.c @@ -268,7 +268,7 @@ fail1: return status; } -static int vpss_remove(struct platform_device *pdev) +static int __devexit vpss_remove(struct platform_device *pdev) { iounmap(oper_cfg.vpss_bl_regs_base); release_mem_region(oper_cfg.r1->start, oper_cfg.len1); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 82da205047be..25100001ffff 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2285,7 +2285,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev) dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; break; case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - dev->init_data.ir_codes = &ir_codes_hauppauge_new_table; + dev->init_data.ir_codes = &ir_codes_rc5_hauppauge_new_table; dev->init_data.get_key = em28xx_get_key_em_haup; dev->init_data.name = "i2c IR (EM2840 Hauppauge)"; break; @@ -2653,7 +2653,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, INIT_LIST_HEAD(&dev->vbiq.active); INIT_LIST_HEAD(&dev->vbiq.queued); - if (dev->board.has_msp34xx) { /* Send a reset to other chips via gpio */ errCode = em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf7); @@ -2923,9 +2922,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (dev->users) { em28xx_warn - ("device /dev/video%d is open! Deregistration and memory " + ("device %s is open! Deregistration and memory " "deallocation are deferred on close.\n", - dev->vdev->num); + video_device_node_name(dev->vdev)); dev->state |= DEV_MISCONFIGURED; em28xx_uninit_isoc(dev); diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index 3f86d36dff2b..b311d4514bdf 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -216,7 +216,7 @@ int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val) * sets only some bits (specified by bitmask) of a register, by first reading * the actual value */ -static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, +int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask) { int oldval; @@ -1136,34 +1136,6 @@ void em28xx_wake_i2c(struct em28xx *dev) static LIST_HEAD(em28xx_devlist); static DEFINE_MUTEX(em28xx_devlist_mutex); -struct em28xx *em28xx_get_device(int minor, - enum v4l2_buf_type *fh_type, - int *has_radio) -{ - struct em28xx *h, *dev = NULL; - - *fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - *has_radio = 0; - - mutex_lock(&em28xx_devlist_mutex); - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) - dev = h; - if (h->vbi_dev && h->vbi_dev->minor == minor) { - dev = h; - *fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - dev = h; - *has_radio = 1; - } - } - mutex_unlock(&em28xx_devlist_mutex); - - return dev; -} - /* * em28xx_realease_resources() * unregisters the v4l2,i2c and usb devices diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index d96ec7c09dca..af0d935c29be 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -112,10 +112,13 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { unsigned char buf[2]; - unsigned char code; + u16 code; + int size; /* poll IR chip */ - if (2 != i2c_master_recv(ir->c, buf, 2)) + size = i2c_master_recv(ir->c, buf, sizeof(buf)); + + if (size != 2) return -EIO; /* Does eliminate repeated parity code */ @@ -124,16 +127,30 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) ir->old = buf[1]; - /* Rearranges bits to the right order */ - code = ((buf[0]&0x01)<<5) | /* 0010 0000 */ - ((buf[0]&0x02)<<3) | /* 0001 0000 */ - ((buf[0]&0x04)<<1) | /* 0000 1000 */ - ((buf[0]&0x08)>>1) | /* 0000 0100 */ - ((buf[0]&0x10)>>3) | /* 0000 0010 */ - ((buf[0]&0x20)>>5); /* 0000 0001 */ - - i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", - code, buf[0]); + /* + * Rearranges bits to the right order. + * The bit order were determined experimentally by using + * The original Hauppauge Grey IR and another RC5 that uses addr=0x08 + * The RC5 code has 14 bits, but we've experimentally determined + * the meaning for only 11 bits. + * So, the code translation is not complete. Yet, it is enough to + * work with the provided RC5 IR. + */ + code = + ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */ + ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */ + ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */ + ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */ + ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */ + ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */ + ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */ + ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */ + ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */ + ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */ + ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */ + + i2cdprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x%02x)\n", + code, buf[1], buf[0]); /* return key */ *ir_key = code; @@ -337,19 +354,28 @@ int em28xx_ir_init(struct em28xx *dev) goto err_out_free; ir->input = input_dev; + ir_config = EM2874_IR_RC5; + + /* Adjust xclk based o IR table for RC5/NEC tables */ + if (dev->board.ir_codes->ir_type == IR_TYPE_RC5) { + dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; + ir->full_code = 1; + } else if (dev->board.ir_codes->ir_type == IR_TYPE_NEC) { + dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; + ir_config = EM2874_IR_NEC; + ir->full_code = 1; + } + em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, + EM28XX_XCLK_IR_RC5_MODE); /* Setup the proper handler based on the chip */ switch (dev->chip_id) { case CHIP_ID_EM2860: case CHIP_ID_EM2883: - if (dev->model == EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950) - ir->full_code = 1; ir->get_key = default_polling_getkey; break; case CHIP_ID_EM2874: ir->get_key = em2874_polling_getkey; - /* For now we only support RC5, so enable it */ - ir_config = EM2874_IR_RC5; em28xx_write_regs(dev, EM2874_R50_IR_CONFIG, &ir_config, 1); break; default: @@ -367,8 +393,7 @@ int em28xx_ir_init(struct em28xx *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER, - dev->board.ir_codes); + err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER); if (err < 0) goto err_out_free; @@ -387,7 +412,7 @@ int em28xx_ir_init(struct em28xx *dev) em28xx_ir_start(ir); /* all done */ - err = input_register_device(ir->input); + err = ir_input_register(ir->input, dev->board.ir_codes); if (err) goto err_out_stop; @@ -396,8 +421,6 @@ int em28xx_ir_init(struct em28xx *dev) em28xx_ir_stop(ir); dev->ir = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -411,8 +434,7 @@ int em28xx_ir_fini(struct em28xx *dev) return 0; em28xx_ir_stop(ir); - ir_input_free(ir->input); - input_unregister_device(ir->input); + ir_input_unregister(ir->input); kfree(ir); /* done */ diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 7ad65370f274..849b18c94037 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -2081,22 +2081,30 @@ static int radio_queryctrl(struct file *file, void *priv, */ static int em28xx_v4l2_open(struct file *filp) { - int minor = video_devdata(filp)->minor; - int errCode = 0, radio; - struct em28xx *dev; - enum v4l2_buf_type fh_type; + int errCode = 0, radio = 0; + struct video_device *vdev = video_devdata(filp); + struct em28xx *dev = video_drvdata(filp); + enum v4l2_buf_type fh_type = 0; struct em28xx_fh *fh; enum v4l2_field field; - dev = em28xx_get_device(minor, &fh_type, &radio); - - if (NULL == dev) - return -ENODEV; + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; + } mutex_lock(&dev->lock); - em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor, v4l2_type_names[fh_type], dev->users); + em28xx_videodbg("open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[fh_type], + dev->users); fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); @@ -2160,25 +2168,25 @@ void em28xx_release_analog_resources(struct em28xx *dev) /*FIXME: I2C IR should be disconnected */ if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) + if (video_is_registered(dev->radio_dev)) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); dev->radio_dev = NULL; } if (dev->vbi_dev) { - em28xx_info("V4L2 device /dev/vbi%d deregistered\n", - dev->vbi_dev->num); - if (-1 != dev->vbi_dev->minor) + em28xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vbi_dev)); + if (video_is_registered(dev->vbi_dev)) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->vdev) { - em28xx_info("V4L2 device /dev/video%d deregistered\n", - dev->vdev->num); - if (-1 != dev->vdev->minor) + em28xx_info("V4L2 device %s deregistered\n", + video_device_node_name(dev->vdev)); + if (video_is_registered(dev->vdev)) video_unregister_device(dev->vdev); else video_device_release(dev->vdev); @@ -2397,8 +2405,6 @@ static const struct video_device em28xx_video_template = { .release = video_device_release, .ioctl_ops = &video_ioctl_ops, - .minor = -1, - .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, }; @@ -2433,7 +2439,6 @@ static struct video_device em28xx_radio_template = { .name = "em28xx-radio", .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, - .minor = -1, }; /******************************** usb interface ******************************/ @@ -2451,7 +2456,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, return NULL; *vfd = *template; - vfd->minor = -1; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; vfd->debug = video_debug; @@ -2459,6 +2463,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); + video_set_drvdata(vfd, dev); return vfd; } @@ -2540,16 +2545,16 @@ int em28xx_register_analog_devices(struct em28xx *dev) em28xx_errdev("can't register radio device\n"); return ret; } - em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->num); + em28xx_info("Registered radio device as %s\n", + video_device_node_name(dev->radio_dev)); } - em28xx_info("V4L2 video device registered as /dev/video%d\n", - dev->vdev->num); + em28xx_info("V4L2 video device registered as %s\n", + video_device_node_name(dev->vdev)); if (dev->vbi_dev) - em28xx_info("V4L2 VBI device registered as /dev/vbi%d\n", - dev->vbi_dev->num); + em28xx_info("V4L2 VBI device registered as %s\n", + video_device_node_name(dev->vbi_dev)); return 0; } diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 441df644ddbe..80d9b4fa1b97 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -643,6 +643,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val); +int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, + u8 bitmask); int em28xx_read_ac97(struct em28xx *dev, u8 reg); int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val); @@ -666,9 +668,6 @@ int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); void em28xx_wake_i2c(struct em28xx *dev); void em28xx_remove_from_devlist(struct em28xx *dev); void em28xx_add_into_devlist(struct em28xx *dev); -struct em28xx *em28xx_get_device(int minor, - enum v4l2_buf_type *fh_type, - int *has_radio); int em28xx_register_extension(struct em28xx_ops *dev); void em28xx_unregister_extension(struct em28xx_ops *dev); void em28xx_init_extension(struct em28xx *dev); diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c index 88987a57cf7b..e6c23d509862 100644 --- a/drivers/media/video/et61x251/et61x251_core.c +++ b/drivers/media/video/et61x251/et61x251_core.c @@ -587,8 +587,8 @@ static int et61x251_stream_interrupt(struct et61x251_device* cam) else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " - "use it, close and open /dev/video%d again.", - cam->v4ldev->num); + "use it, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1195,7 +1195,8 @@ static void et61x251_release_resources(struct kref *kref) cam = container_of(kref, struct et61x251_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); + DBG(2, "V4L2 device %s deregistered", + video_device_node_name(cam->v4ldev)); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -1236,8 +1237,8 @@ static int et61x251_open(struct file *filp) } if (cam->users) { - DBG(2, "Device /dev/video%d is already in use", - cam->v4ldev->num); + DBG(2, "Device %s is already in use", + video_device_node_name(cam->v4ldev)); DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { @@ -1280,7 +1281,8 @@ static int et61x251_open(struct file *filp) cam->frame_count = 0; et61x251_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); + DBG(3, "Video device %s is open", + video_device_node_name(cam->v4ldev)); out: mutex_unlock(&cam->open_mutex); @@ -1304,7 +1306,8 @@ static int et61x251_release(struct file *filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); + DBG(3, "Video device %s closed", + video_device_node_name(cam->v4ldev)); kref_put(&cam->kref, et61x251_release_resources); @@ -1846,8 +1849,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1859,8 +1862,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg) nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -2069,8 +2072,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -2081,8 +2084,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd, nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -2130,7 +2133,7 @@ et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg) cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->num); + "%s again.", video_device_node_name(cam->v4ldev)); return -EIO; } @@ -2584,7 +2587,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); cam->v4ldev->fops = &et61x251_fops; - cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); @@ -2603,7 +2605,8 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); + DBG(2, "V4L2 device registered as %s", + video_device_node_name(cam->v4ldev)); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; @@ -2654,9 +2657,9 @@ static void et61x251_usb_disconnect(struct usb_interface* intf) DBG(2, "Disconnecting %s...", cam->v4ldev->name); if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred.", - cam->v4ldev->num); + DBG(2, "Device %s is open! Deregistration and memory " + "deallocation are deferred.", + video_device_node_name(cam->v4ldev)); cam->state |= DEV_MISCONFIGURED; et61x251_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index 2f0b8d621e00..c98b5d69c438 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -1046,14 +1046,14 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0572, 0x0041)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c index 9de86419ae1e..fdf4c0ec5e7a 100644 --- a/drivers/media/video/gspca/etoms.c +++ b/drivers/media/video/gspca/etoms.c @@ -864,7 +864,7 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, #if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, @@ -875,7 +875,7 @@ static __devinitdata struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/gl860/gl860-mi1320.c b/drivers/media/video/gspca/gl860/gl860-mi1320.c index 1355e526ee84..c276a7debdec 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi1320.c +++ b/drivers/media/video/gspca/gl860/gl860-mi1320.c @@ -345,7 +345,7 @@ static int mi1320_configure_alt(struct gspca_dev *gspca_dev) return 0; } -int mi1320_camera_settings(struct gspca_dev *gspca_dev) +static int mi1320_camera_settings(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c index 80cb3f1b36f7..7c31b4f2abea 100644 --- a/drivers/media/video/gspca/gl860/gl860-mi2020.c +++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c @@ -769,7 +769,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev) return 0; } -int mi2020_camera_settings(struct gspca_dev *gspca_dev) +static int mi2020_camera_settings(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index a695e0ae13c2..4878c8f66543 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -40,7 +40,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, static void sd_callback(struct gspca_dev *gspca_dev); static int gl860_guess_sensor(struct gspca_dev *gspca_dev, - s32 vendor_id, s32 product_id); + u16 vendor_id, u16 product_id); /*============================ driver options ==============================*/ @@ -326,11 +326,11 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - s32 vendor_id, product_id; + u16 vendor_id, product_id; /* Get USB VendorID and ProductID */ - vendor_id = le16_to_cpu(id->idVendor); - product_id = le16_to_cpu(id->idProduct); + vendor_id = id->idVendor; + product_id = id->idProduct; sd->nbRightUp = 1; sd->nbIm = -1; @@ -534,8 +534,8 @@ static int sd_probe(struct usb_interface *intf, gspca_dev = usb_get_intfdata(intf); PDEBUG(D_PROBE, - "Camera is now controlling video device /dev/video%d", - gspca_dev->vdev.minor); + "Camera is now controlling video device %s", + video_device_node_name(&gspca_dev->vdev)); } return ret; @@ -673,7 +673,7 @@ void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len) } static int gl860_guess_sensor(struct gspca_dev *gspca_dev, - s32 vendor_id, s32 product_id) + u16 vendor_id, u16 product_id) { struct sd *sd = (struct sd *) gspca_dev; u8 probe, nb26, nb96, nOV, ntry; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 4076f8e5a6fc..bd6214d4ab3b 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -304,7 +304,6 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, j = gspca_dev->fr_queue[i]; gspca_dev->cur_frame = &gspca_dev->frame[j]; } - return; } EXPORT_SYMBOL(gspca_frame_add); @@ -321,7 +320,7 @@ static int gspca_is_compressed(__u32 format) return 0; } -static void *rvmalloc(unsigned long size) +static void *rvmalloc(long size) { void *mem; unsigned long adr; @@ -329,7 +328,7 @@ static void *rvmalloc(unsigned long size) mem = vmalloc_32(size); if (mem != NULL) { adr = (unsigned long) mem; - while ((long) size > 0) { + while (size > 0) { SetPageReserved(vmalloc_to_page((void *) adr)); adr += PAGE_SIZE; size -= PAGE_SIZE; @@ -768,6 +767,7 @@ static int vidioc_g_register(struct file *file, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); else @@ -791,6 +791,7 @@ static int vidioc_s_register(struct file *file, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); else @@ -812,6 +813,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); else @@ -983,11 +985,40 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } +static int vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct gspca_dev *gspca_dev = priv; + int mode = wxh_to_mode(gspca_dev, fival->width, fival->height); + __u32 i; + + if (gspca_dev->cam.mode_framerates == NULL || + gspca_dev->cam.mode_framerates[mode].nrates == 0) + return -EINVAL; + + if (fival->pixel_format != + gspca_dev->cam.cam_mode[mode].pixelformat) + return -EINVAL; + + for (i = 0; i < gspca_dev->cam.mode_framerates[mode].nrates; i++) { + if (fival->index == i) { + fival->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fival->discrete.numerator = 1; + fival->discrete.denominator = + gspca_dev->cam.mode_framerates[mode].rates[i]; + return 0; + } + } + + return -EINVAL; +} + static void gspca_release(struct video_device *vfd) { struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); - PDEBUG(D_PROBE, "/dev/video%d released", gspca_dev->vdev.num); + PDEBUG(D_PROBE, "%s released", + video_device_node_name(&gspca_dev->vdev)); kfree(gspca_dev->usb_buf); kfree(gspca_dev); @@ -1053,6 +1084,7 @@ static int dev_close(struct file *file) if (gspca_dev->capt_file == file) { if (gspca_dev->streaming) { mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } @@ -1143,12 +1175,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, continue; ctrls = &gspca_dev->sd_desc->ctrls[i]; } + if (ctrls == NULL) + return -EINVAL; } else { ctrls = get_ctrl(gspca_dev, id); + if (ctrls == NULL) + return -EINVAL; i = ctrls - gspca_dev->sd_desc->ctrls; } - if (ctrls == NULL) - return -EINVAL; memcpy(q_ctrl, ctrls, sizeof *q_ctrl); if (gspca_dev->ctrl_inac & (1 << i)) q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; @@ -1172,6 +1206,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = ctrls->set(gspca_dev, ctrl->value); else @@ -1193,6 +1228,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = ctrls->get(gspca_dev, &ctrl->value); else @@ -1307,6 +1343,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, /* stop streaming */ if (gspca_dev->streaming) { mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); } @@ -1398,6 +1435,7 @@ static int vidioc_streamoff(struct file *file, void *priv, ret = -ERESTARTSYS; goto out; } + gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); @@ -1423,6 +1461,7 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, return -EINVAL; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); else @@ -1441,6 +1480,7 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, return -EINVAL; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); else @@ -1461,6 +1501,7 @@ static int vidioc_g_parm(struct file *filp, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); @@ -1490,6 +1531,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + gspca_dev->usb_err = 0; if (gspca_dev->present) ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); @@ -1613,7 +1655,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) size -= PAGE_SIZE; } - vma->vm_ops = (struct vm_operations_struct *) &gspca_vm_ops; + vma->vm_ops = &gspca_vm_ops; vma->vm_private_data = frame; gspca_vm_open(vma); ret = 0; @@ -1661,6 +1703,7 @@ static int frame_wait(struct gspca_dev *gspca_dev, if (gspca_dev->sd_desc->dq_callback) { mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; if (gspca_dev->present) gspca_dev->sd_desc->dq_callback(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); @@ -1772,6 +1815,8 @@ static int vidioc_qbuf(struct file *file, void *priv, /* put the buffer in the 'queued' queue */ i = gspca_dev->fr_q; gspca_dev->fr_queue[i] = index; + if (gspca_dev->fr_i == i) + gspca_dev->cur_frame = frame; gspca_dev->fr_q = (i + 1) % gspca_dev->nframes; PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d", gspca_dev->fr_q, @@ -1973,6 +2018,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_g_parm = vidioc_g_parm, .vidioc_s_parm = vidioc_s_parm, .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, @@ -1988,7 +2034,6 @@ static struct video_device gspca_template = { .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, .release = gspca_release, - .minor = -1, }; /* @@ -2049,9 +2094,6 @@ int gspca_dev_probe(struct usb_interface *intf, ret = sd_desc->init(gspca_dev); if (ret < 0) goto out; - ret = gspca_set_alt0(gspca_dev); - if (ret < 0) - goto out; gspca_set_default_mode(gspca_dev); mutex_init(&gspca_dev->usb_lock); @@ -2073,7 +2115,7 @@ int gspca_dev_probe(struct usb_interface *intf, } usb_set_intfdata(intf, gspca_dev); - PDEBUG(D_PROBE, "/dev/video%d created", gspca_dev->vdev.num); + PDEBUG(D_PROBE, "%s created", video_device_node_name(&gspca_dev->vdev)); return 0; out: kfree(gspca_dev->usb_buf); @@ -2092,7 +2134,8 @@ void gspca_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); - PDEBUG(D_PROBE, "/dev/video%d disconnect", gspca_dev->vdev.num); + PDEBUG(D_PROBE, "%s disconnect", + video_device_node_name(&gspca_dev->vdev)); mutex_lock(&gspca_dev->usb_lock); gspca_dev->present = 0; diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 181617355ec3..59c7941da999 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -45,11 +45,20 @@ extern int gspca_debug; /* image transfers */ #define MAX_NURBS 4 /* max number of URBs */ + +/* used to list framerates supported by a camera mode (resolution) */ +struct framerates { + int *rates; + int nrates; +}; + /* device information - set at probe time */ struct cam { int bulk_size; /* buffer size when image transfer by bulk */ const struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; + const struct framerates *mode_framerates; /* must have size nmode, + * just like cam_mode */ __u8 bulk_nurbs; /* number of URBs in bulk mode * - cannot be > MAX_NURBS * - when 0 and bulk_size != 0 means @@ -171,6 +180,7 @@ struct gspca_dev { struct mutex usb_lock; /* usb exchange protection */ struct mutex read_lock; /* read protection */ struct mutex queue_lock; /* ISOC queue protection */ + int usb_err; /* USB error - protected by usb_lock */ #ifdef CONFIG_PM char frozen; /* suspend - resume */ #endif diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c index 844fc1d886d1..4294c75e3b11 100644 --- a/drivers/media/video/gspca/m5602/m5602_core.c +++ b/drivers/media/video/gspca/m5602/m5602_core.c @@ -81,7 +81,7 @@ int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) return (err < 0) ? err : 0; } -int m5602_wait_for_i2c(struct sd *sd) +static int m5602_wait_for_i2c(struct sd *sd) { int err; u8 data; @@ -388,7 +388,7 @@ static int m5602_probe(struct usb_interface *intf, THIS_MODULE); } -void m5602_disconnect(struct usb_interface *intf) +static void m5602_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c index c2739d6605a1..923cdd5f7a6b 100644 --- a/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -439,7 +439,7 @@ int ov9650_start(struct sd *sd) err = m5602_write_bridge(sd, res_init_ov9650[i][1], res_init_ov9650[i][2]); else if (res_init_ov9650[i][0] == SENSOR) { - u8 data = res_init_ov9650[i][2]; + data = res_init_ov9650[i][2]; err = m5602_write_sensor(sd, res_init_ov9650[i][1], &data, 1); } diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index a27afeb6f39b..1b536f7d30cf 100644 --- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -48,6 +48,12 @@ static DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xa 2528") } }, { + .ident = "Fujitsu-Siemens Amilo Xi 2428", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 2428") + } + }, { .ident = "Fujitsu-Siemens Amilo Xi 2528", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), @@ -525,7 +531,10 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); if (err < 0) return err; - data = (data & 0xfe) | !val; + if (val) + data &= 0xfe; + else + data |= 0x01; err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); return err; } @@ -570,7 +579,10 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) return err; - data = (data & 0xfe) | !val; + if (val) + data &= 0xfe; + else + data |= 0x01; err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); return err; } diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c index 126d968dd9e0..9154870e07d2 100644 --- a/drivers/media/video/gspca/mr97310a.c +++ b/drivers/media/video/gspca/mr97310a.c @@ -67,7 +67,7 @@ MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); MODULE_LICENSE("GPL"); /* global parameters */ -int force_sensor_type = -1; +static int force_sensor_type = -1; module_param(force_sensor_type, int, 0644); MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index ad9ec339981d..b4f965731244 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -1982,7 +1982,7 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n) { int ret; - *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value); + *((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value); ret = usb_control_msg(sd->gspca_dev.dev, usb_sndctrlpipe(sd->gspca_dev.dev, 0), @@ -2021,9 +2021,9 @@ static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value) if (rc < 0) return rc; - do + do { rc = reg_r(sd, R511_I2C_CTL); - while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ if (rc < 0) return rc; @@ -2055,9 +2055,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg) if (rc < 0) return rc; - do + do { rc = reg_r(sd, R511_I2C_CTL); - while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ if (rc < 0) return rc; @@ -2081,9 +2081,9 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg) if (rc < 0) return rc; - do + do { rc = reg_r(sd, R511_I2C_CTL); - while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ + } while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */ if (rc < 0) return rc; diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 4dbb882c83dc..0a6b8f07a69d 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -1533,7 +1533,7 @@ static void setexposure_96(struct gspca_dev *gspca_dev) static void setsharpness_96(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - u8 val; + s8 val; val = sd->sharpness; if (val < 0) { /* auto */ diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 74acceea8094..de0b66c4b56e 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -90,6 +90,9 @@ struct sd { unsigned char autogain; __u8 hflip; __u8 vflip; + u8 flags; +#define FL_HFLIP 0x01 /* mirrored by default */ +#define FL_VFLIP 0x02 /* vertical flipped by default */ u8 sof_read; u8 autogain_ignore_frames; @@ -552,6 +555,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autogain = AUTOGAIN_DEF; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; + sd->flags = id->driver_info; return 0; } @@ -708,10 +712,17 @@ static int sethvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int ret; - __u8 data; + u8 data, hflip, vflip; + + hflip = sd->hflip; + if (sd->flags & FL_HFLIP) + hflip = !hflip; + vflip = sd->vflip; + if (sd->flags & FL_VFLIP) + vflip = !vflip; ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - data = (sd->hflip ? 0x08 : 0x00) | (sd->vflip ? 0x04 : 0x00); + data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); if (0 <= ret) ret = reg_w(gspca_dev, 0x21, data); /* load registers to sensor (Bit 0, auto clear) */ @@ -1218,15 +1229,15 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x06f8, 0x3009)}, {USB_DEVICE(0x093a, 0x2620)}, {USB_DEVICE(0x093a, 0x2621)}, - {USB_DEVICE(0x093a, 0x2622)}, - {USB_DEVICE(0x093a, 0x2624)}, + {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP}, + {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2626)}, {USB_DEVICE(0x093a, 0x2628)}, - {USB_DEVICE(0x093a, 0x2629)}, + {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x262a)}, {USB_DEVICE(0x093a, 0x262c)}, {} @@ -1234,7 +1245,7 @@ static __devinitdata struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index e5697a6345e8..42cfcdfd8f4f 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -863,7 +863,7 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x093a, 0x2600)}, {USB_DEVICE(0x093a, 0x2601)}, {USB_DEVICE(0x093a, 0x2603)}, @@ -875,7 +875,7 @@ static __devinitdata struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index b1944a7cbb0f..0ca1c06652b1 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -1158,7 +1158,7 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) return i2c_w(gspca_dev, row); } -int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) +static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) { struct sd *sd = (struct sd *) gspca_dev; u8 row[8]; @@ -1183,7 +1183,7 @@ int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) return 0; } -int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) +static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) { struct sd *sd = (struct sd *) gspca_dev; u8 row[8]; @@ -1476,8 +1476,9 @@ static int sn9c20x_input_init(struct gspca_dev *gspca_dev) if (input_register_device(sd->input_dev)) return -EINVAL; - sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%d", - gspca_dev->vdev.minor); + sd->input_task = kthread_run(input_kthread, gspca_dev, "sn9c20x/%s-%s", + gspca_dev->dev->bus->bus_name, + gspca_dev->dev->devpath); if (IS_ERR(sd->input_task)) return -EINVAL; @@ -2174,8 +2175,7 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode) } #define HW_WIN(mode, hstart, vstart) \ -((const u8 []){hstart & 0xff, hstart >> 8, \ -vstart & 0xff, vstart >> 8, \ +((const u8 []){hstart, 0, vstart, 0, \ (mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \ (mode & MODE_SXGA ? 1024 >> 3 : 480 >> 3)}) @@ -2319,7 +2319,7 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) } } if (avg_lum > MAX_AVG_LUM) { - if (sd->gain - 1 >= 0) { + if (sd->gain >= 1) { sd->gain--; set_gain(gspca_dev); } diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 5be95bc65138..ddff2b5ee5c2 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1226,7 +1226,7 @@ static const struct sd_desc sd_desc = { .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */ {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */ #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE @@ -1257,7 +1257,7 @@ static __devinitdata struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/spca506.c b/drivers/media/video/gspca/spca506.c index ab28cc23e415..39257e4e074f 100644 --- a/drivers/media/video/gspca/spca506.c +++ b/drivers/media/video/gspca/spca506.c @@ -685,7 +685,7 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -static __devinitdata struct usb_device_id device_table[] = { +static const struct usb_device_id device_table[] __devinitconst = { {USB_DEVICE(0x06e1, 0xa190)}, /*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 {USB_DEVICE(0x0733, 0x0430)}, */ @@ -696,7 +696,7 @@ static __devinitdata struct usb_device_id device_table[] = { MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ -static int sd_probe(struct usb_interface *intf, +static int __devinit sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c index 8e23320d7ab7..2e2935532d99 100644 --- a/drivers/media/video/gspca/stk014.c +++ b/drivers/media/video/gspca/stk014.c @@ -126,12 +126,14 @@ static const struct v4l2_pix_format vga_mode[] = { }; /* -- read a register -- */ -static int reg_r(struct gspca_dev *gspca_dev, +static u8 reg_r(struct gspca_dev *gspca_dev, __u16 index) { struct usb_device *dev = gspca_dev->dev; int ret; + if (gspca_dev->usb_err < 0) + return 0; ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x00, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -141,18 +143,21 @@ static int reg_r(struct gspca_dev *gspca_dev, 500); if (ret < 0) { PDEBUG(D_ERR, "reg_r err %d", ret); - return ret; + gspca_dev->usb_err = ret; + return 0; } return gspca_dev->usb_buf[0]; } /* -- write a register -- */ -static int reg_w(struct gspca_dev *gspca_dev, +static void reg_w(struct gspca_dev *gspca_dev, __u16 index, __u16 value) { struct usb_device *dev = gspca_dev->dev; int ret; + if (gspca_dev->usb_err < 0) + return; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x01, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -161,13 +166,14 @@ static int reg_w(struct gspca_dev *gspca_dev, NULL, 0, 500); - if (ret < 0) + if (ret < 0) { PDEBUG(D_ERR, "reg_w err %d", ret); - return ret; + gspca_dev->usb_err = ret; + } } /* -- get a bulk value (4 bytes) -- */ -static int rcv_val(struct gspca_dev *gspca_dev, +static void rcv_val(struct gspca_dev *gspca_dev, int ads) { struct usb_device *dev = gspca_dev->dev; @@ -182,17 +188,22 @@ static int rcv_val(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 0x63a, 0); reg_w(gspca_dev, 0x63b, 0); reg_w(gspca_dev, 0x630, 5); + if (gspca_dev->usb_err < 0) + return; ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, 0x05), gspca_dev->usb_buf, 4, /* length */ &alen, 500); /* timeout in milliseconds */ - return ret; + if (ret < 0) { + PDEBUG(D_ERR, "rcv_val err %d", ret); + gspca_dev->usb_err = ret; + } } /* -- send a bulk value -- */ -static int snd_val(struct gspca_dev *gspca_dev, +static void snd_val(struct gspca_dev *gspca_dev, int ads, unsigned int val) { @@ -201,16 +212,9 @@ static int snd_val(struct gspca_dev *gspca_dev, __u8 seq = 0; if (ads == 0x003f08) { - ret = reg_r(gspca_dev, 0x0704); - if (ret < 0) - goto ko; - ret = reg_r(gspca_dev, 0x0705); - if (ret < 0) - goto ko; - seq = ret; /* keep the sequence number */ - ret = reg_r(gspca_dev, 0x0650); - if (ret < 0) - goto ko; + reg_r(gspca_dev, 0x0704); + seq = reg_r(gspca_dev, 0x0705); + reg_r(gspca_dev, 0x0650); reg_w(gspca_dev, 0x654, seq); } else { reg_w(gspca_dev, 0x654, (ads >> 16) & 0xff); @@ -223,6 +227,8 @@ static int snd_val(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 0x65a, 0); reg_w(gspca_dev, 0x65b, 0); reg_w(gspca_dev, 0x650, 5); + if (gspca_dev->usb_err < 0) + return; gspca_dev->usb_buf[0] = val >> 24; gspca_dev->usb_buf[1] = val >> 16; gspca_dev->usb_buf[2] = val >> 8; @@ -233,24 +239,23 @@ static int snd_val(struct gspca_dev *gspca_dev, 4, &alen, 500); /* timeout in milliseconds */ - if (ret < 0) - goto ko; - if (ads == 0x003f08) { - seq += 4; - seq &= 0x3f; - reg_w(gspca_dev, 0x705, seq); + if (ret < 0) { + PDEBUG(D_ERR, "snd_val err %d", ret); + gspca_dev->usb_err = ret; + } else { + if (ads == 0x003f08) { + seq += 4; + seq &= 0x3f; + reg_w(gspca_dev, 0x705, seq); + } } - return ret; -ko: - PDEBUG(D_ERR, "snd_val err %d", ret); - return ret; } /* set a camera parameter */ -static int set_par(struct gspca_dev *gspca_dev, +static void set_par(struct gspca_dev *gspca_dev, int parval) { - return snd_val(gspca_dev, 0x003f08, parval); + snd_val(gspca_dev, 0x003f08, parval); } static void setbrightness(struct gspca_dev *gspca_dev) @@ -311,18 +316,18 @@ static int sd_config(struct gspca_dev *gspca_dev, /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - int ret; + u8 ret; /* check if the device responds */ usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); ret = reg_r(gspca_dev, 0x0740); - if (ret < 0) - return ret; - if (ret != 0xff) { - PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); - return -1; + if (gspca_dev->usb_err >= 0) { + if (ret != 0xff) { + PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret); + gspca_dev->usb_err = -EIO; + } } - return 0; + return gspca_dev->usb_err; } /* -- start the camera -- */ @@ -357,15 +362,12 @@ static int sd_start(struct gspca_dev *gspca_dev) if (ret < 0) { PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed", gspca_dev->iface, gspca_dev->alt); + gspca_dev->usb_err = ret; goto out; } - ret = reg_r(gspca_dev, 0x0630); - if (ret < 0) - goto out; + reg_r(gspca_dev, 0x0630); rcv_val(gspca_dev, 0x000020); /* << (value ff ff ff ff) */ - ret = reg_r(gspca_dev, 0x0650); - if (ret < 0) - goto out; + reg_r(gspca_dev, 0x0650); snd_val(gspca_dev, 0x000020, 0xffffffff); reg_w(gspca_dev, 0x0620, 0); reg_w(gspca_dev, 0x0630, 0); @@ -384,11 +386,11 @@ static int sd_start(struct gspca_dev *gspca_dev) /* start the video flow */ set_par(gspca_dev, 0x01000000); set_par(gspca_dev, 0x01000000); - PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); - return 0; + if (gspca_dev->usb_err >= 0) + PDEBUG(D_STREAM, "camera started alt: 0x%02x", + gspca_dev->alt); out: - PDEBUG(D_ERR|D_STREAM, "camera start err %d", ret); - return ret; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -456,7 +458,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) sd->brightness = val; if (gspca_dev->streaming) setbrightness(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -474,7 +476,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) sd->contrast = val; if (gspca_dev->streaming) setcontrast(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) @@ -492,7 +494,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) sd->colors = val; if (gspca_dev->streaming) setcolors(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) @@ -510,7 +512,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val) sd->lightfreq = val; if (gspca_dev->streaming) setfreq(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) @@ -552,7 +554,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, sd->quality = jcomp->quality; if (gspca_dev->streaming) jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; + return gspca_dev->usb_err; } static int sd_get_jcomp(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index 487d40555343..96c61926d372 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -228,6 +228,7 @@ static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ {NULL, 0x1620, 0x80}, {NULL, 0x1620, 0x00}, + {NULL, 0x1443, 0x00}, {NULL, 0x1423, 0x04}, {x1500, 0x1500, ARRAY_SIZE(x1500)}, {x1536, 0x1536, ARRAY_SIZE(x1536)}, diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 72bf3b4f0a31..306b7d75b4aa 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -460,13 +460,17 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 index, u16 len) { + int ret; + #ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { err("reg_r: buffer overflow"); return; } #endif - usb_control_msg(gspca_dev->dev, + if (gspca_dev->usb_err < 0) + return; + ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, @@ -474,6 +478,10 @@ static void reg_r(struct gspca_dev *gspca_dev, index, len ? gspca_dev->usb_buf : NULL, len, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_r err %d", ret); + gspca_dev->usb_err = ret; + } } /* write one byte */ @@ -483,40 +491,55 @@ static void reg_w_1(struct gspca_dev *gspca_dev, u16 index, u16 byte) { + int ret; + + if (gspca_dev->usb_err < 0) + return; gspca_dev->usb_buf[0] = byte; - usb_control_msg(gspca_dev->dev, + ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, gspca_dev->usb_buf, 1, 500); + if (ret < 0) { + PDEBUG(D_ERR, "reg_w_1 err %d", ret); + gspca_dev->usb_err = ret; + } } /* write req / index / value */ -static int reg_w_riv(struct usb_device *dev, +static void reg_w_riv(struct gspca_dev *gspca_dev, u8 req, u16 index, u16 value) { + struct usb_device *dev = gspca_dev->dev; int ret; + if (gspca_dev->usb_err < 0) + return; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d", - req, index, value, ret); - if (ret < 0) - PDEBUG(D_ERR, "reg write: error %d", ret); - return ret; + if (ret < 0) { + PDEBUG(D_ERR, "reg_w_riv err %d", ret); + gspca_dev->usb_err = ret; + return; + } + PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x", + req, index, value); } /* read 1 byte */ -static int reg_r_1(struct gspca_dev *gspca_dev, +static u8 reg_r_1(struct gspca_dev *gspca_dev, u16 value) /* wValue */ { int ret; + if (gspca_dev->usb_err < 0) + return 0; ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0x20, /* request */ @@ -527,19 +550,22 @@ static int reg_r_1(struct gspca_dev *gspca_dev, 500); /* timeout */ if (ret < 0) { PDEBUG(D_ERR, "reg_r_1 err %d", ret); + gspca_dev->usb_err = ret; return 0; } return gspca_dev->usb_buf[0]; } -/* read 1 or 2 bytes - returns < 0 if error */ -static int reg_r_12(struct gspca_dev *gspca_dev, +/* read 1 or 2 bytes */ +static u16 reg_r_12(struct gspca_dev *gspca_dev, u8 req, /* bRequest */ u16 index, /* wIndex */ u16 length) /* wLength (1 or 2 only) */ { int ret; + if (gspca_dev->usb_err < 0) + return 0; gspca_dev->usb_buf[1] = 0; ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), @@ -550,62 +576,44 @@ static int reg_r_12(struct gspca_dev *gspca_dev, gspca_dev->usb_buf, length, 500); if (ret < 0) { - PDEBUG(D_ERR, "reg_read err %d", ret); - return -1; + PDEBUG(D_ERR, "reg_r_12 err %d", ret); + gspca_dev->usb_err = ret; + return 0; } return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; } -static int write_vector(struct gspca_dev *gspca_dev, +static void write_vector(struct gspca_dev *gspca_dev, const struct cmd *data, int ncmds) { - struct usb_device *dev = gspca_dev->dev; - int ret; - while (--ncmds >= 0) { - ret = reg_w_riv(dev, data->req, data->idx, data->val); - if (ret < 0) { - PDEBUG(D_ERR, - "Register write failed for 0x%02x, 0x%04x, 0x%04x", - data->req, data->val, data->idx); - return ret; - } + reg_w_riv(gspca_dev, data->req, data->idx, data->val); data++; } - return 0; } -static int spca50x_setup_qtable(struct gspca_dev *gspca_dev, - const u8 qtable[2][64]) +static void setup_qtable(struct gspca_dev *gspca_dev, + const u8 qtable[2][64]) { - struct usb_device *dev = gspca_dev->dev; - int i, err; + int i; /* loop over y components */ - for (i = 0; i < 64; i++) { - err = reg_w_riv(dev, 0x00, 0x2800 + i, qtable[0][i]); - if (err < 0) - return err; - } + for (i = 0; i < 64; i++) + reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]); /* loop over c components */ - for (i = 0; i < 64; i++) { - err = reg_w_riv(dev, 0x00, 0x2840 + i, qtable[1][i]); - if (err < 0) - return err; - } - return 0; + for (i = 0; i < 64; i++) + reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]); } static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, u8 req, u16 idx, u16 val) { - struct usb_device *dev = gspca_dev->dev; - int notdone; + u16 notdone; - reg_w_riv(dev, req, idx, val); + reg_w_riv(gspca_dev, req, idx, val); notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - reg_w_riv(dev, req, idx, val); + reg_w_riv(gspca_dev, req, idx, val); PDEBUG(D_FRAM, "before wait 0x%04x", notdone); @@ -616,23 +624,22 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, u8 req, - u16 idx, u16 val, u8 stat, u8 count) + u16 idx, u16 val, u16 endcode, u8 count) { - struct usb_device *dev = gspca_dev->dev; - int status; - u8 endcode; + u16 status; - reg_w_riv(dev, req, idx, val); + reg_w_riv(gspca_dev, req, idx, val); status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); - endcode = stat; - PDEBUG(D_FRAM, "Status 0x%x Need 0x%04x", status, stat); + if (gspca_dev->usb_err < 0) + return; + PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode); if (!count) return; count = 200; while (--count > 0) { msleep(10); /* gsmart mini2 write a each wait setting 1 ms is enough */ -/* reg_w_riv(dev, req, idx, val); */ +/* reg_w_riv(gspca_dev, req, idx, val); */ status = reg_r_12(gspca_dev, 0x01, 0x0001, 1); if (status == endcode) { PDEBUG(D_FRAM, "status 0x%04x after wait %d", @@ -642,7 +649,7 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, } } -static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) +static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev) { int count = 10; @@ -652,7 +659,6 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) break; msleep(10); } - return gspca_dev->usb_buf[0]; } static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) @@ -686,28 +692,26 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; u8 Size; - int rc; Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; switch (sd->bridge) { case BRIDGE_SPCA533: - reg_w_riv(dev, 0x31, 0, 0); + reg_w_riv(gspca_dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ reg_r(gspca_dev, 0x24, 8, 1); reg_w_1(gspca_dev, 0x25, 0, 4, Size); reg_r(gspca_dev, 0x25, 4, 1); /* size */ - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); /* Init the cam width height with some values get on init ? */ - reg_w_riv(dev, 0x31, 0, 0x04); + reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); spca504B_WaitCmdStatus(gspca_dev); - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); break; default: /* case BRIDGE_SPCA504B: */ @@ -716,7 +720,7 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x25, 4, 1); /* size */ reg_w_1(gspca_dev, 0x27, 0, 0, 6); reg_r(gspca_dev, 0x27, 0, 1); /* type */ - rc = spca504B_PollingDataReady(gspca_dev); + spca504B_PollingDataReady(gspca_dev); break; case BRIDGE_SPCA504: Size += 3; @@ -733,8 +737,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) break; case BRIDGE_SPCA504C: /* capture mode */ - reg_w_riv(dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); - reg_w_riv(dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); + reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00); + reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f)); break; } } @@ -762,37 +766,33 @@ static void spca504B_setQtable(struct gspca_dev *gspca_dev) static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7; - reg_w_riv(dev, 0x00, reg, sd->brightness); + reg_w_riv(gspca_dev, 0x00, reg, sd->brightness); } static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8; - reg_w_riv(dev, 0x00, reg, sd->contrast); + reg_w_riv(gspca_dev, 0x00, reg, sd->contrast); } static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; u16 reg; reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae; - reg_w_riv(dev, 0x00, reg, sd->colors); + reg_w_riv(gspca_dev, 0x00, reg, sd->colors); } static void init_ctl_reg(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int pollreg = 1; setbrightness(gspca_dev); @@ -807,14 +807,14 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev) default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA504B: */ - reg_w_riv(dev, 0, 0x00, 0x21ad); /* hue */ - reg_w_riv(dev, 0, 0x01, 0x21ac); /* sat/hue */ - reg_w_riv(dev, 0, 0x00, 0x21a3); /* gamma */ + reg_w_riv(gspca_dev, 0, 0x21ad, 0x00); /* hue */ + reg_w_riv(gspca_dev, 0, 0x21ac, 0x01); /* sat/hue */ + reg_w_riv(gspca_dev, 0, 0x21a3, 0x00); /* gamma */ break; case BRIDGE_SPCA536: - reg_w_riv(dev, 0, 0x40, 0x20f5); - reg_w_riv(dev, 0, 0x01, 0x20f4); - reg_w_riv(dev, 0, 0x00, 0x2089); + reg_w_riv(gspca_dev, 0, 0x20f5, 0x40); + reg_w_riv(gspca_dev, 0, 0x20f4, 0x01); + reg_w_riv(gspca_dev, 0, 0x2089, 0x00); break; } if (pollreg) @@ -881,18 +881,17 @@ static int sd_config(struct gspca_dev *gspca_dev, static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; - int i, err_code; + int i; u8 info[6]; switch (sd->bridge) { case BRIDGE_SPCA504B: - reg_w_riv(dev, 0x1d, 0x00, 0); - reg_w_riv(dev, 0, 0x01, 0x2306); - reg_w_riv(dev, 0, 0x00, 0x0d04); - reg_w_riv(dev, 0, 0x00, 0x2000); - reg_w_riv(dev, 0, 0x13, 0x2301); - reg_w_riv(dev, 0, 0x00, 0x2306); + reg_w_riv(gspca_dev, 0x1d, 0x00, 0); + reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01); + reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00); + reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00); + reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13); + reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00); /* fall thru */ case BRIDGE_SPCA533: spca504B_PollingDataReady(gspca_dev); @@ -904,13 +903,13 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w_1(gspca_dev, 0x24, 0, 0, 0); reg_r(gspca_dev, 0x24, 0, 1); spca504B_PollingDataReady(gspca_dev); - reg_w_riv(dev, 0x34, 0, 0); + reg_w_riv(gspca_dev, 0x34, 0, 0); spca504B_WaitCmdStatus(gspca_dev); break; case BRIDGE_SPCA504C: /* pccam600 */ PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)"); - reg_w_riv(dev, 0xe0, 0x0000, 0x0000); - reg_w_riv(dev, 0xe0, 0x0000, 0x0001); /* reset */ + reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000); + reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */ spca504_wait_status(gspca_dev); if (sd->subtype == LogitechClickSmart420) write_vector(gspca_dev, @@ -919,12 +918,7 @@ static int sd_init(struct gspca_dev *gspca_dev) else write_vector(gspca_dev, spca504_pccam600_open_data, ARRAY_SIZE(spca504_pccam600_open_data)); - err_code = spca50x_setup_qtable(gspca_dev, - qtable_creative_pccam); - if (err_code < 0) { - PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed"); - return err_code; - } + setup_qtable(gspca_dev, qtable_creative_pccam); break; default: /* case BRIDGE_SPCA504: */ @@ -958,29 +952,24 @@ static int sd_init(struct gspca_dev *gspca_dev) 6, 0, 0x86, 1); */ /* spca504A_acknowledged_command (gspca_dev, 0x24, 0, 0, 0x9D, 1); */ - reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ - reg_w_riv(dev, 0x00, 0x2310, 0x05); + reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); + /* L92 sno1t.txt */ + reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); spca504A_acknowledged_command(gspca_dev, 0x01, 0x0f, 0, 0xff, 0); } /* setup qtable */ - reg_w_riv(dev, 0, 0x2000, 0); - reg_w_riv(dev, 0, 0x2883, 1); - err_code = spca50x_setup_qtable(gspca_dev, - qtable_spca504_default); - if (err_code < 0) { - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); - return err_code; - } + reg_w_riv(gspca_dev, 0, 0x2000, 0); + reg_w_riv(gspca_dev, 0, 0x2883, 1); + setup_qtable(gspca_dev, qtable_spca504_default); break; } - return 0; + return gspca_dev->usb_err; } static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int enable; int i; u8 info[6]; @@ -1005,13 +994,13 @@ static int sd_start(struct gspca_dev *gspca_dev) case MegapixV4: case LogitechClickSmart820: case MegaImageVI: - reg_w_riv(dev, 0xf0, 0, 0); + reg_w_riv(gspca_dev, 0xf0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); reg_r(gspca_dev, 0xf0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); break; default: - reg_w_riv(dev, 0x31, 0, 0x04); + reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); break; @@ -1048,8 +1037,9 @@ static int sd_start(struct gspca_dev *gspca_dev) spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); } spca504B_SetSizeType(gspca_dev); - reg_w_riv(dev, 0x00, 0x270c, 0x05); /* L92 sno1t.txt */ - reg_w_riv(dev, 0x00, 0x2310, 0x05); + reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05); + /* L92 sno1t.txt */ + reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05); break; case BRIDGE_SPCA504C: if (sd->subtype == LogitechClickSmart420) { @@ -1061,36 +1051,37 @@ static int sd_start(struct gspca_dev *gspca_dev) ARRAY_SIZE(spca504_pccam600_init_data)); } enable = (sd->autogain ? 0x04 : 0x01); - reg_w_riv(dev, 0x0c, 0x0000, enable); /* auto exposure */ - reg_w_riv(dev, 0xb0, 0x0000, enable); /* auto whiteness */ + reg_w_riv(gspca_dev, 0x0c, 0x0000, enable); + /* auto exposure */ + reg_w_riv(gspca_dev, 0xb0, 0x0000, enable); + /* auto whiteness */ /* set default exposure compensation and whiteness balance */ - reg_w_riv(dev, 0x30, 0x0001, 800); /* ~ 20 fps */ - reg_w_riv(dev, 0x30, 0x0002, 1600); + reg_w_riv(gspca_dev, 0x30, 0x0001, 800); /* ~ 20 fps */ + reg_w_riv(gspca_dev, 0x30, 0x0002, 1600); spca504B_SetSizeType(gspca_dev); break; } init_ctl_reg(gspca_dev); - return 0; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; switch (sd->bridge) { default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ /* case BRIDGE_SPCA504B: */ - reg_w_riv(dev, 0x31, 0, 0); + reg_w_riv(gspca_dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); break; case BRIDGE_SPCA504: case BRIDGE_SPCA504C: - reg_w_riv(dev, 0x00, 0x2000, 0x0000); + reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000); if (sd->subtype == AiptekMiniPenCam13) { /* spca504a aiptek */ @@ -1102,7 +1093,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) 0x0f, 0x00, 0xff, 1); } else { spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); - reg_w_riv(dev, 0x01, 0x000f, 0x0000); + reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000); } break; } @@ -1216,7 +1207,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) sd->brightness = val; if (gspca_dev->streaming) setbrightness(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -1234,7 +1225,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) sd->contrast = val; if (gspca_dev->streaming) setcontrast(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) @@ -1252,7 +1243,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) sd->colors = val; if (gspca_dev->streaming) setcolors(gspca_dev); - return 0; + return gspca_dev->usb_err; } static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) @@ -1292,7 +1283,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev, sd->quality = jcomp->quality; if (gspca_dev->streaming) jpeg_set_qual(sd->jpeg_hdr, sd->quality); - return 0; + return gspca_dev->usb_err; } static int sd_get_jcomp(struct gspca_dev *gspca_dev, diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index c090efcd8045..71921c878424 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -3009,6 +3009,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int l; frame = gspca_get_i_frame(gspca_dev); + if (frame == NULL) { + gspca_dev->last_packet_type = DISCARD_PACKET; + return; + } l = frame->data_end - frame->data; if (len > frame->v4l2_buf.length - l) len = frame->v4l2_buf.length - l; diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 69e5dc4fc9de..1a800fc1c00e 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -5345,9 +5345,6 @@ static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, - {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, @@ -5364,27 +5361,27 @@ static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */ {0xa0, 0xf7, ZC3XX_R101_SENSORCORRECTION}, {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x95, ZC3XX_R18D_YTARGET}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x00, 0x01ad}, {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, {} }; static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, {0xa0, 0x02, ZC3XX_R010_CMOSSENSORSELECT}, {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, {0xa0, 0x00, ZC3XX_R001_SYSTEMOPERATING}, {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, - {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, @@ -5400,13 +5397,15 @@ static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x95, ZC3XX_R18D_YTARGET}, + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, {0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN}, {0xa0, 0x00, 0x01ad}, {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, + {0xa0, 0x07, ZC3XX_R0A5_EXPOSUREGAIN}, + {0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL}, {} }; static const struct usb_action tas5130cxx_50HZ[] = { @@ -6424,11 +6423,11 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev) if (retword != 0) return 0x0e; /* PAS202BCB */ - start_2wr_probe(dev, 0x02); /* ?? */ + start_2wr_probe(dev, 0x02); /* TAS5130C */ i2c_write(gspca_dev, 0x01, 0xaa, 0x00); retword = i2c_read(gspca_dev, 0x01); if (retword != 0) - return 0x02; /* ?? */ + return 0x02; /* TAS5130C */ ov_check: reg_r(gspca_dev, 0x0010); /* ?? */ reg_r(gspca_dev, 0x0010); @@ -6505,6 +6504,8 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x0010); /* value 0x4001 is meaningless */ if (retword != 0x4001) { + if ((retword & 0xff00) == 0x6400) + return 0x02; /* TAS5130C */ for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) { if (chipset_revision_sensor[i].revision == retword) { sd->chip_revision = retword; @@ -6515,7 +6516,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) } } - reg_w(dev, 0x01, 0x0000); /* check ?? */ + reg_w(dev, 0x01, 0x0000); /* check PB0330 */ reg_w(dev, 0x01, 0x0001); reg_w(dev, 0xdd, 0x008b); reg_w(dev, 0x0a, 0x0010); @@ -6524,7 +6525,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) retword = i2c_read(gspca_dev, 0x00); if (retword != 0) { PDEBUG(D_PROBE, "probe 3wr vga type 0a ?"); - return 0x0a; /* ?? */ + return 0x0a; /* PB0330 */ } reg_w(dev, 0x01, 0x0000); @@ -6673,6 +6674,10 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Find Sensor HV7131B"); sd->sensor = SENSOR_HV7131B; break; + case 0x02: + PDEBUG(D_PROBE, "Sensor TAS5130C"); + sd->sensor = SENSOR_TAS5130CXX; + break; case 0x04: PDEBUG(D_PROBE, "Find Sensor CS2102"); sd->sensor = SENSOR_CS2102; @@ -6866,11 +6871,14 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_GC0305: case SENSOR_OV7620: case SENSOR_PO2030: + case SENSOR_TAS5130CXX: case SENSOR_TAS5130C_VF0250: /* msleep(100); * ?? */ reg_r(gspca_dev, 0x0002); /* --> 0x40 */ reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ reg_w(dev, 0x15, 0x01ae); + if (sd->sensor == SENSOR_TAS5130CXX) + break; reg_w(dev, 0x0d, 0x003a); reg_w(dev, 0x02, 0x003b); reg_w(dev, 0x00, 0x0038); @@ -6887,6 +6895,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case SENSOR_PAS202B: case SENSOR_GC0305: + case SENSOR_TAS5130CXX: reg_r(gspca_dev, 0x0008); /* fall thru */ case SENSOR_PO2030: @@ -6928,6 +6937,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(dev, 0x40, 0x0117); break; case SENSOR_GC0305: + case SENSOR_TAS5130CXX: reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ reg_w(dev, 0x15, 0x01ae); /* fall thru */ @@ -7220,7 +7230,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x0ac8, 0x301b)}, {USB_DEVICE(0x0ac8, 0x303b)}, - {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x0ac8, 0x305b)}, {USB_DEVICE(0x0ac8, 0x307b)}, {USB_DEVICE(0x10fd, 0x0128)}, {USB_DEVICE(0x10fd, 0x804d)}, diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c index 1c9bc94c905c..51f393d03a46 100644 --- a/drivers/media/video/hdpvr/hdpvr-core.c +++ b/drivers/media/video/hdpvr/hdpvr-core.c @@ -145,7 +145,7 @@ static int device_authorization(struct hdpvr_device *dev) #ifdef HDPVR_DEBUG else { hex_dump_to_buffer(dev->usbc_buf, 46, 16, 1, print_buf, - sizeof(print_buf), 0); + 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "Status request returned, len %d: %s\n", ret, print_buf); @@ -168,13 +168,13 @@ static int device_authorization(struct hdpvr_device *dev) response = dev->usbc_buf+38; #ifdef HDPVR_DEBUG - hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0); + hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "challenge: %s\n", print_buf); #endif challenge(response); #ifdef HDPVR_DEBUG - hex_dump_to_buffer(response, 8, 16, 1, print_buf, sizeof(print_buf), 0); + hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", print_buf); #endif @@ -376,8 +376,8 @@ static int hdpvr_probe(struct usb_interface *interface, usb_set_intfdata(interface, dev); /* let the user know what node this device is now attached to */ - v4l2_info(&dev->v4l2_dev, "device now attached to /dev/video%d\n", - dev->video_dev->minor); + v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", + video_device_node_name(dev->video_dev)); return 0; error: @@ -391,13 +391,10 @@ error: static void hdpvr_disconnect(struct usb_interface *interface) { struct hdpvr_device *dev; - int minor; dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); - minor = dev->video_dev->minor; - /* prevent more I/O from starting and stop any ongoing */ mutex_lock(&dev->io_mutex); dev->status = STATUS_DISCONNECTED; @@ -425,7 +422,8 @@ static void hdpvr_disconnect(struct usb_interface *interface) atomic_dec(&dev_nr); - v4l2_info(&dev->v4l2_dev, "device /dev/video%d disconnected\n", minor); + v4l2_info(&dev->v4l2_dev, "device %s disconnected\n", + video_device_node_name(dev->video_dev)); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev->usbc_buf); diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index b5439cabb381..fdd782039e9d 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -523,7 +523,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) mutex_lock(&dev->io_mutex); - if (video_is_unregistered(dev->video_dev)) { + if (!video_is_registered(dev->video_dev)) { mutex_unlock(&dev->io_mutex); return -EIO; } diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 64360d26b32d..b86e35386cee 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -353,6 +353,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir_type = IR_TYPE_RC5; ir_codes = &ir_codes_fusionhdtv_mce_table; break; + case 0x0b: case 0x47: case 0x71: if (adap->id == I2C_HW_B_CX2388x || @@ -422,7 +423,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Make sure we are all setup before going on */ if (!name || !ir->get_key || !ir_type || !ir_codes) { - dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n", + dprintk(1, ": Unsupported device at address 0x%02x\n", addr); err = -ENODEV; goto err_out_free; @@ -437,7 +438,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) dev_name(&client->dev)); /* init + register input device */ - err = ir_input_init(input_dev, &ir->ir, ir_type, ir->ir_codes); + err = ir_input_init(input_dev, &ir->ir, ir_type); if (err < 0) goto err_out_free; @@ -445,7 +446,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) input_dev->name = ir->name; input_dev->phys = ir->phys; - err = input_register_device(ir->input); + err = ir_input_register(ir->input, ir->ir_codes); if (err) goto err_out_free; @@ -459,8 +460,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) return 0; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -473,8 +472,7 @@ static int ir_remove(struct i2c_client *client) cancel_delayed_work_sync(&ir->work); /* unregister device */ - ir_input_free(ir->input); - input_unregister_device(ir->input); + ir_input_unregister(ir->input); /* free memory */ kfree(ir); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index e707ef3086b2..babcabd73c08 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -985,8 +985,8 @@ int ivtv_v4l2_open(struct file *filp) mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) { - IVTV_ERR("Failed to initialize on minor %d\n", - vdev->minor); + IVTV_ERR("Failed to initialize on device %s\n", + video_device_node_name(vdev)); mutex_unlock(&itv->serialize_lock); return -ENXIO; } diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 67699e3f2aaa..e12c6022373e 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c @@ -245,6 +245,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) { struct ivtv_stream *s = &itv->streams[type]; int vfl_type = ivtv_stream_info[type].vfl_type; + const char *name; int num; if (s->vdev == NULL) @@ -268,24 +269,24 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) s->vdev = NULL; return -ENOMEM; } - num = s->vdev->num; + name = video_device_node_name(s->vdev); switch (vfl_type) { case VFL_TYPE_GRABBER: - IVTV_INFO("Registered device video%d for %s (%d kB)\n", - num, s->name, itv->options.kilobytes[type]); + IVTV_INFO("Registered device %s for %s (%d kB)\n", + name, s->name, itv->options.kilobytes[type]); break; case VFL_TYPE_RADIO: - IVTV_INFO("Registered device radio%d for %s\n", - num, s->name); + IVTV_INFO("Registered device %s for %s\n", + name, s->name); break; case VFL_TYPE_VBI: if (itv->options.kilobytes[type]) - IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", - num, s->name, itv->options.kilobytes[type]); + IVTV_INFO("Registered device %s for %s (%d kB)\n", + name, s->name, itv->options.kilobytes[type]); else - IVTV_INFO("Registered device vbi%d for %s\n", - num, s->name); + IVTV_INFO("Registered device %s for %s\n", + name, s->name); break; } return 0; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 01e1eefcf1eb..b421858ccf90 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -800,8 +800,8 @@ again: return IRQ_HANDLED; if (meye.mchip_mode == MCHIP_HIC_MODE_CONT_OUT) { - if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, - sizeof(int)) != sizeof(int)) { + if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, + sizeof(int), &meye.grabq_lock) != sizeof(int)) { mchip_free_frame(); return IRQ_HANDLED; } @@ -811,7 +811,8 @@ again: meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); + kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock); wake_up_interruptible(&meye.proc_list); } else { int size; @@ -820,8 +821,8 @@ again: mchip_free_frame(); goto again; } - if (kfifo_get(meye.grabq, (unsigned char *)&reqnr, - sizeof(int)) != sizeof(int)) { + if (kfifo_out_locked(&meye.grabq, (unsigned char *)&reqnr, + sizeof(int), &meye.grabq_lock) != sizeof(int)) { mchip_free_frame(); goto again; } @@ -831,7 +832,8 @@ again: meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; do_gettimeofday(&meye.grab_buffer[reqnr].timestamp); meye.grab_buffer[reqnr].sequence = sequence++; - kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); + kfifo_in_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock); wake_up_interruptible(&meye.proc_list); } mchip_free_frame(); @@ -859,8 +861,8 @@ static int meye_open(struct file *file) for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - kfifo_reset(meye.grabq); - kfifo_reset(meye.doneq); + kfifo_reset(&meye.grabq); + kfifo_reset(&meye.doneq); return 0; } @@ -933,7 +935,8 @@ static int meyeioc_qbuf_capt(int *nb) mchip_cont_compression_start(); meye.grab_buffer[*nb].state = MEYE_BUF_USING; - kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); + kfifo_in_locked(&meye.grabq, (unsigned char *)nb, sizeof(int), + &meye.grabq_lock); mutex_unlock(&meye.lock); return 0; @@ -965,7 +968,9 @@ static int meyeioc_sync(struct file *file, void *fh, int *i) /* fall through */ case MEYE_BUF_DONE: meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; - kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); + if (kfifo_out_locked(&meye.doneq, (unsigned char *)&unused, + sizeof(int), &meye.doneq_lock) != sizeof(int)) + break; } *i = meye.grab_buffer[*i].size; mutex_unlock(&meye.lock); @@ -1452,7 +1457,8 @@ static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags &= ~V4L2_BUF_FLAG_DONE; meye.grab_buffer[buf->index].state = MEYE_BUF_USING; - kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); + kfifo_in_locked(&meye.grabq, (unsigned char *)&buf->index, + sizeof(int), &meye.grabq_lock); mutex_unlock(&meye.lock); return 0; @@ -1467,19 +1473,19 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) mutex_lock(&meye.lock); - if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { + if (kfifo_len(&meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, - kfifo_len(meye.doneq) != 0) < 0) { + kfifo_len(&meye.doneq) != 0) < 0) { mutex_unlock(&meye.lock); return -EINTR; } - if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, - sizeof(int))) { + if (!kfifo_out_locked(&meye.doneq, (unsigned char *)&reqnr, + sizeof(int), &meye.doneq_lock)) { mutex_unlock(&meye.lock); return -EBUSY; } @@ -1529,8 +1535,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) { mutex_lock(&meye.lock); mchip_hic_stop(); - kfifo_reset(meye.grabq); - kfifo_reset(meye.doneq); + kfifo_reset(&meye.grabq); + kfifo_reset(&meye.doneq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; @@ -1572,7 +1578,7 @@ static unsigned int meye_poll(struct file *file, poll_table *wait) mutex_lock(&meye.lock); poll_wait(file, &meye.proc_list, wait); - if (kfifo_len(meye.doneq)) + if (kfifo_len(&meye.doneq)) res = POLLIN | POLLRDNORM; mutex_unlock(&meye.lock); return res; @@ -1681,7 +1687,6 @@ static struct video_device meye_template = { .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, .release = video_device_release, - .minor = -1, }; #ifdef CONFIG_PM @@ -1746,16 +1751,14 @@ static int __devinit meye_probe(struct pci_dev *pcidev, } spin_lock_init(&meye.grabq_lock); - meye.grabq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, - &meye.grabq_lock); - if (IS_ERR(meye.grabq)) { + if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, + GFP_KERNEL)) { printk(KERN_ERR "meye: fifo allocation failed\n"); goto outkfifoalloc1; } spin_lock_init(&meye.doneq_lock); - meye.doneq = kfifo_alloc(sizeof(int) * MEYE_MAX_BUFNBRS, GFP_KERNEL, - &meye.doneq_lock); - if (IS_ERR(meye.doneq)) { + if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, + GFP_KERNEL)) { printk(KERN_ERR "meye: fifo allocation failed\n"); goto outkfifoalloc2; } @@ -1869,9 +1872,9 @@ outregions: outenabledev: sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); outsonypienable: - kfifo_free(meye.doneq); + kfifo_free(&meye.doneq); outkfifoalloc2: - kfifo_free(meye.grabq); + kfifo_free(&meye.grabq); outkfifoalloc1: vfree(meye.grab_temp); outvmalloc: @@ -1902,8 +1905,8 @@ static void __devexit meye_remove(struct pci_dev *pcidev) sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0); - kfifo_free(meye.doneq); - kfifo_free(meye.grabq); + kfifo_free(&meye.doneq); + kfifo_free(&meye.grabq); vfree(meye.grab_temp); diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h index 5f70a106ba2b..1321ad5d6597 100644 --- a/drivers/media/video/meye.h +++ b/drivers/media/video/meye.h @@ -303,9 +303,9 @@ struct meye { struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ struct mutex lock; /* mutex for open/mmap... */ - struct kfifo *grabq; /* queue for buffers to be grabbed */ + struct kfifo grabq; /* queue for buffers to be grabbed */ spinlock_t grabq_lock; /* lock protecting the queue */ - struct kfifo *doneq; /* queue for grabbed buffers */ + struct kfifo doneq; /* queue for grabbed buffers */ spinlock_t doneq_lock; /* lock protecting the queue */ wait_queue_head_t proc_list; /* wait queue */ struct video_device *video_dev; /* video device parameters */ diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 45388d2ce2fd..b62c0bd3f8ea 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -17,9 +17,11 @@ #include <media/v4l2-chip-ident.h> #include <media/soc_camera.h> -/* mt9m001 i2c address 0x5d +/* + * mt9m001 i2c address 0x5d * The platform has to define ctruct i2c_board_info objects and link to them - * from struct soc_camera_link */ + * from struct soc_camera_link + */ /* mt9m001 selected register addresses */ #define MT9M001_CHIP_VERSION 0x00 @@ -46,42 +48,50 @@ #define MT9M001_COLUMN_SKIP 20 #define MT9M001_ROW_SKIP 12 -static const struct soc_camera_data_format mt9m001_colour_formats[] = { - /* Order important: first natively supported, - * second supported with a GPIO extender */ - { - .name = "Bayer (sRGB) 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_SBGGR16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .name = "Bayer (sRGB) 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_SBGGR8, - .colorspace = V4L2_COLORSPACE_SRGB, - } +/* MT9M001 has only one fixed colorspace per pixelcode */ +struct mt9m001_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9m001_datafmt *mt9m001_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9m001_datafmt mt9m001_colour_fmts[] = { + /* + * Order important: first natively supported, + * second supported with a GPIO extender + */ + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, }; -static const struct soc_camera_data_format mt9m001_monochrome_formats[] = { +static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = { /* Order important - see above */ - { - .name = "Monochrome 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_Y16, - }, { - .name = "Monochrome 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_GREY, - }, + {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, }; struct mt9m001 { struct v4l2_subdev subdev; struct v4l2_rect rect; /* Sensor window */ - __u32 fourcc; + const struct mt9m001_datafmt *fmt; + const struct mt9m001_datafmt *fmts; + int num_fmts; int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */ unsigned int gain; unsigned int exposure; + unsigned short y_skip_top; /* Lines to skip at the top */ unsigned char autoexposure; }; @@ -204,8 +214,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) const u16 hblank = 9, vblank = 25; unsigned int total_h; - if (mt9m001->fourcc == V4L2_PIX_FMT_SBGGR8 || - mt9m001->fourcc == V4L2_PIX_FMT_SBGGR16) + if (mt9m001->fmts == mt9m001_colour_fmts) /* * Bayer format - even number of rows for simplicity, * but let the user play with the top row. @@ -222,15 +231,17 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) soc_camera_limit_side(&rect.top, &rect.height, MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT); - total_h = rect.height + icd->y_skip_top + vblank; + total_h = rect.height + mt9m001->y_skip_top + vblank; /* Blanking and start values - default... */ ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); if (!ret) ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); - /* The caller provides a supported format, as verified per - * call to icd->try_fmt() */ + /* + * The caller provides a supported format, as verified per + * call to icd->try_fmt() + */ if (!ret) ret = reg_write(client, MT9M001_COLUMN_START, rect.left); if (!ret) @@ -239,7 +250,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1); if (!ret) ret = reg_write(client, MT9M001_WINDOW_HEIGHT, - rect.height + icd->y_skip_top - 1); + rect.height + mt9m001->y_skip_top - 1); if (!ret && mt9m001->autoexposure) { ret = reg_write(client, MT9M001_SHUTTER_WIDTH, total_h); if (!ret) { @@ -283,32 +294,32 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m001_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m001_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->width = mt9m001->rect.width; - pix->height = mt9m001->rect.height; - pix->pixelformat = mt9m001->fourcc; - pix->field = V4L2_FIELD_NONE; - pix->colorspace = V4L2_COLORSPACE_SRGB; + mf->width = mt9m001->rect.width; + mf->height = mt9m001->rect.height; + mf->code = mt9m001->fmt->code; + mf->colorspace = mt9m001->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; return 0; } -static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m001_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9m001 *mt9m001 = to_mt9m001(client); - struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_crop a = { .c = { .left = mt9m001->rect.left, .top = mt9m001->rect.top, - .width = pix->width, - .height = pix->height, + .width = mf->width, + .height = mf->height, }, }; int ret; @@ -316,28 +327,39 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) /* No support for scaling so far, just crop. TODO: use skipping */ ret = mt9m001_s_crop(sd, &a); if (!ret) { - pix->width = mt9m001->rect.width; - pix->height = mt9m001->rect.height; - mt9m001->fourcc = pix->pixelformat; + mf->width = mt9m001->rect.width; + mf->height = mt9m001->rect.height; + mt9m001->fmt = mt9m001_find_datafmt(mf->code, + mt9m001->fmts, mt9m001->num_fmts); + mf->colorspace = mt9m001->fmt->colorspace; } return ret; } -static int mt9m001_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m001_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct v4l2_pix_format *pix = &f->fmt.pix; + struct mt9m001 *mt9m001 = to_mt9m001(client); + const struct mt9m001_datafmt *fmt; - v4l_bound_align_image(&pix->width, MT9M001_MIN_WIDTH, + v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH, 1, - &pix->height, MT9M001_MIN_HEIGHT + icd->y_skip_top, - MT9M001_MAX_HEIGHT + icd->y_skip_top, 0, 0); + &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, + MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0); + + if (mt9m001->fmts == mt9m001_colour_fmts) + mf->height = ALIGN(mf->height - 1, 2); - if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || - pix->pixelformat == V4L2_PIX_FMT_SBGGR16) - pix->height = ALIGN(pix->height - 1, 2); + fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts, + mt9m001->num_fmts); + if (!fmt) { + fmt = mt9m001->fmt; + mf->code = fmt->code; + } + + mf->colorspace = fmt->colorspace; return 0; } @@ -552,7 +574,7 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (ctrl->value) { const u16 vblank = 25; unsigned int total_h = mt9m001->rect.height + - icd->y_skip_top + vblank; + mt9m001->y_skip_top + vblank; if (reg_write(client, MT9M001_SHUTTER_WIDTH, total_h) < 0) return -EIO; @@ -568,8 +590,10 @@ static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return 0; } -/* Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one */ +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ static int mt9m001_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { @@ -579,8 +603,10 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, unsigned long flags; int ret; - /* We must have a parent by now. And it cannot be a wrong one. - * So this entire test is completely redundant. */ + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ if (!icd->dev.parent || to_soc_camera_host(icd->dev.parent)->nr != icd->iface) return -ENODEV; @@ -597,11 +623,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, case 0x8411: case 0x8421: mt9m001->model = V4L2_IDENT_MT9M001C12ST; - icd->formats = mt9m001_colour_formats; + mt9m001->fmts = mt9m001_colour_fmts; break; case 0x8431: mt9m001->model = V4L2_IDENT_MT9M001C12STM; - icd->formats = mt9m001_monochrome_formats; + mt9m001->fmts = mt9m001_monochrome_fmts; break; default: dev_err(&client->dev, @@ -609,7 +635,7 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, return -ENODEV; } - icd->num_formats = 0; + mt9m001->num_fmts = 0; /* * This is a 10bit sensor, so by default we only allow 10bit. @@ -622,14 +648,14 @@ static int mt9m001_video_probe(struct soc_camera_device *icd, flags = SOCAM_DATAWIDTH_10; if (flags & SOCAM_DATAWIDTH_10) - icd->num_formats++; + mt9m001->num_fmts++; else - icd->formats++; + mt9m001->fmts++; if (flags & SOCAM_DATAWIDTH_8) - icd->num_formats++; + mt9m001->num_fmts++; - mt9m001->fourcc = icd->formats->fourcc; + mt9m001->fmt = &mt9m001->fmts[0]; dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data, data == 0x8431 ? "C12STM" : "C12ST"); @@ -655,6 +681,16 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) icl->free_bus(icl); } +static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); + + *lines = mt9m001->y_skip_top; + + return 0; +} + static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { .g_ctrl = mt9m001_g_ctrl, .s_ctrl = mt9m001_s_ctrl, @@ -665,19 +701,38 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { #endif }; +static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + struct i2c_client *client = sd->priv; + struct mt9m001 *mt9m001 = to_mt9m001(client); + + if ((unsigned int)index >= mt9m001->num_fmts) + return -EINVAL; + + *code = mt9m001->fmts[index].code; + return 0; +} + static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, - .s_fmt = mt9m001_s_fmt, - .g_fmt = mt9m001_g_fmt, - .try_fmt = mt9m001_try_fmt, + .s_mbus_fmt = mt9m001_s_fmt, + .g_mbus_fmt = mt9m001_g_fmt, + .try_mbus_fmt = mt9m001_try_fmt, .s_crop = mt9m001_s_crop, .g_crop = mt9m001_g_crop, .cropcap = mt9m001_cropcap, + .enum_mbus_fmt = mt9m001_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { + .g_skip_top_lines = mt9m001_g_skip_top_lines, }; static struct v4l2_subdev_ops mt9m001_subdev_ops = { .core = &mt9m001_subdev_core_ops, .video = &mt9m001_subdev_video_ops, + .sensor = &mt9m001_subdev_sensor_ops, }; static int mt9m001_probe(struct i2c_client *client, @@ -714,15 +769,17 @@ static int mt9m001_probe(struct i2c_client *client, /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m001_ops; - icd->y_skip_top = 0; + mt9m001->y_skip_top = 0; mt9m001->rect.left = MT9M001_COLUMN_SKIP; mt9m001->rect.top = MT9M001_ROW_SKIP; mt9m001->rect.width = MT9M001_MAX_WIDTH; mt9m001->rect.height = MT9M001_MAX_HEIGHT; - /* Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width */ + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ mt9m001->autoexposure = 1; ret = mt9m001_video_probe(icd, client); diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index 90da699601ea..d35f536f9fc3 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -123,23 +123,34 @@ #define MT9M111_MAX_HEIGHT 1024 #define MT9M111_MAX_WIDTH 1280 -#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ - { .name = _name, .depth = _depth, .fourcc = _fourcc, \ - .colorspace = _colorspace } -#define RGB_FMT(_name, _depth, _fourcc) \ - COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) -#define JPG_FMT(_name, _depth, _fourcc) \ - COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_JPEG) - -static const struct soc_camera_data_format mt9m111_colour_formats[] = { - JPG_FMT("CbYCrY 16 bit", 16, V4L2_PIX_FMT_UYVY), - JPG_FMT("CrYCbY 16 bit", 16, V4L2_PIX_FMT_VYUY), - JPG_FMT("YCbYCr 16 bit", 16, V4L2_PIX_FMT_YUYV), - JPG_FMT("YCrYCb 16 bit", 16, V4L2_PIX_FMT_YVYU), - RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), - RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), - RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), - RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8), +/* MT9M111 has only one fixed colorspace per pixelcode */ +struct mt9m111_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9m111_datafmt *mt9m111_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9m111_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9m111_datafmt mt9m111_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, }; enum mt9m111_context { @@ -152,7 +163,7 @@ struct mt9m111 { int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */ enum mt9m111_context context; struct v4l2_rect rect; - u32 pixfmt; + const struct mt9m111_datafmt *fmt; unsigned int gain; unsigned char autoexposure; unsigned char datawidth; @@ -258,8 +269,8 @@ static int mt9m111_setup_rect(struct i2c_client *client, int width = rect->width; int height = rect->height; - if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || - mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) is_raw_format = 1; else is_raw_format = 0; @@ -307,7 +318,8 @@ static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt) static int mt9m111_setfmt_bayer8(struct i2c_client *client) { - return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER); + return mt9m111_setup_pixfmt(client, MT9M111_OUTFMT_PROCESSED_BAYER | + MT9M111_OUTFMT_RGB); } static int mt9m111_setfmt_bayer10(struct i2c_client *client) @@ -401,8 +413,8 @@ static int mt9m111_make_rect(struct i2c_client *client, { struct mt9m111 *mt9m111 = to_mt9m111(client); - if (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8 || - mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16) { + if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) { /* Bayer format - even size lengths */ rect->width = ALIGN(rect->width, 2); rect->height = ALIGN(rect->height, 2); @@ -460,120 +472,139 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m111_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m111_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9m111 *mt9m111 = to_mt9m111(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->width = mt9m111->rect.width; - pix->height = mt9m111->rect.height; - pix->pixelformat = mt9m111->pixfmt; - pix->field = V4L2_FIELD_NONE; - pix->colorspace = V4L2_COLORSPACE_SRGB; + mf->width = mt9m111->rect.width; + mf->height = mt9m111->rect.height; + mf->code = mt9m111->fmt->code; + mf->field = V4L2_FIELD_NONE; return 0; } -static int mt9m111_set_pixfmt(struct i2c_client *client, u32 pixfmt) +static int mt9m111_set_pixfmt(struct i2c_client *client, + enum v4l2_mbus_pixelcode code) { struct mt9m111 *mt9m111 = to_mt9m111(client); int ret; - switch (pixfmt) { - case V4L2_PIX_FMT_SBGGR8: + switch (code) { + case V4L2_MBUS_FMT_SBGGR8_1X8: ret = mt9m111_setfmt_bayer8(client); break; - case V4L2_PIX_FMT_SBGGR16: + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: ret = mt9m111_setfmt_bayer10(client); break; - case V4L2_PIX_FMT_RGB555: + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: ret = mt9m111_setfmt_rgb555(client); break; - case V4L2_PIX_FMT_RGB565: + case V4L2_MBUS_FMT_RGB565_2X8_LE: ret = mt9m111_setfmt_rgb565(client); break; - case V4L2_PIX_FMT_UYVY: + case V4L2_MBUS_FMT_YUYV8_2X8_BE: mt9m111->swap_yuv_y_chromas = 0; mt9m111->swap_yuv_cb_cr = 0; ret = mt9m111_setfmt_yuv(client); break; - case V4L2_PIX_FMT_VYUY: + case V4L2_MBUS_FMT_YVYU8_2X8_BE: mt9m111->swap_yuv_y_chromas = 0; mt9m111->swap_yuv_cb_cr = 1; ret = mt9m111_setfmt_yuv(client); break; - case V4L2_PIX_FMT_YUYV: + case V4L2_MBUS_FMT_YUYV8_2X8_LE: mt9m111->swap_yuv_y_chromas = 1; mt9m111->swap_yuv_cb_cr = 0; ret = mt9m111_setfmt_yuv(client); break; - case V4L2_PIX_FMT_YVYU: + case V4L2_MBUS_FMT_YVYU8_2X8_LE: mt9m111->swap_yuv_y_chromas = 1; mt9m111->swap_yuv_cb_cr = 1; ret = mt9m111_setfmt_yuv(client); break; default: dev_err(&client->dev, "Pixel format not handled : %x\n", - pixfmt); + code); ret = -EINVAL; } - if (!ret) - mt9m111->pixfmt = pixfmt; - return ret; } -static int mt9m111_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m111_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; + const struct mt9m111_datafmt *fmt; struct mt9m111 *mt9m111 = to_mt9m111(client); - struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_rect rect = { .left = mt9m111->rect.left, .top = mt9m111->rect.top, - .width = pix->width, - .height = pix->height, + .width = mf->width, + .height = mf->height, }; int ret; + fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, + ARRAY_SIZE(mt9m111_colour_fmts)); + if (!fmt) + return -EINVAL; + dev_dbg(&client->dev, - "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", __func__, - pix->pixelformat, rect.left, rect.top, rect.width, rect.height); + "%s code=%x left=%d, top=%d, width=%d, height=%d\n", __func__, + mf->code, rect.left, rect.top, rect.width, rect.height); ret = mt9m111_make_rect(client, &rect); if (!ret) - ret = mt9m111_set_pixfmt(client, pix->pixelformat); - if (!ret) - mt9m111->rect = rect; + ret = mt9m111_set_pixfmt(client, mf->code); + if (!ret) { + mt9m111->rect = rect; + mt9m111->fmt = fmt; + mf->colorspace = fmt->colorspace; + } + return ret; } -static int mt9m111_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9m111_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { - struct v4l2_pix_format *pix = &f->fmt.pix; - bool bayer = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || - pix->pixelformat == V4L2_PIX_FMT_SBGGR16; + struct i2c_client *client = sd->priv; + struct mt9m111 *mt9m111 = to_mt9m111(client); + const struct mt9m111_datafmt *fmt; + bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE; + + fmt = mt9m111_find_datafmt(mf->code, mt9m111_colour_fmts, + ARRAY_SIZE(mt9m111_colour_fmts)); + if (!fmt) { + fmt = mt9m111->fmt; + mf->code = fmt->code; + } /* * With Bayer format enforce even side lengths, but let the user play * with the starting pixel */ - if (pix->height > MT9M111_MAX_HEIGHT) - pix->height = MT9M111_MAX_HEIGHT; - else if (pix->height < 2) - pix->height = 2; + if (mf->height > MT9M111_MAX_HEIGHT) + mf->height = MT9M111_MAX_HEIGHT; + else if (mf->height < 2) + mf->height = 2; else if (bayer) - pix->height = ALIGN(pix->height, 2); + mf->height = ALIGN(mf->height, 2); - if (pix->width > MT9M111_MAX_WIDTH) - pix->width = MT9M111_MAX_WIDTH; - else if (pix->width < 2) - pix->width = 2; + if (mf->width > MT9M111_MAX_WIDTH) + mf->width = MT9M111_MAX_WIDTH; + else if (mf->width < 2) + mf->width = 2; else if (bayer) - pix->width = ALIGN(pix->width, 2); + mf->width = ALIGN(mf->width, 2); + + mf->colorspace = fmt->colorspace; return 0; } @@ -863,7 +894,7 @@ static int mt9m111_restore_state(struct i2c_client *client) struct mt9m111 *mt9m111 = to_mt9m111(client); mt9m111_set_context(client, mt9m111->context); - mt9m111_set_pixfmt(client, mt9m111->pixfmt); + mt9m111_set_pixfmt(client, mt9m111->fmt->code); mt9m111_setup_rect(client, &mt9m111->rect); mt9m111_set_flip(client, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); mt9m111_set_flip(client, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); @@ -952,9 +983,6 @@ static int mt9m111_video_probe(struct soc_camera_device *icd, goto ei2c; } - icd->formats = mt9m111_colour_formats; - icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); - dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data); ei2c: @@ -971,13 +999,24 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { #endif }; +static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts)) + return -EINVAL; + + *code = mt9m111_colour_fmts[index].code; + return 0; +} + static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { - .s_fmt = mt9m111_s_fmt, - .g_fmt = mt9m111_g_fmt, - .try_fmt = mt9m111_try_fmt, + .s_mbus_fmt = mt9m111_s_fmt, + .g_mbus_fmt = mt9m111_g_fmt, + .try_mbus_fmt = mt9m111_try_fmt, .s_crop = mt9m111_s_crop, .g_crop = mt9m111_g_crop, .cropcap = mt9m111_cropcap, + .enum_mbus_fmt = mt9m111_enum_fmt, }; static struct v4l2_subdev_ops mt9m111_subdev_ops = { @@ -1019,12 +1058,12 @@ static int mt9m111_probe(struct i2c_client *client, /* Second stage probe - when a capture adapter is there */ icd->ops = &mt9m111_ops; - icd->y_skip_top = 0; mt9m111->rect.left = MT9M111_MIN_DARK_COLS; mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; mt9m111->rect.width = MT9M111_MAX_WIDTH; mt9m111->rect.height = MT9M111_MAX_HEIGHT; + mt9m111->fmt = &mt9m111_colour_fmts[0]; ret = mt9m111_video_probe(icd, client); if (ret) { diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c index 6966f644977e..a9061bff79b2 100644 --- a/drivers/media/video/mt9t031.c +++ b/drivers/media/video/mt9t031.c @@ -17,9 +17,11 @@ #include <media/v4l2-chip-ident.h> #include <media/soc_camera.h> -/* mt9t031 i2c address 0x5d +/* + * mt9t031 i2c address 0x5d * The platform has to define i2c_board_info and link to it from - * struct soc_camera_link */ + * struct soc_camera_link + */ /* mt9t031 selected register addresses */ #define MT9T031_CHIP_VERSION 0x00 @@ -58,15 +60,6 @@ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \ SOCAM_MASTER | SOCAM_DATAWIDTH_10) -static const struct soc_camera_data_format mt9t031_colour_formats[] = { - { - .name = "Bayer (sRGB) 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_SGRBG10, - .colorspace = V4L2_COLORSPACE_SRGB, - } -}; - struct mt9t031 { struct v4l2_subdev subdev; struct v4l2_rect rect; /* Sensor window */ @@ -74,6 +67,7 @@ struct mt9t031 { u16 xskip; u16 yskip; unsigned int gain; + unsigned short y_skip_top; /* Lines to skip at the top */ unsigned int exposure; unsigned char autoexposure; }; @@ -207,6 +201,71 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd) return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM); } +enum { + MT9T031_CTRL_VFLIP, + MT9T031_CTRL_HFLIP, + MT9T031_CTRL_GAIN, + MT9T031_CTRL_EXPOSURE, + MT9T031_CTRL_EXPOSURE_AUTO, +}; + +static const struct v4l2_queryctrl mt9t031_controls[] = { + [MT9T031_CTRL_VFLIP] = { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + [MT9T031_CTRL_HFLIP] = { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + [MT9T031_CTRL_GAIN] = { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 64, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, + [MT9T031_CTRL_EXPOSURE] = { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 1, + .maximum = 255, + .step = 1, + .default_value = 255, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, + [MT9T031_CTRL_EXPOSURE_AUTO] = { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Automatic Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static struct soc_camera_ops mt9t031_ops = { + .set_bus_param = mt9t031_set_bus_param, + .query_bus_param = mt9t031_query_bus_param, + .controls = mt9t031_controls, + .num_controls = ARRAY_SIZE(mt9t031_controls), +}; + /* target must be _even_ */ static u16 mt9t031_skip(s32 *source, s32 target, s32 max) { @@ -226,10 +285,9 @@ static u16 mt9t031_skip(s32 *source, s32 target, s32 max) } /* rect is the sensor rectangle, the caller guarantees parameter validity */ -static int mt9t031_set_params(struct soc_camera_device *icd, +static int mt9t031_set_params(struct i2c_client *client, struct v4l2_rect *rect, u16 xskip, u16 yskip) { - struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); struct mt9t031 *mt9t031 = to_mt9t031(client); int ret; u16 xbin, ybin; @@ -291,8 +349,10 @@ static int mt9t031_set_params(struct soc_camera_device *icd, dev_dbg(&client->dev, "new physical left %u, top %u\n", rect->left, rect->top); - /* The caller provides a supported format, as guaranteed by - * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */ + /* + * The caller provides a supported format, as guaranteed by + * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() + */ if (ret >= 0) ret = reg_write(client, MT9T031_COLUMN_START, rect->left); if (ret >= 0) @@ -301,15 +361,14 @@ static int mt9t031_set_params(struct soc_camera_device *icd, ret = reg_write(client, MT9T031_WINDOW_WIDTH, rect->width - 1); if (ret >= 0) ret = reg_write(client, MT9T031_WINDOW_HEIGHT, - rect->height + icd->y_skip_top - 1); + rect->height + mt9t031->y_skip_top - 1); if (ret >= 0 && mt9t031->autoexposure) { - unsigned int total_h = rect->height + icd->y_skip_top + vblank; + unsigned int total_h = rect->height + mt9t031->y_skip_top + vblank; ret = set_shutter(client, total_h); if (ret >= 0) { const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; const struct v4l2_queryctrl *qctrl = - soc_camera_find_qctrl(icd->ops, - V4L2_CID_EXPOSURE); + &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * (qctrl->maximum - qctrl->minimum)) / shutter_max + qctrl->minimum; @@ -334,7 +393,6 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) struct v4l2_rect rect = a->c; struct i2c_client *client = sd->priv; struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; rect.width = ALIGN(rect.width, 2); rect.height = ALIGN(rect.height, 2); @@ -345,7 +403,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) soc_camera_limit_side(&rect.top, &rect.height, MT9T031_ROW_SKIP, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT); - return mt9t031_set_params(icd, &rect, mt9t031->xskip, mt9t031->yskip); + return mt9t031_set_params(client, &rect, mt9t031->xskip, mt9t031->yskip); } static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) @@ -373,27 +431,26 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9t031_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9t031_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9t031 *mt9t031 = to_mt9t031(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->width = mt9t031->rect.width / mt9t031->xskip; - pix->height = mt9t031->rect.height / mt9t031->yskip; - pix->pixelformat = V4L2_PIX_FMT_SGRBG10; - pix->field = V4L2_FIELD_NONE; - pix->colorspace = V4L2_COLORSPACE_SRGB; + mf->width = mt9t031->rect.width / mt9t031->xskip; + mf->height = mt9t031->rect.height / mt9t031->yskip; + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + mf->field = V4L2_FIELD_NONE; return 0; } -static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9t031_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; - struct v4l2_pix_format *pix = &f->fmt.pix; u16 xskip, yskip; struct v4l2_rect rect = mt9t031->rect; @@ -401,24 +458,29 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) * try_fmt has put width and height within limits. * S_FMT: use binning and skipping for scaling */ - xskip = mt9t031_skip(&rect.width, pix->width, MT9T031_MAX_WIDTH); - yskip = mt9t031_skip(&rect.height, pix->height, MT9T031_MAX_HEIGHT); + xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); + yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT); + + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; /* mt9t031_set_params() doesn't change width and height */ - return mt9t031_set_params(icd, &rect, xskip, yskip); + return mt9t031_set_params(client, &rect, xskip, yskip); } /* * If a user window larger than sensor window is requested, we'll increase the * sensor window. */ -static int mt9t031_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9t031_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { - struct v4l2_pix_format *pix = &f->fmt.pix; - v4l_bound_align_image( - &pix->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, - &pix->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); + &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, + &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); + + mf->code = V4L2_MBUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; return 0; } @@ -479,59 +541,6 @@ static int mt9t031_s_register(struct v4l2_subdev *sd, } #endif -static const struct v4l2_queryctrl mt9t031_controls[] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Vertically", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip Horizontally", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 64, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 255, - .flags = V4L2_CTRL_FLAG_SLIDER, - }, { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - } -}; - -static struct soc_camera_ops mt9t031_ops = { - .set_bus_param = mt9t031_set_bus_param, - .query_bus_param = mt9t031_query_bus_param, - .controls = mt9t031_controls, - .num_controls = ARRAY_SIZE(mt9t031_controls), -}; - static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = sd->priv; @@ -568,15 +577,9 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = sd->priv; struct mt9t031 *mt9t031 = to_mt9t031(client); - struct soc_camera_device *icd = client->dev.platform_data; const struct v4l2_queryctrl *qctrl; int data; - qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id); - - if (!qctrl) - return -EINVAL; - switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) @@ -595,6 +598,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return -EIO; break; case V4L2_CID_GAIN: + qctrl = &mt9t031_controls[MT9T031_CTRL_GAIN]; if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) return -EINVAL; /* See Datasheet Table 7, Gain settings. */ @@ -634,6 +638,7 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) mt9t031->gain = ctrl->value; break; case V4L2_CID_EXPOSURE: + qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; /* mt9t031 has maximum == default */ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum) return -EINVAL; @@ -657,11 +662,11 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) const u16 vblank = MT9T031_VERTICAL_BLANK; const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; unsigned int total_h = mt9t031->rect.height + - icd->y_skip_top + vblank; + mt9t031->y_skip_top + vblank; if (set_shutter(client, total_h) < 0) return -EIO; - qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); + qctrl = &mt9t031_controls[MT9T031_CTRL_EXPOSURE]; mt9t031->exposure = (shutter_max / 2 + (total_h - 1) * (qctrl->maximum - qctrl->minimum)) / shutter_max + qctrl->minimum; @@ -669,15 +674,18 @@ static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) } else mt9t031->autoexposure = 0; break; + default: + return -EINVAL; } return 0; } -/* Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one */ +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ static int mt9t031_video_probe(struct i2c_client *client) { - struct soc_camera_device *icd = client->dev.platform_data; struct mt9t031 *mt9t031 = to_mt9t031(client); s32 data; int ret; @@ -692,8 +700,6 @@ static int mt9t031_video_probe(struct i2c_client *client) switch (data) { case 0x1621: mt9t031->model = V4L2_IDENT_MT9T031; - icd->formats = mt9t031_colour_formats; - icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats); break; default: dev_err(&client->dev, @@ -714,6 +720,16 @@ static int mt9t031_video_probe(struct i2c_client *client) return ret; } +static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = sd->priv; + struct mt9t031 *mt9t031 = to_mt9t031(client); + + *lines = mt9t031->y_skip_top; + + return 0; +} + static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { .g_ctrl = mt9t031_g_ctrl, .s_ctrl = mt9t031_s_ctrl, @@ -724,19 +740,35 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { #endif }; +static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_SBGGR10_1X10; + return 0; +} + static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_stream = mt9t031_s_stream, - .s_fmt = mt9t031_s_fmt, - .g_fmt = mt9t031_g_fmt, - .try_fmt = mt9t031_try_fmt, + .s_mbus_fmt = mt9t031_s_fmt, + .g_mbus_fmt = mt9t031_g_fmt, + .try_mbus_fmt = mt9t031_try_fmt, .s_crop = mt9t031_s_crop, .g_crop = mt9t031_g_crop, .cropcap = mt9t031_cropcap, + .enum_mbus_fmt = mt9t031_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { + .g_skip_top_lines = mt9t031_g_skip_top_lines, }; static struct v4l2_subdev_ops mt9t031_subdev_ops = { .core = &mt9t031_subdev_core_ops, .video = &mt9t031_subdev_video_ops, + .sensor = &mt9t031_subdev_sensor_ops, }; static int mt9t031_probe(struct i2c_client *client, @@ -745,18 +777,16 @@ static int mt9t031_probe(struct i2c_client *client, struct mt9t031 *mt9t031; struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - struct soc_camera_link *icl; int ret; - if (!icd) { - dev_err(&client->dev, "MT9T031: missing soc-camera data!\n"); - return -EINVAL; - } + if (icd) { + struct soc_camera_link *icl = to_soc_camera_link(icd); + if (!icl) { + dev_err(&client->dev, "MT9T031 driver needs platform data\n"); + return -EINVAL; + } - icl = to_soc_camera_link(icd); - if (!icl) { - dev_err(&client->dev, "MT9T031 driver needs platform data\n"); - return -EINVAL; + icd->ops = &mt9t031_ops; } if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -771,17 +801,16 @@ static int mt9t031_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&mt9t031->subdev, client, &mt9t031_subdev_ops); - /* Second stage probe - when a capture adapter is there */ - icd->ops = &mt9t031_ops; - icd->y_skip_top = 0; - + mt9t031->y_skip_top = 0; mt9t031->rect.left = MT9T031_COLUMN_SKIP; mt9t031->rect.top = MT9T031_ROW_SKIP; mt9t031->rect.width = MT9T031_MAX_WIDTH; mt9t031->rect.height = MT9T031_MAX_HEIGHT; - /* Simulated autoexposure. If enabled, we calculate shutter width - * ourselves in the driver based on vertical blanking and frame width */ + /* + * Simulated autoexposure. If enabled, we calculate shutter width + * ourselves in the driver based on vertical blanking and frame width + */ mt9t031->autoexposure = 1; mt9t031->xskip = 1; @@ -794,7 +823,8 @@ static int mt9t031_probe(struct i2c_client *client, mt9t031_disable(client); if (ret) { - icd->ops = NULL; + if (icd) + icd->ops = NULL; i2c_set_clientdata(client, NULL); kfree(mt9t031); } @@ -807,7 +837,8 @@ static int mt9t031_remove(struct i2c_client *client) struct mt9t031 *mt9t031 = to_mt9t031(client); struct soc_camera_device *icd = client->dev.platform_data; - icd->ops = NULL; + if (icd) + icd->ops = NULL; i2c_set_clientdata(client, NULL); client->driver = NULL; kfree(mt9t031); diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c new file mode 100644 index 000000000000..fc4dd6045720 --- /dev/null +++ b/drivers/media/video/mt9t112.c @@ -0,0 +1,1177 @@ +/* + * mt9t112 Camera Driver + * + * Copyright (C) 2009 Renesas Solutions Corp. + * Kuninori Morimoto <morimoto.kuninori@renesas.com> + * + * Based on ov772x driver, mt9m111 driver, + * + * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> + * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> + * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> + * Copyright (C) 2008 Magnus Damm + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/videodev2.h> + +#include <media/mt9t112.h> +#include <media/soc_camera.h> +#include <media/soc_mediabus.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-common.h> + +/* you can check PLL/clock info */ +/* #define EXT_CLOCK 24000000 */ + +/************************************************************************ + + + macro + + +************************************************************************/ +/* + * frame size + */ +#define MAX_WIDTH 2048 +#define MAX_HEIGHT 1536 + +#define VGA_WIDTH 640 +#define VGA_HEIGHT 480 + +/* + * macro of read/write + */ +#define ECHECKER(ret, x) \ + do { \ + (ret) = (x); \ + if ((ret) < 0) \ + return (ret); \ + } while (0) + +#define mt9t112_reg_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_reg_write(client, a, b)) +#define mt9t112_mcu_write(ret, client, a, b) \ + ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) + +#define mt9t112_reg_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) +#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ + ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) + +#define mt9t112_reg_read(ret, client, a) \ + ECHECKER(ret, __mt9t112_reg_read(client, a)) + +/* + * Logical address + */ +#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) +#define VAR(id, offset) _VAR(id, offset, 0x0000) +#define VAR8(id, offset) _VAR(id, offset, 0x8000) + +/************************************************************************ + + + struct + + +************************************************************************/ +struct mt9t112_frame_size { + u16 width; + u16 height; +}; + +struct mt9t112_format { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; + u16 fmt; + u16 order; +}; + +struct mt9t112_priv { + struct v4l2_subdev subdev; + struct mt9t112_camera_info *info; + struct i2c_client *client; + struct soc_camera_device icd; + struct mt9t112_frame_size frame; + const struct mt9t112_format *format; + int model; + u32 flags; +/* for flags */ +#define INIT_DONE (1<<0) +}; + +/************************************************************************ + + + supported format + + +************************************************************************/ + +static const struct mt9t112_format mt9t112_cfmts[] = { + { + .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 0, + }, { + .code = V4L2_MBUS_FMT_YVYU8_2X8_BE, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 1, + }, { + .code = V4L2_MBUS_FMT_YUYV8_2X8_LE, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 2, + }, { + .code = V4L2_MBUS_FMT_YVYU8_2X8_LE, + .colorspace = V4L2_COLORSPACE_JPEG, + .fmt = 1, + .order = 3, + }, { + .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 8, + .order = 2, + }, { + .code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .fmt = 4, + .order = 2, + }, +}; + +/************************************************************************ + + + general function + + +************************************************************************/ +static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), + struct mt9t112_priv, + subdev); +} + +static int __mt9t112_reg_read(const struct i2c_client *client, u16 command) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + command = swab16(command); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = (u8 *)&command; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 2; + msg[1].buf = buf; + + /* + * if return value of this function is < 0, + * it mean error. + * else, under 16bit is valid data. + */ + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) + return ret; + + memcpy(&ret, buf, 2); + return swab16(ret); +} + +static int __mt9t112_reg_write(const struct i2c_client *client, + u16 command, u16 data) +{ + struct i2c_msg msg; + u8 buf[4]; + int ret; + + command = swab16(command); + data = swab16(data); + + memcpy(buf + 0, &command, 2); + memcpy(buf + 2, &data, 2); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 4; + msg.buf = buf; + + /* + * i2c_transfer return message length, + * but this function should return 0 if correct case + */ + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret >= 0) + ret = 0; + + return ret; +} + +static int __mt9t112_reg_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_reg_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_reg_write(client, command, val); +} + +/* mcu access */ +static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_read(client, 0x0990); +} + +static int __mt9t112_mcu_write(const struct i2c_client *client, + u16 command, u16 data) +{ + int ret; + + ret = __mt9t112_reg_write(client, 0x098E, command); + if (ret < 0) + return ret; + + return __mt9t112_reg_write(client, 0x0990, data); +} + +static int __mt9t112_mcu_mask_set(const struct i2c_client *client, + u16 command, + u16 mask, + u16 set) +{ + int val = __mt9t112_mcu_read(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return __mt9t112_mcu_write(client, command, val); +} + +static int mt9t112_reset(const struct i2c_client *client) +{ + int ret; + + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); + msleep(1); + mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); + + return ret; +} + +#ifndef EXT_CLOCK +#define CLOCK_INFO(a, b) +#else +#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) +static int mt9t112_clock_info(const struct i2c_client *client, u32 ext) +{ + int m, n, p1, p2, p3, p4, p5, p6, p7; + u32 vco, clk; + char *enable; + + ext /= 1000; /* kbyte order */ + + mt9t112_reg_read(n, client, 0x0012); + p1 = n & 0x000f; + n = n >> 4; + p2 = n & 0x000f; + n = n >> 4; + p3 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002a); + p4 = n & 0x000f; + n = n >> 4; + p5 = n & 0x000f; + n = n >> 4; + p6 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x002c); + p7 = n & 0x000f; + + mt9t112_reg_read(n, client, 0x0010); + m = n & 0x00ff; + n = (n >> 8) & 0x003f; + + enable = ((6000 > ext) || (54000 < ext)) ? "X" : ""; + dev_info(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); + + vco = 2 * m * ext / (n+1); + enable = ((384000 > vco) || (768000 < vco)) ? "X" : ""; + dev_info(&client->dev, "VCO : %10u K %s\n", vco, enable); + + clk = vco / (p1+1) / (p2+1); + enable = (96000 < clk) ? "X" : ""; + dev_info(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); + + clk = vco / (p3+1); + enable = (768000 < clk) ? "X" : ""; + dev_info(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); + + clk = vco / (p6+1); + enable = (96000 < clk) ? "X" : ""; + dev_info(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); + + clk = vco / (p5+1); + enable = (54000 < clk) ? "X" : ""; + dev_info(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); + + clk = vco / (p4+1); + enable = (70000 < clk) ? "X" : ""; + dev_info(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); + + clk = vco / (p7+1); + dev_info(&client->dev, "External sensor : %10u K\n", clk); + + clk = ext / (n+1); + enable = ((2000 > clk) || (24000 < clk)) ? "X" : ""; + dev_info(&client->dev, "PFD : %10u K %s\n", clk, enable); + + return 0; +} +#endif + +static void mt9t112_frame_check(u32 *width, u32 *height) +{ + if (*width > MAX_WIDTH) + *width = MAX_WIDTH; + + if (*height > MAX_HEIGHT) + *height = MAX_HEIGHT; +} + +static int mt9t112_set_a_frame_size(const struct i2c_client *client, + u16 width, + u16 height) +{ + int ret; + u16 wstart = (MAX_WIDTH - width) / 2; + u16 hstart = (MAX_HEIGHT - height) / 2; + + /* (Context A) Image Width/Height */ + mt9t112_mcu_write(ret, client, VAR(26, 0), width); + mt9t112_mcu_write(ret, client, VAR(26, 2), height); + + /* (Context A) Output Width/Height */ + mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); + mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); + + /* (Context A) Start Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); + + /* (Context A) End Row/Column */ + mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); + mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + return ret; +} + +static int mt9t112_set_pll_dividers(const struct i2c_client *client, + u8 m, u8 n, + u8 p1, u8 p2, u8 p3, + u8 p4, u8 p5, u8 p6, + u8 p7) +{ + int ret; + u16 val; + + /* N/M */ + val = (n << 8) | + (m << 0); + mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); + + /* P1/P2/P3 */ + val = ((p3 & 0x0F) << 8) | + ((p2 & 0x0F) << 4) | + ((p1 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); + + /* P4/P5/P6 */ + val = (0x7 << 12) | + ((p6 & 0x0F) << 8) | + ((p5 & 0x0F) << 4) | + ((p4 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); + + /* P7 */ + val = (0x1 << 12) | + ((p7 & 0x0F) << 0); + mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); + + return ret; +} + +static int mt9t112_init_pll(const struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int data, i, ret; + + mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); + + /* PLL control: BYPASS PLL = 8517 */ + mt9t112_reg_write(ret, client, 0x0014, 0x2145); + + /* Replace these registers when new timing parameters are generated */ + mt9t112_set_pll_dividers(client, + priv->info->divider.m, + priv->info->divider.n, + priv->info->divider.p1, + priv->info->divider.p2, + priv->info->divider.p3, + priv->info->divider.p4, + priv->info->divider.p5, + priv->info->divider.p6, + priv->info->divider.p7); + + /* + * TEST_BYPASS on + * PLL_ENABLE on + * SEL_LOCK_DET on + * TEST_BYPASS off + */ + mt9t112_reg_write(ret, client, 0x0014, 0x2525); + mt9t112_reg_write(ret, client, 0x0014, 0x2527); + mt9t112_reg_write(ret, client, 0x0014, 0x3427); + mt9t112_reg_write(ret, client, 0x0014, 0x3027); + + mdelay(10); + + /* + * PLL_BYPASS off + * Reference clock count + * I2C Master Clock Divider + */ + mt9t112_reg_write(ret, client, 0x0014, 0x3046); + mt9t112_reg_write(ret, client, 0x0022, 0x0190); + mt9t112_reg_write(ret, client, 0x3B84, 0x0212); + + /* External sensor clock is PLL bypass */ + mt9t112_reg_write(ret, client, 0x002E, 0x0500); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); + mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); + + /* MCU disabled */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); + + /* out of standby */ + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); + + mdelay(50); + + /* + * Standby Workaround + * Disable Secondary I2C Pads + */ + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + mt9t112_reg_write(ret, client, 0x0614, 0x0001); + mdelay(1); + + /* poll to verify out of standby. Must Poll this bit */ + for (i = 0; i < 100; i++) { + mt9t112_reg_read(data, client, 0x0018); + if (0x4000 & data) + break; + + mdelay(10); + } + + return ret; +} + +static int mt9t112_init_setting(const struct i2c_client *client) +{ + + int ret; + + /* Adaptive Output Clock (A) */ + mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); + + /* Read Mode (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); + + /* Fine Correction (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); + + /* Fine IT Min (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); + + /* Fine IT Max Margin (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); + + /* Base Frame Lines (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); + + /* Min Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); + + /* Line Length (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); + + /* Adaptive Output Clock (B) */ + mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); + + /* Row Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); + + /* Column Start (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); + + /* Row End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); + + /* Column End (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); + + /* Fine Correction (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); + + /* Fine IT Min (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); + + /* Fine IT Max Margin (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); + + /* Base Frame Lines (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); + + /* Min Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); + + /* Line Length (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); + + /* + * Flicker Dectection registers + * This section should be replaced whenever new Timing file is generated + * All the following registers need to be replaced + * Following registers are generated from Register Wizard but user can + * modify them. For detail see auto flicker detection tuning + */ + + /* FD_FDPERIOD_SELECT */ + mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); + + /* PRI_B_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); + + /* PRI_A_CONFIG_FD_ALGO_RUN */ + mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); + + /* + * AFD range detection tuning registers + */ + + /* search_f1_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); + + /* search_f2_50 */ + mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); + + /* search_f1_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); + + /* search_f2_60 */ + mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); + + /* period_50Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); + + /* secret register by aptina */ + /* period_50Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); + + /* period_60Hz (A) */ + mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); + + /* secret register by aptina */ + /* period_60Hz (A MSB) */ + mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); + + /* period_50Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); + + /* secret register by aptina */ + /* period_50Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); + + /* period_60Hz (B) */ + mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); + + /* secret register by aptina */ + /* period_60Hz (B) MSB */ + mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); + + /* FD Mode */ + mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); + + /* Stat_min */ + mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); + + /* Stat_max */ + mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); + + /* Min_amplitude */ + mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); + + /* RX FIFO Watermark (A) */ + mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); + + /* RX FIFO Watermark (B) */ + mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); + + /* MCLK: 16MHz + * PCLK: 73MHz + * CorePixCLK: 36.5 MHz + */ + mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); + mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); + mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); + + mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); + mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); + + return ret; +} + +static int mt9t112_auto_focus_setting(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); + mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_reg_write(ret, client, 0x0614, 0x0000); + + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); + mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); + mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); + mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); + mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); + mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); + + return ret; +} + +static int mt9t112_auto_focus_trigger(const struct i2c_client *client) +{ + int ret; + + mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); + + return ret; +} + +static int mt9t112_init_camera(const struct i2c_client *client) +{ + int ret; + + ECHECKER(ret, mt9t112_reset(client)); + + ECHECKER(ret, mt9t112_init_pll(client)); + + ECHECKER(ret, mt9t112_init_setting(client)); + + ECHECKER(ret, mt9t112_auto_focus_setting(client)); + + mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); + + /* Analog setting B */ + mt9t112_reg_write(ret, client, 0x3084, 0x2409); + mt9t112_reg_write(ret, client, 0x3092, 0x0A49); + mt9t112_reg_write(ret, client, 0x3094, 0x4949); + mt9t112_reg_write(ret, client, 0x3096, 0x4950); + + /* + * Disable adaptive clock + * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR + * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR + */ + mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); + mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); + + /* Configure STatus in Status_before_length Format and enable header */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); + + /* Enable JPEG in context B */ + /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */ + mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); + + /* Disable Dac_TXLO */ + mt9t112_reg_write(ret, client, 0x316C, 0x350F); + + /* Set max slew rates */ + mt9t112_reg_write(ret, client, 0x1E, 0x777); + + return ret; +} + +/************************************************************************ + + + soc_camera_ops + + +************************************************************************/ +static int mt9t112_set_bus_param(struct soc_camera_device *icd, + unsigned long flags) +{ + return 0; +} + +static unsigned long mt9t112_query_bus_param(struct soc_camera_device *icd) +{ + struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); + struct mt9t112_priv *priv = to_mt9t112(client); + struct soc_camera_link *icl = to_soc_camera_link(icd); + unsigned long flags = SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH; + + flags |= (priv->info->flags & MT9T112_FLAG_PCLK_RISING_EDGE) ? + SOCAM_PCLK_SAMPLE_RISING : SOCAM_PCLK_SAMPLE_FALLING; + + if (priv->info->flags & MT9T112_FLAG_DATAWIDTH_8) + flags |= SOCAM_DATAWIDTH_8; + else + flags |= SOCAM_DATAWIDTH_10; + + return soc_camera_apply_sensor_flags(icl, flags); +} + +static struct soc_camera_ops mt9t112_ops = { + .set_bus_param = mt9t112_set_bus_param, + .query_bus_param = mt9t112_query_bus_param, +}; + +/************************************************************************ + + + v4l2_subdev_core_ops + + +************************************************************************/ +static int mt9t112_g_chip_ident(struct v4l2_subdev *sd, + struct v4l2_dbg_chip_ident *id) +{ + struct i2c_client *client = sd->priv; + struct mt9t112_priv *priv = to_mt9t112(client); + + id->ident = priv->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9t112_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = sd->priv; + int ret; + + reg->size = 2; + mt9t112_reg_read(ret, client, reg->reg); + + reg->val = (__u64)ret; + + return 0; +} + +static int mt9t112_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = sd->priv; + int ret; + + mt9t112_reg_write(ret, client, reg->reg, reg->val); + + return ret; +} +#endif + +static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { + .g_chip_ident = mt9t112_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = mt9t112_g_register, + .s_register = mt9t112_s_register, +#endif +}; + + +/************************************************************************ + + + v4l2_subdev_video_ops + + +************************************************************************/ +static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = sd->priv; + struct mt9t112_priv *priv = to_mt9t112(client); + int ret = 0; + + if (!enable) { + /* FIXME + * + * If user selected large output size, + * and used it long time, + * mt9t112 camera will be very warm. + * + * But current driver can not stop mt9t112 camera. + * So, set small size here to solve this problem. + */ + mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); + return ret; + } + + if (!(priv->flags & INIT_DONE)) { + u16 param = (MT9T112_FLAG_PCLK_RISING_EDGE & + priv->info->flags) ? 0x0001 : 0x0000; + + ECHECKER(ret, mt9t112_init_camera(client)); + + /* Invert PCLK (Data sampled on falling edge of pixclk) */ + mt9t112_reg_write(ret, client, 0x3C20, param); + + mdelay(5); + + priv->flags |= INIT_DONE; + } + + mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); + mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); + mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); + + mt9t112_set_a_frame_size(client, + priv->frame.width, + priv->frame.height); + + ECHECKER(ret, mt9t112_auto_focus_trigger(client)); + + dev_dbg(&client->dev, "format : %d\n", priv->format->code); + dev_dbg(&client->dev, "size : %d x %d\n", + priv->frame.width, + priv->frame.height); + + CLOCK_INFO(client, EXT_CLOCK); + + return ret; +} + +static int mt9t112_set_params(struct i2c_client *client, u32 width, u32 height, + enum v4l2_mbus_pixelcode code) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + int i; + + priv->format = NULL; + + /* + * frame size check + */ + mt9t112_frame_check(&width, &height); + + /* + * get color format + */ + for (i = 0; i < ARRAY_SIZE(mt9t112_cfmts); i++) + if (mt9t112_cfmts[i].code == code) + break; + + if (i == ARRAY_SIZE(mt9t112_cfmts)) + return -EINVAL; + + priv->frame.width = (u16)width; + priv->frame.height = (u16)height; + + priv->format = mt9t112_cfmts + i; + + return 0; +} + +static int mt9t112_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) +{ + a->bounds.left = 0; + a->bounds.top = 0; + a->bounds.width = VGA_WIDTH; + a->bounds.height = VGA_HEIGHT; + a->defrect = a->bounds; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + a->pixelaspect.numerator = 1; + a->pixelaspect.denominator = 1; + + return 0; +} + +static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + a->c.left = 0; + a->c.top = 0; + a->c.width = VGA_WIDTH; + a->c.height = VGA_HEIGHT; + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = sd->priv; + struct v4l2_rect *rect = &a->c; + + return mt9t112_set_params(client, rect->width, rect->height, + V4L2_MBUS_FMT_YUYV8_2X8_BE); +} + +static int mt9t112_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = sd->priv; + struct mt9t112_priv *priv = to_mt9t112(client); + + if (!priv->format) { + int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT, + V4L2_MBUS_FMT_YUYV8_2X8_BE); + if (ret < 0) + return ret; + } + + mf->width = priv->frame.width; + mf->height = priv->frame.height; + /* TODO: set colorspace */ + mf->code = priv->format->code; + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = sd->priv; + + /* TODO: set colorspace */ + return mt9t112_set_params(client, mf->width, mf->height, mf->code); +} + +static int mt9t112_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + mt9t112_frame_check(&mf->width, &mf->height); + + /* TODO: set colorspace */ + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts)) + return -EINVAL; + + *code = mt9t112_cfmts[index].code; + return 0; +} + +static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { + .s_stream = mt9t112_s_stream, + .g_mbus_fmt = mt9t112_g_fmt, + .s_mbus_fmt = mt9t112_s_fmt, + .try_mbus_fmt = mt9t112_try_fmt, + .cropcap = mt9t112_cropcap, + .g_crop = mt9t112_g_crop, + .s_crop = mt9t112_s_crop, + .enum_mbus_fmt = mt9t112_enum_fmt, +}; + +/************************************************************************ + + + i2c driver + + +************************************************************************/ +static struct v4l2_subdev_ops mt9t112_subdev_ops = { + .core = &mt9t112_subdev_core_ops, + .video = &mt9t112_subdev_video_ops, +}; + +static int mt9t112_camera_probe(struct soc_camera_device *icd, + struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + const char *devname; + int chipid; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + /* + * check and show chip ID + */ + mt9t112_reg_read(chipid, client, 0x0000); + + switch (chipid) { + case 0x2680: + devname = "mt9t111"; + priv->model = V4L2_IDENT_MT9T111; + break; + case 0x2682: + devname = "mt9t112"; + priv->model = V4L2_IDENT_MT9T112; + break; + default: + dev_err(&client->dev, "Product ID error %04x\n", chipid); + return -ENODEV; + } + + dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); + + return 0; +} + +static int mt9t112_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9t112_priv *priv; + struct soc_camera_device *icd = client->dev.platform_data; + struct soc_camera_link *icl; + int ret; + + if (!icd) { + dev_err(&client->dev, "mt9t112: missing soc-camera data!\n"); + return -EINVAL; + } + + icl = to_soc_camera_link(icd); + if (!icl || !icl->priv) + return -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = icl->priv; + + v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); + + icd->ops = &mt9t112_ops; + + ret = mt9t112_camera_probe(icd, client); + if (ret) { + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(priv); + } + + return ret; +} + +static int mt9t112_remove(struct i2c_client *client) +{ + struct mt9t112_priv *priv = to_mt9t112(client); + struct soc_camera_device *icd = client->dev.platform_data; + + icd->ops = NULL; + i2c_set_clientdata(client, NULL); + kfree(priv); + return 0; +} + +static const struct i2c_device_id mt9t112_id[] = { + { "mt9t112", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9t112_id); + +static struct i2c_driver mt9t112_i2c_driver = { + .driver = { + .name = "mt9t112", + }, + .probe = mt9t112_probe, + .remove = mt9t112_remove, + .id_table = mt9t112_id, +}; + +/************************************************************************ + + + module function + + +************************************************************************/ +static int __init mt9t112_module_init(void) +{ + return i2c_add_driver(&mt9t112_i2c_driver); +} + +static void __exit mt9t112_module_exit(void) +{ + i2c_del_driver(&mt9t112_i2c_driver); +} + +module_init(mt9t112_module_init); +module_exit(mt9t112_module_exit); + +MODULE_DESCRIPTION("SoC Camera driver for mt9t112"); +MODULE_AUTHOR("Kuninori Morimoto"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index 995607f9d3ba..91df7ec91fb6 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -18,9 +18,11 @@ #include <media/v4l2-chip-ident.h> #include <media/soc_camera.h> -/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c +/* + * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c * The platform has to define ctruct i2c_board_info objects and link to them - * from struct soc_camera_link */ + * from struct soc_camera_link + */ static char *sensor_type; module_param(sensor_type, charp, S_IRUGO); @@ -62,41 +64,49 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_COLUMN_SKIP 1 #define MT9V022_ROW_SKIP 4 -static const struct soc_camera_data_format mt9v022_colour_formats[] = { - /* Order important: first natively supported, - * second supported with a GPIO extender */ - { - .name = "Bayer (sRGB) 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_SBGGR16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, { - .name = "Bayer (sRGB) 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_SBGGR8, - .colorspace = V4L2_COLORSPACE_SRGB, - } +/* MT9V022 has only one fixed colorspace per pixelcode */ +struct mt9v022_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct mt9v022_datafmt *mt9v022_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct mt9v022_datafmt mt9v022_colour_fmts[] = { + /* + * Order important: first natively supported, + * second supported with a GPIO extender + */ + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB}, }; -static const struct soc_camera_data_format mt9v022_monochrome_formats[] = { +static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = { /* Order important - see above */ - { - .name = "Monochrome 10 bit", - .depth = 10, - .fourcc = V4L2_PIX_FMT_Y16, - }, { - .name = "Monochrome 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_GREY, - }, + {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_GREY8_1X8, V4L2_COLORSPACE_JPEG}, }; struct mt9v022 { struct v4l2_subdev subdev; struct v4l2_rect rect; /* Sensor window */ - __u32 fourcc; + const struct mt9v022_datafmt *fmt; + const struct mt9v022_datafmt *fmts; + int num_fmts; int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ u16 chip_control; + unsigned short y_skip_top; /* Lines to skip at the top */ }; static struct mt9v022 *to_mt9v022(const struct i2c_client *client) @@ -143,9 +153,11 @@ static int mt9v022_init(struct i2c_client *client) struct mt9v022 *mt9v022 = to_mt9v022(client); int ret; - /* Almost the default mode: master, parallel, simultaneous, and an + /* + * Almost the default mode: master, parallel, simultaneous, and an * undocumented bit 0x200, which is present in table 7, but not in 8, - * plus snapshot mode to disable scan for now */ + * plus snapshot mode to disable scan for now + */ mt9v022->chip_control |= 0x10; ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (!ret) @@ -265,12 +277,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) struct i2c_client *client = sd->priv; struct mt9v022 *mt9v022 = to_mt9v022(client); struct v4l2_rect rect = a->c; - struct soc_camera_device *icd = client->dev.platform_data; int ret; /* Bayer format - even size lengths */ - if (mt9v022->fourcc == V4L2_PIX_FMT_SBGGR8 || - mt9v022->fourcc == V4L2_PIX_FMT_SBGGR16) { + if (mt9v022->fmts == mt9v022_colour_fmts) { rect.width = ALIGN(rect.width, 2); rect.height = ALIGN(rect.height, 2); /* Let the user play with the starting pixel */ @@ -287,10 +297,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) if (ret >= 0) { if (ret & 1) /* Autoexposure */ ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, - rect.height + icd->y_skip_top + 43); + rect.height + mt9v022->y_skip_top + 43); else ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - rect.height + icd->y_skip_top + 43); + rect.height + mt9v022->y_skip_top + 43); } /* Setup frame format: defaults apart from width and height */ if (!ret) @@ -298,8 +308,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) if (!ret) ret = reg_write(client, MT9V022_ROW_START, rect.top); if (!ret) - /* Default 94, Phytec driver says: - * "width + horizontal blank >= 660" */ + /* + * Default 94, Phytec driver says: + * "width + horizontal blank >= 660" + */ ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, rect.width > 660 - 43 ? 43 : 660 - rect.width); @@ -309,7 +321,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); if (!ret) ret = reg_write(client, MT9V022_WINDOW_HEIGHT, - rect.height + icd->y_skip_top); + rect.height + mt9v022->y_skip_top); if (ret < 0) return ret; @@ -346,46 +358,48 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9v022_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9v022_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->width = mt9v022->rect.width; - pix->height = mt9v022->rect.height; - pix->pixelformat = mt9v022->fourcc; - pix->field = V4L2_FIELD_NONE; - pix->colorspace = V4L2_COLORSPACE_SRGB; + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mf->code = mt9v022->fmt->code; + mf->colorspace = mt9v022->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; return 0; } -static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9v022_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct mt9v022 *mt9v022 = to_mt9v022(client); - struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_crop a = { .c = { .left = mt9v022->rect.left, .top = mt9v022->rect.top, - .width = pix->width, - .height = pix->height, + .width = mf->width, + .height = mf->height, }, }; int ret; - /* The caller provides a supported format, as verified per call to - * icd->try_fmt(), datawidth is from our supported format list */ - switch (pix->pixelformat) { - case V4L2_PIX_FMT_GREY: - case V4L2_PIX_FMT_Y16: + /* + * The caller provides a supported format, as verified per call to + * icd->try_fmt(), datawidth is from our supported format list + */ + switch (mf->code) { + case V4L2_MBUS_FMT_GREY8_1X8: + case V4L2_MBUS_FMT_Y10_1X10: if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM) return -EINVAL; break; - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SBGGR16: + case V4L2_MBUS_FMT_SBGGR8_1X8: + case V4L2_MBUS_FMT_SBGGR10_1X10: if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC) return -EINVAL; break; @@ -399,26 +413,38 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) /* No support for scaling on this camera, just crop. */ ret = mt9v022_s_crop(sd, &a); if (!ret) { - pix->width = mt9v022->rect.width; - pix->height = mt9v022->rect.height; - mt9v022->fourcc = pix->pixelformat; + mf->width = mt9v022->rect.width; + mf->height = mt9v022->rect.height; + mt9v022->fmt = mt9v022_find_datafmt(mf->code, + mt9v022->fmts, mt9v022->num_fmts); + mf->colorspace = mt9v022->fmt->colorspace; } return ret; } -static int mt9v022_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int mt9v022_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; - struct soc_camera_device *icd = client->dev.platform_data; - struct v4l2_pix_format *pix = &f->fmt.pix; - int align = pix->pixelformat == V4L2_PIX_FMT_SBGGR8 || - pix->pixelformat == V4L2_PIX_FMT_SBGGR16; + struct mt9v022 *mt9v022 = to_mt9v022(client); + const struct mt9v022_datafmt *fmt; + int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 || + mf->code == V4L2_MBUS_FMT_SBGGR10_1X10; - v4l_bound_align_image(&pix->width, MT9V022_MIN_WIDTH, + v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH, align, - &pix->height, MT9V022_MIN_HEIGHT + icd->y_skip_top, - MT9V022_MAX_HEIGHT + icd->y_skip_top, align, 0); + &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, + MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0); + + fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts, + mt9v022->num_fmts); + if (!fmt) { + fmt = mt9v022->fmt; + mf->code = fmt->code; + } + + mf->colorspace = fmt->colorspace; return 0; } @@ -635,8 +661,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) 48 + range / 2) / range + 16; if (gain >= 32) gain &= ~1; - /* The user wants to set gain manually, hope, she - * knows, what she's doing... Switch AGC off. */ + /* + * The user wants to set gain manually, hope, she + * knows, what she's doing... Switch AGC off. + */ if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; @@ -655,8 +683,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) unsigned long range = qctrl->maximum - qctrl->minimum; unsigned long shutter = ((ctrl->value - qctrl->minimum) * 479 + range / 2) / range + 1; - /* The user wants to set shutter width manually, hope, - * she knows, what she's doing... Switch AEC off. */ + /* + * The user wants to set shutter width manually, hope, + * she knows, what she's doing... Switch AEC off. + */ if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) return -EIO; @@ -689,8 +719,10 @@ static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) return 0; } -/* Interface active, can use i2c. If it fails, it can indeed mean, that - * this wasn't our capture interface, so, we wait for the right one */ +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ static int mt9v022_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { @@ -733,17 +765,17 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, !strcmp("color", sensor_type))) { ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; - icd->formats = mt9v022_colour_formats; + mt9v022->fmts = mt9v022_colour_fmts; } else { ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; - icd->formats = mt9v022_monochrome_formats; + mt9v022->fmts = mt9v022_monochrome_fmts; } if (ret < 0) goto ei2c; - icd->num_formats = 0; + mt9v022->num_fmts = 0; /* * This is a 10bit sensor, so by default we only allow 10bit. @@ -756,14 +788,14 @@ static int mt9v022_video_probe(struct soc_camera_device *icd, flags = SOCAM_DATAWIDTH_10; if (flags & SOCAM_DATAWIDTH_10) - icd->num_formats++; + mt9v022->num_fmts++; else - icd->formats++; + mt9v022->fmts++; if (flags & SOCAM_DATAWIDTH_8) - icd->num_formats++; + mt9v022->num_fmts++; - mt9v022->fourcc = icd->formats->fourcc; + mt9v022->fmt = &mt9v022->fmts[0]; dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n", data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ? @@ -787,6 +819,16 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) icl->free_bus(icl); } +static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines) +{ + struct i2c_client *client = sd->priv; + struct mt9v022 *mt9v022 = to_mt9v022(client); + + *lines = mt9v022->y_skip_top; + + return 0; +} + static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { .g_ctrl = mt9v022_g_ctrl, .s_ctrl = mt9v022_s_ctrl, @@ -797,19 +839,38 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { #endif }; +static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + struct i2c_client *client = sd->priv; + struct mt9v022 *mt9v022 = to_mt9v022(client); + + if ((unsigned int)index >= mt9v022->num_fmts) + return -EINVAL; + + *code = mt9v022->fmts[index].code; + return 0; +} + static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_stream = mt9v022_s_stream, - .s_fmt = mt9v022_s_fmt, - .g_fmt = mt9v022_g_fmt, - .try_fmt = mt9v022_try_fmt, + .s_mbus_fmt = mt9v022_s_fmt, + .g_mbus_fmt = mt9v022_g_fmt, + .try_mbus_fmt = mt9v022_try_fmt, .s_crop = mt9v022_s_crop, .g_crop = mt9v022_g_crop, .cropcap = mt9v022_cropcap, + .enum_mbus_fmt = mt9v022_enum_fmt, +}; + +static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { + .g_skip_top_lines = mt9v022_g_skip_top_lines, }; static struct v4l2_subdev_ops mt9v022_subdev_ops = { .core = &mt9v022_subdev_core_ops, .video = &mt9v022_subdev_video_ops, + .sensor = &mt9v022_subdev_sensor_ops, }; static int mt9v022_probe(struct i2c_client *client, @@ -851,8 +912,7 @@ static int mt9v022_probe(struct i2c_client *client, * MT9V022 _really_ corrupts the first read out line. * TODO: verify on i.MX31 */ - icd->y_skip_top = 1; - + mt9v022->y_skip_top = 1; mt9v022->rect.left = MT9V022_COLUMN_SKIP; mt9v022->rect.top = MT9V022_ROW_SKIP; mt9v022->rect.width = MT9V022_MAX_WIDTH; diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c index 72802291e812..c167cc3de492 100644 --- a/drivers/media/video/mx1_camera.c +++ b/drivers/media/video/mx1_camera.c @@ -37,6 +37,7 @@ #include <media/v4l2-common.h> #include <media/v4l2-dev.h> #include <media/videobuf-dma-contig.h> +#include <media/soc_mediabus.h> #include <asm/dma.h> #include <asm/fiq.h> @@ -94,14 +95,16 @@ /* buffer for one video frame */ struct mx1_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - const struct soc_camera_data_format *fmt; - int inwork; + struct videobuf_buffer vb; + enum v4l2_mbus_pixelcode code; + int inwork; }; -/* i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor +/* + * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor * Interface. If anyone ever builds hardware to enable more than - * one camera, they will have to modify this driver too */ + * one camera, they will have to modify this driver too + */ struct mx1_camera_dev { struct soc_camera_host soc_host; struct soc_camera_device *icd; @@ -126,9 +129,13 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { struct soc_camera_device *icd = vq->priv_data; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; - *size = icd->user_width * icd->user_height * - ((icd->current_fmt->depth + 7) >> 3); + *size = bytes_per_line * icd->user_height; if (!*count) *count = 32; @@ -151,8 +158,10 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf) dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); - /* This waits until this buffer is out of danger, i.e., until it is no - * longer in STATE_QUEUED or STATE_ACTIVE */ + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in STATE_QUEUED or STATE_ACTIVE + */ videobuf_waiton(vb, 0, 0); videobuf_dma_contig_free(vq, vb); @@ -165,6 +174,11 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb); int ret; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -174,22 +188,24 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq, BUG_ON(NULL == icd->current_fmt); - /* I think, in buf_prepare you only have to protect global data, - * the actual buffer is yours */ + /* + * I think, in buf_prepare you only have to protect global data, + * the actual buffer is yours + */ buf->inwork = 1; - if (buf->fmt != icd->current_fmt || + if (buf->code != icd->current_fmt->code || vb->width != icd->user_width || vb->height != icd->user_height || vb->field != field) { - buf->fmt = icd->current_fmt; + buf->code = icd->current_fmt->code; vb->width = icd->user_width; vb->height = icd->user_height; vb->field = field; vb->state = VIDEOBUF_NEEDS_INIT; } - vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); + vb->size = bytes_per_line * vb->height; if (0 != vb->baddr && vb->bsize < vb->size) { ret = -EINVAL; goto out; @@ -381,8 +397,10 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) lcdclk = clk_get_rate(pcdev->clk); - /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here - * they get a nice Oops */ + /* + * We verify platform_mclk_10khz != 0, so if anyone breaks it, here + * they get a nice Oops + */ div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; dev_dbg(pcdev->icd->dev.parent, @@ -420,8 +438,10 @@ static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) clk_disable(pcdev->clk); } -/* The following two functions absolutely depend on the fact, that - * there can be only one camera on i.MX1/i.MXL camera sensor interface */ +/* + * The following two functions absolutely depend on the fact, that + * there can be only one camera on i.MX1/i.MXL camera sensor interface + */ static int mx1_camera_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); @@ -487,12 +507,10 @@ static int mx1_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) /* MX1 supports only 8bit buswidth */ common_flags = soc_camera_bus_param_compatible(camera_flags, - CSI_BUS_FLAGS); + CSI_BUS_FLAGS); if (!common_flags) return -EINVAL; - icd->buswidth = 8; - /* Make choises, based on platform choice */ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { @@ -545,7 +563,8 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; + struct v4l2_mbus_framefmt mf; + int ret, buswidth; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { @@ -554,12 +573,33 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - ret = v4l2_subdev_call(sd, video, s_fmt, f); - if (!ret) { - icd->buswidth = xlate->buswidth; - icd->current_fmt = xlate->host_fmt; + buswidth = xlate->host_fmt->bits_per_sample; + if (buswidth > 8) { + dev_warn(icd->dev.parent, + "bits-per-sample %d for format %x unsupported\n", + buswidth, pix->pixelformat); + return -EINVAL; } + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; + return ret; } @@ -567,10 +607,36 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + const struct soc_camera_format_xlate *xlate; + struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; + int ret; /* TODO: limit to mx1 hardware capabilities */ + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); + if (!xlate) { + dev_warn(icd->dev.parent, "Format %x not found\n", + pix->pixelformat); + return -EINVAL; + } + + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + /* limit to sensor capabilities */ - return v4l2_subdev_call(sd, video, try_fmt, f); + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + + return 0; } static int mx1_camera_reqbufs(struct soc_camera_file *icf, @@ -578,10 +644,12 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf, { int i; - /* This is for locking debugging only. I removed spinlocks and now I + /* + * This is for locking debugging only. I removed spinlocks and now I * check whether .prepare is ever called on a linked buffer, or whether * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered */ + * it hadn't triggered + */ for (i = 0; i < p->count; i++) { struct mx1_buffer *buf = container_of(icf->vb_vidq.bufs[i], struct mx1_buffer, vb); @@ -650,7 +718,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!res || !irq) { + if (!res || (int)irq <= 0) { err = -ENODEV; goto exit; } diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index 7db82bdf6f31..bd297f567dc7 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c @@ -23,6 +23,7 @@ #include <media/v4l2-dev.h> #include <media/videobuf-dma-contig.h> #include <media/soc_camera.h> +#include <media/soc_mediabus.h> #include <mach/ipu.h> #include <mach/mx3_camera.h> @@ -63,7 +64,7 @@ struct mx3_camera_buffer { /* common v4l buffer stuff -- must be first */ struct videobuf_buffer vb; - const struct soc_camera_data_format *fmt; + enum v4l2_mbus_pixelcode code; /* One descriptot per scatterlist (per frame) */ struct dma_async_tx_descriptor *txd; @@ -118,8 +119,6 @@ struct dma_chan_request { enum ipu_channel id; }; -static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt); - static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg) { return __raw_readl(mx3->base + reg); @@ -211,17 +210,16 @@ static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - /* - * bits-per-pixel (depth) as specified in camera's pixel format does - * not necessarily match what the camera interface writes to RAM, but - * it should be good enough for now. - */ - unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8); + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; if (!mx3_cam->idmac_channel[0]) return -EINVAL; - *size = icd->user_width * icd->user_height * bpp; + *size = bytes_per_line * icd->user_height; if (!*count) *count = 32; @@ -241,21 +239,26 @@ static int mx3_videobuf_prepare(struct videobuf_queue *vq, struct mx3_camera_dev *mx3_cam = ici->priv; struct mx3_camera_buffer *buf = container_of(vb, struct mx3_camera_buffer, vb); - /* current_fmt _must_ always be set */ - size_t new_size = icd->user_width * icd->user_height * - ((icd->current_fmt->depth + 7) >> 3); + size_t new_size; int ret; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; + + new_size = bytes_per_line * icd->user_height; /* * I think, in buf_prepare you only have to protect global data, * the actual buffer is yours */ - if (buf->fmt != icd->current_fmt || + if (buf->code != icd->current_fmt->code || vb->width != icd->user_width || vb->height != icd->user_height || vb->field != field) { - buf->fmt = icd->current_fmt; + buf->code = icd->current_fmt->code; vb->width = icd->user_width; vb->height = icd->user_height; vb->field = field; @@ -348,13 +351,13 @@ static void mx3_videobuf_queue(struct videobuf_queue *vq, struct dma_async_tx_descriptor *txd = buf->txd; struct idmac_channel *ichan = to_idmac_chan(txd->chan); struct idmac_video_param *video = &ichan->params.video; - const struct soc_camera_data_format *data_fmt = icd->current_fmt; dma_cookie_t cookie; + u32 fourcc = icd->current_fmt->host_fmt->fourcc; BUG_ON(!irqs_disabled()); /* This is the configuration of one sg-element */ - video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc); + video->out_pixel_fmt = fourcc_to_ipu_pix(fourcc); video->out_width = icd->user_width; video->out_height = icd->user_height; video->out_stride = icd->user_width; @@ -564,30 +567,37 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_LOW; - /* If requested data width is supported by the platform, use it or any - * possible lower value - i.MX31 is smart enough to schift bits */ + /* + * If requested data width is supported by the platform, use it or any + * possible lower value - i.MX31 is smart enough to schift bits + */ + if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15) + *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | + SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10) + *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | + SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8) + *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; + else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4) + *flags |= SOCAM_DATAWIDTH_4; + switch (buswidth) { case 15: - if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)) + if (!(*flags & SOCAM_DATAWIDTH_15)) return -EINVAL; - *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 | - SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; break; case 10: - if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)) + if (!(*flags & SOCAM_DATAWIDTH_10)) return -EINVAL; - *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 | - SOCAM_DATAWIDTH_4; break; case 8: - if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)) + if (!(*flags & SOCAM_DATAWIDTH_8)) return -EINVAL; - *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4; break; case 4: - if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)) + if (!(*flags & SOCAM_DATAWIDTH_4)) return -EINVAL; - *flags |= SOCAM_DATAWIDTH_4; break; default: dev_warn(mx3_cam->soc_host.v4l2_dev.dev, @@ -636,91 +646,92 @@ static bool chan_filter(struct dma_chan *chan, void *arg) pdata->dma_dev == chan->device->dev; } -static const struct soc_camera_data_format mx3_camera_formats[] = { +static const struct soc_mbus_pixelfmt mx3_camera_formats[] = { { - .name = "Bayer (sRGB) 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_SBGGR8, - .colorspace = V4L2_COLORSPACE_SRGB, + .fourcc = V4L2_PIX_FMT_SBGGR8, + .name = "Bayer BGGR (sRGB) 8 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, }, { - .name = "Monochrome 8 bit", - .depth = 8, - .fourcc = V4L2_PIX_FMT_GREY, - .colorspace = V4L2_COLORSPACE_JPEG, + .fourcc = V4L2_PIX_FMT_GREY, + .name = "Monochrome 8 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, }, }; -static bool buswidth_supported(struct soc_camera_host *ici, int depth) +/* This will be corrected as we get more formats */ +static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) { - struct mx3_camera_dev *mx3_cam = ici->priv; - - switch (depth) { - case 4: - return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4); - case 8: - return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8); - case 10: - return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10); - case 15: - return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15); - } - return false; + return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || + (fmt->bits_per_sample > 8 && + fmt->packing == SOC_MBUS_PACKING_EXTEND16); } static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, struct soc_camera_format_xlate *xlate) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int formats = 0, buswidth, ret; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct device *dev = icd->dev.parent; + int formats = 0, ret; + enum v4l2_mbus_pixelcode code; + const struct soc_mbus_pixelfmt *fmt; - buswidth = icd->formats[idx].depth; + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* No more formats */ + return 0; - if (!buswidth_supported(ici, buswidth)) + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(icd->dev.parent, + "Invalid format code #%d: %d\n", idx, code); return 0; + } - ret = mx3_camera_try_bus_param(icd, buswidth); + /* This also checks support for the requested bits-per-sample */ + ret = mx3_camera_try_bus_param(icd, fmt->bits_per_sample); if (ret < 0) return 0; - switch (icd->formats[idx].fourcc) { - case V4L2_PIX_FMT_SGRBG10: + switch (code) { + case V4L2_MBUS_FMT_SBGGR10_1X10: formats++; if (xlate) { - xlate->host_fmt = &mx3_camera_formats[0]; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = buswidth; + xlate->host_fmt = &mx3_camera_formats[0]; + xlate->code = code; xlate++; - dev_dbg(icd->dev.parent, - "Providing format %s using %s\n", - mx3_camera_formats[0].name, - icd->formats[idx].name); + dev_dbg(dev, "Providing format %s using code %d\n", + mx3_camera_formats[0].name, code); } - goto passthrough; - case V4L2_PIX_FMT_Y16: + break; + case V4L2_MBUS_FMT_Y10_1X10: formats++; if (xlate) { - xlate->host_fmt = &mx3_camera_formats[1]; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = buswidth; + xlate->host_fmt = &mx3_camera_formats[1]; + xlate->code = code; xlate++; - dev_dbg(icd->dev.parent, - "Providing format %s using %s\n", - mx3_camera_formats[0].name, - icd->formats[idx].name); + dev_dbg(dev, "Providing format %s using code %d\n", + mx3_camera_formats[1].name, code); } + break; default: -passthrough: - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = icd->formats + idx; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = buswidth; - xlate++; - dev_dbg(icd->dev.parent, - "Providing format %s in pass-through mode\n", - icd->formats[idx].name); - } + if (!mx3_camera_packing_supported(fmt)) + return 0; + } + + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %x in pass-through mode\n", + xlate->host_fmt->fourcc); } return formats; @@ -804,8 +815,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; - struct v4l2_pix_format *pix = &f.fmt.pix; + struct v4l2_mbus_framefmt mf; int ret; soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); @@ -816,19 +826,19 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, video, g_fmt, &f); + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); if (ret < 0) return ret; - if (pix->width & 7) { + if (mf.width & 7) { /* Ouch! We can only handle 8-byte aligned width... */ - stride_align(&pix->width); - ret = v4l2_subdev_call(sd, video, s_fmt, &f); + stride_align(&mf.width); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; } - if (pix->width != icd->user_width || pix->height != icd->user_height) { + if (mf.width != icd->user_width || mf.height != icd->user_height) { /* * We now know pixel formats and can decide upon DMA-channel(s) * So far only direct camera-to-memory is supported @@ -839,14 +849,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; } - configure_geometry(mx3_cam, pix->width, pix->height); + configure_geometry(mx3_cam, mf.width, mf.height); } dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n", - pix->width, pix->height); + mf.width, mf.height); - icd->user_width = pix->width; - icd->user_height = pix->height; + icd->user_width = mf.width; + icd->user_height = mf.height; return ret; } @@ -859,6 +869,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -883,11 +894,24 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, configure_geometry(mx3_cam, pix->width, pix->height); - ret = v4l2_subdev_call(sd, video, s_fmt, f); - if (!ret) { - icd->buswidth = xlate->buswidth; - icd->current_fmt = xlate->host_fmt; - } + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + if (ret < 0) + return ret; + + if (mf.code != xlate->code) + return -EINVAL; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; dev_dbg(icd->dev.parent, "Sensor set %dx%d\n", pix->width, pix->height); @@ -900,8 +924,8 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; __u32 pixfmt = pix->pixelformat; - enum v4l2_field field; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); @@ -916,23 +940,37 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, if (pix->width > 4096) pix->width = 4096; - pix->bytesperline = pix->width * - DIV_ROUND_UP(xlate->host_fmt->depth, 8); + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; pix->sizeimage = pix->height * pix->bytesperline; - /* camera has to see its format, but the user the original one */ - pix->pixelformat = xlate->cam_fmt->fourcc; /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_fmt, f); - pix->pixelformat = xlate->host_fmt->fourcc; + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; - field = pix->field; + pix->width = mf.width; + pix->height = mf.height; + pix->colorspace = mf.colorspace; - if (field == V4L2_FIELD_ANY) { + switch (mf.field) { + case V4L2_FIELD_ANY: pix->field = V4L2_FIELD_NONE; - } else if (field != V4L2_FIELD_NONE) { - dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); - return -EINVAL; + break; + case V4L2_FIELD_NONE: + break; + default: + dev_err(icd->dev.parent, "Field type %d unsupported.\n", + mf.field); + ret = -EINVAL; } return ret; @@ -968,18 +1006,26 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) struct mx3_camera_dev *mx3_cam = ici->priv; unsigned long bus_flags, camera_flags, common_flags; u32 dw, sens_conf; - int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags); + const struct soc_mbus_pixelfmt *fmt; + int buswidth; + int ret; const struct soc_camera_format_xlate *xlate; struct device *dev = icd->dev.parent; + fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); + if (!fmt) + return -EINVAL; + + buswidth = fmt->bits_per_sample; + ret = test_platform_param(mx3_cam, buswidth, &bus_flags); + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { dev_warn(dev, "Format %x not found\n", pixfmt); return -EINVAL; } - dev_dbg(dev, "requested bus width %d bit: %d\n", - icd->buswidth, ret); + dev_dbg(dev, "requested bus width %d bit: %d\n", buswidth, ret); if (ret < 0) return ret; @@ -1027,8 +1073,10 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING; } - /* Make the camera work in widest common mode, we'll take care of - * the rest */ + /* + * Make the camera work in widest common mode, we'll take care of + * the rest + */ if (common_flags & SOCAM_DATAWIDTH_15) common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) | SOCAM_DATAWIDTH_15; @@ -1078,7 +1126,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT; /* Just do what we're asked to do */ - switch (xlate->host_fmt->depth) { + switch (xlate->host_fmt->bits_per_sample) { case 4: dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT; break; @@ -1152,8 +1200,10 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev) if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 | MX3_CAMERA_DATAWIDTH_15))) { - /* Platform hasn't set available data widths. This is bad. - * Warn and use a default. */ + /* + * Platform hasn't set available data widths. This is bad. + * Warn and use a default. + */ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " "data widths, using default 8 bit\n"); mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8; diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 5fc4ac0d88f0..7400eacb4d64 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -1450,12 +1450,11 @@ static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma) static int omap24xxcam_open(struct file *file) { - int minor = video_devdata(file)->minor; struct omap24xxcam_device *cam = omap24xxcam.priv; struct omap24xxcam_fh *fh; struct v4l2_format format; - if (!cam || !cam->vfd || (cam->vfd->minor != minor)) + if (!cam || !cam->vfd) return -ENODEV; fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -1660,7 +1659,6 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s) strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name)); vfd->fops = &omap24xxcam_fops; - vfd->minor = -1; vfd->ioctl_ops = &omap24xxcam_ioctl_fops; omap24xxcam_hwinit(cam); @@ -1671,14 +1669,14 @@ static int omap24xxcam_device_register(struct v4l2_int_device *s) if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) { dev_err(cam->dev, "could not register V4L device\n"); - vfd->minor = -1; rval = -EBUSY; goto err; } omap24xxcam_poweron_reset(cam); - dev_info(cam->dev, "registered device video%d\n", vfd->minor); + dev_info(cam->dev, "registered device %s\n", + video_device_node_name(vfd)); return 0; @@ -1695,7 +1693,7 @@ static void omap24xxcam_device_unregister(struct v4l2_int_device *s) omap24xxcam_sensor_exit(cam); if (cam->vfd) { - if (cam->vfd->minor == -1) { + if (!video_is_registered(cam->vfd)) { /* * The device was never registered, so release the * video_device struct directly. diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c index 0bc2cf573c76..e0bce8dc74bf 100644 --- a/drivers/media/video/ov511.c +++ b/drivers/media/video/ov511.c @@ -4674,7 +4674,6 @@ static struct video_device vdev_template = { .name = "OV511 USB Camera", .fops = &ov511_fops, .release = video_device_release, - .minor = -1, }; /**************************************************************************** @@ -5867,8 +5866,8 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) ov511_devused |= 1 << nr; ov->nr = nr; - dev_info(&intf->dev, "Device at %s registered to minor %d\n", - ov->usb_path, ov->vdev->minor); + dev_info(&intf->dev, "Device at %s registered to %s\n", + ov->usb_path, video_device_node_name(ov->vdev)); usb_set_intfdata(intf, ov); if (ov_create_sysfs(ov->vdev)) { @@ -5878,13 +5877,13 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id) goto error; } - mutex_lock(&ov->lock); + mutex_unlock(&ov->lock); return 0; error: if (ov->vdev) { - if (-1 == ov->vdev->minor) + if (!video_is_registered(ov->vdev)) video_device_release(ov->vdev); else video_unregister_device(ov->vdev); diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 205229333466..3a45e945a528 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c @@ -24,6 +24,7 @@ #include <media/v4l2-chip-ident.h> #include <media/v4l2-subdev.h> #include <media/soc_camera.h> +#include <media/soc_mediabus.h> #include <media/ov772x.h> /* @@ -382,7 +383,8 @@ struct regval_list { }; struct ov772x_color_format { - const struct soc_camera_data_format *format; + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; u8 dsp3; u8 com3; u8 com7; @@ -399,7 +401,7 @@ struct ov772x_win_size { struct ov772x_priv { struct v4l2_subdev subdev; struct ov772x_camera_info *info; - const struct ov772x_color_format *fmt; + const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; int model; unsigned short flag_vflip:1; @@ -434,93 +436,57 @@ static const struct regval_list ov772x_vga_regs[] = { }; /* - * supported format list - */ - -#define SETFOURCC(type) .name = (#type), .fourcc = (V4L2_PIX_FMT_ ## type) -static const struct soc_camera_data_format ov772x_fmt_lists[] = { - { - SETFOURCC(YUYV), - .depth = 16, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - { - SETFOURCC(YVYU), - .depth = 16, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - { - SETFOURCC(UYVY), - .depth = 16, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - { - SETFOURCC(RGB555), - .depth = 16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, - { - SETFOURCC(RGB555X), - .depth = 16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, - { - SETFOURCC(RGB565), - .depth = 16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, - { - SETFOURCC(RGB565X), - .depth = 16, - .colorspace = V4L2_COLORSPACE_SRGB, - }, -}; - -/* - * color format list + * supported color format list */ static const struct ov772x_color_format ov772x_cfmts[] = { { - .format = &ov772x_fmt_lists[0], - .dsp3 = 0x0, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, + .code = V4L2_MBUS_FMT_YUYV8_2X8_LE, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = 0x0, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, }, { - .format = &ov772x_fmt_lists[1], - .dsp3 = UV_ON, - .com3 = SWAP_YUV, - .com7 = OFMT_YUV, + .code = V4L2_MBUS_FMT_YVYU8_2X8_LE, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = UV_ON, + .com3 = SWAP_YUV, + .com7 = OFMT_YUV, }, { - .format = &ov772x_fmt_lists[2], - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = OFMT_YUV, + .code = V4L2_MBUS_FMT_YUYV8_2X8_BE, + .colorspace = V4L2_COLORSPACE_JPEG, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = OFMT_YUV, }, { - .format = &ov772x_fmt_lists[3], - .dsp3 = 0x0, - .com3 = SWAP_RGB, - .com7 = FMT_RGB555 | OFMT_RGB, + .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .com3 = SWAP_RGB, + .com7 = FMT_RGB555 | OFMT_RGB, }, { - .format = &ov772x_fmt_lists[4], - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = FMT_RGB555 | OFMT_RGB, + .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = FMT_RGB555 | OFMT_RGB, }, { - .format = &ov772x_fmt_lists[5], - .dsp3 = 0x0, - .com3 = SWAP_RGB, - .com7 = FMT_RGB565 | OFMT_RGB, + .code = V4L2_MBUS_FMT_RGB565_2X8_LE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .com3 = SWAP_RGB, + .com7 = FMT_RGB565 | OFMT_RGB, }, { - .format = &ov772x_fmt_lists[6], - .dsp3 = 0x0, - .com3 = 0x0, - .com7 = FMT_RGB565 | OFMT_RGB, + .code = V4L2_MBUS_FMT_RGB565_2X8_BE, + .colorspace = V4L2_COLORSPACE_SRGB, + .dsp3 = 0x0, + .com3 = 0x0, + .com7 = FMT_RGB565 | OFMT_RGB, }, }; @@ -642,15 +608,15 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) return 0; } - if (!priv->win || !priv->fmt) { + if (!priv->win || !priv->cfmt) { dev_err(&client->dev, "norm or win select error\n"); return -EPERM; } ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); - dev_dbg(&client->dev, "format %s, win %s\n", - priv->fmt->format->name, priv->win->name); + dev_dbg(&client->dev, "format %d, win %s\n", + priv->cfmt->code, priv->win->name); return 0; } @@ -806,8 +772,8 @@ static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) return win; } -static int ov772x_set_params(struct i2c_client *client, - u32 *width, u32 *height, u32 pixfmt) +static int ov772x_set_params(struct i2c_client *client, u32 *width, u32 *height, + enum v4l2_mbus_pixelcode code) { struct ov772x_priv *priv = to_ov772x(client); int ret = -EINVAL; @@ -817,14 +783,14 @@ static int ov772x_set_params(struct i2c_client *client, /* * select format */ - priv->fmt = NULL; + priv->cfmt = NULL; for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { - if (pixfmt == ov772x_cfmts[i].format->fourcc) { - priv->fmt = ov772x_cfmts + i; + if (code == ov772x_cfmts[i].code) { + priv->cfmt = ov772x_cfmts + i; break; } } - if (!priv->fmt) + if (!priv->cfmt) goto ov772x_set_fmt_error; /* @@ -894,7 +860,7 @@ static int ov772x_set_params(struct i2c_client *client, /* * set DSP_CTRL3 */ - val = priv->fmt->dsp3; + val = priv->cfmt->dsp3; if (val) { ret = ov772x_mask_set(client, DSP_CTRL3, UV_MASK, val); @@ -905,7 +871,7 @@ static int ov772x_set_params(struct i2c_client *client, /* * set COM3 */ - val = priv->fmt->com3; + val = priv->cfmt->com3; if (priv->info->flags & OV772X_FLAG_VFLIP) val |= VFLIP_IMG; if (priv->info->flags & OV772X_FLAG_HFLIP) @@ -923,9 +889,9 @@ static int ov772x_set_params(struct i2c_client *client, /* * set COM7 */ - val = priv->win->com7_bit | priv->fmt->com7; + val = priv->win->com7_bit | priv->cfmt->com7; ret = ov772x_mask_set(client, - COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), + COM7, SLCT_MASK | FMT_MASK | OFMT_MASK, val); if (ret < 0) goto ov772x_set_fmt_error; @@ -951,7 +917,7 @@ ov772x_set_fmt_error: ov772x_reset(client); priv->win = NULL; - priv->fmt = NULL; + priv->cfmt = NULL; return ret; } @@ -981,54 +947,79 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int ov772x_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct ov772x_priv *priv = to_ov772x(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - if (!priv->win || !priv->fmt) { + if (!priv->win || !priv->cfmt) { u32 width = VGA_WIDTH, height = VGA_HEIGHT; int ret = ov772x_set_params(client, &width, &height, - V4L2_PIX_FMT_YUYV); + V4L2_MBUS_FMT_YUYV8_2X8_LE); if (ret < 0) return ret; } - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - pix->width = priv->win->width; - pix->height = priv->win->height; - pix->pixelformat = priv->fmt->format->fourcc; - pix->colorspace = priv->fmt->format->colorspace; - pix->field = V4L2_FIELD_NONE; + mf->width = priv->win->width; + mf->height = priv->win->height; + mf->code = priv->cfmt->code; + mf->colorspace = priv->cfmt->colorspace; + mf->field = V4L2_FIELD_NONE; return 0; } -static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int ov772x_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; - struct v4l2_pix_format *pix = &f->fmt.pix; + struct ov772x_priv *priv = to_ov772x(client); + int ret = ov772x_set_params(client, &mf->width, &mf->height, + mf->code); + + if (!ret) + mf->colorspace = priv->cfmt->colorspace; - return ov772x_set_params(client, &pix->width, &pix->height, - pix->pixelformat); + return ret; } static int ov772x_try_fmt(struct v4l2_subdev *sd, - struct v4l2_format *f) + struct v4l2_mbus_framefmt *mf) { - struct v4l2_pix_format *pix = &f->fmt.pix; + struct i2c_client *client = sd->priv; + struct ov772x_priv *priv = to_ov772x(client); const struct ov772x_win_size *win; + int i; /* * select suitable win */ - win = ov772x_select_win(pix->width, pix->height); + win = ov772x_select_win(mf->width, mf->height); + + mf->width = win->width; + mf->height = win->height; + mf->field = V4L2_FIELD_NONE; - pix->width = win->width; - pix->height = win->height; - pix->field = V4L2_FIELD_NONE; + for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) + if (mf->code == ov772x_cfmts[i].code) + break; + + if (i == ARRAY_SIZE(ov772x_cfmts)) { + /* Unsupported format requested. Propose either */ + if (priv->cfmt) { + /* the current one or */ + mf->colorspace = priv->cfmt->colorspace; + mf->code = priv->cfmt->code; + } else { + /* the default one */ + mf->colorspace = ov772x_cfmts[0].colorspace; + mf->code = ov772x_cfmts[0].code; + } + } else { + /* Also return the colorspace */ + mf->colorspace = ov772x_cfmts[i].colorspace; + } return 0; } @@ -1057,9 +1048,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd, return -ENODEV; } - icd->formats = ov772x_fmt_lists; - icd->num_formats = ARRAY_SIZE(ov772x_fmt_lists); - /* * check and show product ID and manufacturer ID */ @@ -1109,13 +1097,24 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { #endif }; +static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts)) + return -EINVAL; + + *code = ov772x_cfmts[index].code; + return 0; +} + static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, - .g_fmt = ov772x_g_fmt, - .s_fmt = ov772x_s_fmt, - .try_fmt = ov772x_try_fmt, + .g_mbus_fmt = ov772x_g_fmt, + .s_mbus_fmt = ov772x_s_fmt, + .try_mbus_fmt = ov772x_try_fmt, .cropcap = ov772x_cropcap, .g_crop = ov772x_g_crop, + .enum_mbus_fmt = ov772x_enum_fmt, }; static struct v4l2_subdev_ops ov772x_subdev_ops = { @@ -1143,10 +1142,10 @@ static int ov772x_probe(struct i2c_client *client, } icl = to_soc_camera_link(icd); - if (!icl) + if (!icl || !icl->priv) return -EINVAL; - info = container_of(icl, struct ov772x_camera_info, link); + info = icl->priv; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c index c81ae2192887..47bf60ceb7a2 100644 --- a/drivers/media/video/ov9640.c +++ b/drivers/media/video/ov9640.c @@ -154,19 +154,10 @@ static const struct ov9640_reg ov9640_regs_rgb[] = { { OV9640_MTXS, 0x65 }, }; -/* - * TODO: this sensor also supports RGB555 and RGB565 formats, but support for - * them has not yet been sufficiently tested and so it is not included with - * this version of the driver. To test and debug these formats add two entries - * to the below array, see ov722x.c for an example. - */ -static const struct soc_camera_data_format ov9640_fmt_lists[] = { - { - .name = "UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .colorspace = V4L2_COLORSPACE_JPEG, - }, +static enum v4l2_mbus_pixelcode ov9640_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8_BE, + V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, + V4L2_MBUS_FMT_RGB565_2X8_LE, }; static const struct v4l2_queryctrl ov9640_controls[] = { @@ -434,20 +425,22 @@ static void ov9640_res_roundup(u32 *width, u32 *height) } /* Prepare necessary register changes depending on color encoding */ -static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt) +static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code, + struct ov9640_reg_alt *alt) { - switch (pixfmt) { - case V4L2_PIX_FMT_UYVY: + switch (code) { + default: + case V4L2_MBUS_FMT_YUYV8_2X8_BE: alt->com12 = OV9640_COM12_YUV_AVG; alt->com13 = OV9640_COM13_Y_DELAY_EN | OV9640_COM13_YUV_DLY(0x01); break; - case V4L2_PIX_FMT_RGB555: + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: alt->com7 = OV9640_COM7_RGB; alt->com13 = OV9640_COM13_RGB_AVG; alt->com15 = OV9640_COM15_RGB_555; break; - case V4L2_PIX_FMT_RGB565: + case V4L2_MBUS_FMT_RGB565_2X8_LE: alt->com7 = OV9640_COM7_RGB; alt->com13 = OV9640_COM13_RGB_AVG; alt->com15 = OV9640_COM15_RGB_565; @@ -456,8 +449,8 @@ static void ov9640_alter_regs(u32 pixfmt, struct ov9640_reg_alt *alt) } /* Setup registers according to resolution and color encoding */ -static int ov9640_write_regs(struct i2c_client *client, - u32 width, u32 pixfmt, struct ov9640_reg_alt *alts) +static int ov9640_write_regs(struct i2c_client *client, u32 width, + enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts) { const struct ov9640_reg *ov9640_regs, *matrix_regs; int ov9640_regs_len, matrix_regs_len; @@ -500,7 +493,7 @@ static int ov9640_write_regs(struct i2c_client *client, } /* select color matrix configuration for given color encoding */ - if (pixfmt == V4L2_PIX_FMT_UYVY) { + if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) { matrix_regs = ov9640_regs_yuv; matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv); } else { @@ -562,15 +555,17 @@ static int ov9640_prog_dflt(struct i2c_client *client) } /* set the format we will capture in */ -static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int ov9640_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; - struct v4l2_pix_format *pix = &f->fmt.pix; struct ov9640_reg_alt alts = {0}; + enum v4l2_colorspace cspace; + enum v4l2_mbus_pixelcode code = mf->code; int ret; - ov9640_res_roundup(&pix->width, &pix->height); - ov9640_alter_regs(pix->pixelformat, &alts); + ov9640_res_roundup(&mf->width, &mf->height); + ov9640_alter_regs(mf->code, &alts); ov9640_reset(client); @@ -578,19 +573,57 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) if (ret) return ret; - return ov9640_write_regs(client, pix->width, pix->pixelformat, &alts); + switch (code) { + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + cspace = V4L2_COLORSPACE_SRGB; + break; + default: + code = V4L2_MBUS_FMT_YUYV8_2X8_BE; + case V4L2_MBUS_FMT_YUYV8_2X8_BE: + cspace = V4L2_COLORSPACE_JPEG; + } + + ret = ov9640_write_regs(client, mf->width, code, &alts); + if (!ret) { + mf->code = code; + mf->colorspace = cspace; + } + + return ret; } -static int ov9640_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int ov9640_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { - struct v4l2_pix_format *pix = &f->fmt.pix; + ov9640_res_roundup(&mf->width, &mf->height); - ov9640_res_roundup(&pix->width, &pix->height); - pix->field = V4L2_FIELD_NONE; + mf->field = V4L2_FIELD_NONE; + + switch (mf->code) { + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + mf->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; + case V4L2_MBUS_FMT_YUYV8_2X8_BE: + mf->colorspace = V4L2_COLORSPACE_JPEG; + } return 0; } +static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes)) + return -EINVAL; + + *code = ov9640_codes[index]; + return 0; +} + static int ov9640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { a->c.left = 0; @@ -637,9 +670,6 @@ static int ov9640_video_probe(struct soc_camera_device *icd, goto err; } - icd->formats = ov9640_fmt_lists; - icd->num_formats = ARRAY_SIZE(ov9640_fmt_lists); - /* * check and show product ID and manufacturer ID */ @@ -702,11 +732,12 @@ static struct v4l2_subdev_core_ops ov9640_core_ops = { }; static struct v4l2_subdev_video_ops ov9640_video_ops = { - .s_stream = ov9640_s_stream, - .s_fmt = ov9640_s_fmt, - .try_fmt = ov9640_try_fmt, - .cropcap = ov9640_cropcap, - .g_crop = ov9640_g_crop, + .s_stream = ov9640_s_stream, + .s_mbus_fmt = ov9640_s_fmt, + .try_mbus_fmt = ov9640_try_fmt, + .enum_mbus_fmt = ov9640_enum_fmt, + .cropcap = ov9640_cropcap, + .g_crop = ov9640_g_crop, }; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 73ec970ca5ca..11a2c26399b5 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -31,7 +31,7 @@ #include <linux/init.h> #include <linux/version.h> #include <linux/mutex.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <asm/io.h> #include <linux/videodev2.h> diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 6aa48e0ae731..cc8ddb2d2382 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -151,17 +151,6 @@ static struct v4l2_format pvr_format [] = { }; -static const char *get_v4l_name(int v4l_type) -{ - switch (v4l_type) { - case VFL_TYPE_GRABBER: return "video"; - case VFL_TYPE_RADIO: return "radio"; - case VFL_TYPE_VBI: return "vbi"; - default: return "?"; - } -} - - /* * pvr_ioctl() * @@ -891,10 +880,8 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) { - int num = dip->devbase.num; struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; enum pvr2_config cfg = dip->config; - int v4l_type = dip->v4l_type; pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); @@ -906,8 +893,8 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) are gone. */ video_unregister_device(&dip->devbase); - printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n", - get_v4l_name(v4l_type), num, + printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n", + video_device_node_name(&dip->devbase), pvr2_config_get_name(cfg)); } @@ -1317,8 +1304,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, ": Failed to register pvrusb2 v4l device\n"); } - printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n", - get_v4l_name(dip->v4l_type), dip->devbase.num, + printk(KERN_INFO "pvrusb2: registered device %s [%s]\n", + video_device_node_name(&dip->devbase), pvr2_config_get_name(dip->config)); pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 89b620f6db7b..aea7e224cef6 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -169,7 +169,6 @@ static struct video_device pwc_template = { .name = "Philips Webcam", /* Filled in later */ .release = video_device_release, .fops = &pwc_fops, - .minor = -1, }; /***************************************************************************/ @@ -1807,7 +1806,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id goto err_video_release; } - PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num); + PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev)); /* occupy slot */ if (hint < MAX_DEV_HINTS) @@ -1948,7 +1947,9 @@ MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); +#ifdef CONFIG_USB_PWC_DEBUG MODULE_PARM_DESC(trace, "For debugging purposes"); +#endif MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 51b683c63b70..294f860ce2b0 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c @@ -32,6 +32,7 @@ #include <media/v4l2-dev.h> #include <media/videobuf-dma-sg.h> #include <media/soc_camera.h> +#include <media/soc_mediabus.h> #include <linux/videodev2.h> @@ -183,23 +184,21 @@ struct pxa_cam_dma { /* buffer for one video frame */ struct pxa_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - const struct soc_camera_data_format *fmt; - + struct videobuf_buffer vb; + enum v4l2_mbus_pixelcode code; /* our descriptor lists for Y, U and V channels */ - struct pxa_cam_dma dmas[3]; - - int inwork; - - enum pxa_camera_active_dma active_dma; + struct pxa_cam_dma dmas[3]; + int inwork; + enum pxa_camera_active_dma active_dma; }; struct pxa_camera_dev { struct soc_camera_host soc_host; - /* PXA27x is only supposed to handle one camera on its Quick Capture + /* + * PXA27x is only supposed to handle one camera on its Quick Capture * interface. If anyone ever builds hardware to enable more than - * one camera, they will have to modify this driver too */ + * one camera, they will have to modify this driver too + */ struct soc_camera_device *icd; struct clk *clk; @@ -241,11 +240,15 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { struct soc_camera_device *icd = vq->priv_data; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; dev_dbg(icd->dev.parent, "count=%d, size=%d\n", *count, *size); - *size = roundup(icd->user_width * icd->user_height * - ((icd->current_fmt->depth + 7) >> 3), 8); + *size = bytes_per_line * icd->user_height; if (0 == *count) *count = 32; @@ -267,8 +270,10 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__, &buf->vb, buf->vb.baddr, buf->vb.bsize); - /* This waits until this buffer is out of danger, i.e., until it is no - * longer in STATE_QUEUED or STATE_ACTIVE */ + /* + * This waits until this buffer is out of danger, i.e., until it is no + * longer in STATE_QUEUED or STATE_ACTIVE + */ videobuf_waiton(&buf->vb, 0, 0); videobuf_dma_unmap(vq, dma); videobuf_dma_free(dma); @@ -429,6 +434,11 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb); int ret; int size_y, size_u = 0, size_v = 0; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); @@ -437,29 +447,33 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, WARN_ON(!list_empty(&vb->queue)); #ifdef DEBUG - /* This can be useful if you want to see if we actually fill - * the buffer with something */ + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ memset((void *)vb->baddr, 0xaa, vb->bsize); #endif BUG_ON(NULL == icd->current_fmt); - /* I think, in buf_prepare you only have to protect global data, - * the actual buffer is yours */ + /* + * I think, in buf_prepare you only have to protect global data, + * the actual buffer is yours + */ buf->inwork = 1; - if (buf->fmt != icd->current_fmt || + if (buf->code != icd->current_fmt->code || vb->width != icd->user_width || vb->height != icd->user_height || vb->field != field) { - buf->fmt = icd->current_fmt; + buf->code = icd->current_fmt->code; vb->width = icd->user_width; vb->height = icd->user_height; vb->field = field; vb->state = VIDEOBUF_NEEDS_INIT; } - vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); + vb->size = bytes_per_line * vb->height; if (0 != vb->baddr && vb->bsize < vb->size) { ret = -EINVAL; goto out; @@ -834,8 +848,10 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; - /* We must pass NULL as dev pointer, then all pci_* dma operations - * transform to normal dma_* ones. */ + /* + * We must pass NULL as dev pointer, then all pci_* dma operations + * transform to normal dma_* ones. + */ videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, sizeof(struct pxa_buffer), icd); @@ -1051,11 +1067,18 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); unsigned long dw, bpp; - u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0; + u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; + int ret = v4l2_subdev_call(sd, sensor, g_skip_top_lines, &y_skip_top); + + if (ret < 0) + y_skip_top = 0; - /* Datawidth is now guaranteed to be equal to one of the three values. - * We fix bit-per-pixel equal to data-width... */ + /* + * Datawidth is now guaranteed to be equal to one of the three values. + * We fix bit-per-pixel equal to data-width... + */ switch (flags & SOCAM_DATAWIDTH_MASK) { case SOCAM_DATAWIDTH_10: dw = 4; @@ -1066,8 +1089,10 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, bpp = 0x20; break; default: - /* Actually it can only be 8 now, - * default is just to silence compiler warnings */ + /* + * Actually it can only be 8 now, + * default is just to silence compiler warnings + */ case SOCAM_DATAWIDTH_8: dw = 2; bpp = 0; @@ -1118,7 +1143,7 @@ static void pxa_camera_setup_cicr(struct soc_camera_device *icd, cicr2 = 0; cicr3 = CICR3_LPF_VAL(icd->user_height - 1) | - CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top)); + CICR3_BFW_VAL(min((u32)255, y_skip_top)); cicr4 |= pcdev->mclk_divisor; __raw_writel(cicr1, pcdev->base + CICR1); @@ -1138,9 +1163,15 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct pxa_camera_dev *pcdev = ici->priv; unsigned long bus_flags, camera_flags, common_flags; - int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags); + const struct soc_mbus_pixelfmt *fmt; + int ret; struct pxa_cam *cam = icd->host_priv; + fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code); + if (!fmt) + return -EINVAL; + + ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags); if (ret < 0) return ret; @@ -1204,59 +1235,49 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL; } -static const struct soc_camera_data_format pxa_camera_formats[] = { +static const struct soc_mbus_pixelfmt pxa_camera_formats[] = { { - .name = "Planar YUV422 16 bit", - .depth = 16, - .fourcc = V4L2_PIX_FMT_YUV422P, - .colorspace = V4L2_COLORSPACE_JPEG, + .fourcc = V4L2_PIX_FMT_YUV422P, + .name = "Planar YUV422 16 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, }, }; -static bool buswidth_supported(struct soc_camera_device *icd, int depth) +/* This will be corrected as we get more formats */ +static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; - - switch (depth) { - case 8: - return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8); - case 9: - return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9); - case 10: - return !!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10); - } - return false; -} - -static int required_buswidth(const struct soc_camera_data_format *fmt) -{ - switch (fmt->fourcc) { - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB555: - return 8; - default: - return fmt->depth; - } + return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || + (fmt->bits_per_sample > 8 && + fmt->packing == SOC_MBUS_PACKING_EXTEND16); } static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, struct soc_camera_format_xlate *xlate) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; - int formats = 0, buswidth, ret; + int formats = 0, ret; struct pxa_cam *cam; + enum v4l2_mbus_pixelcode code; + const struct soc_mbus_pixelfmt *fmt; - buswidth = required_buswidth(icd->formats + idx); + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* No more formats */ + return 0; - if (!buswidth_supported(icd, buswidth)) + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(dev, "Invalid format code #%d: %d\n", idx, code); return 0; + } - ret = pxa_camera_try_bus_param(icd, buswidth); + /* This also checks support for the requested bits-per-sample */ + ret = pxa_camera_try_bus_param(icd, fmt->bits_per_sample); if (ret < 0) return 0; @@ -1270,45 +1291,40 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, cam = icd->host_priv; } - switch (icd->formats[idx].fourcc) { - case V4L2_PIX_FMT_UYVY: + switch (code) { + case V4L2_MBUS_FMT_YUYV8_2X8_BE: formats++; if (xlate) { - xlate->host_fmt = &pxa_camera_formats[0]; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = buswidth; + xlate->host_fmt = &pxa_camera_formats[0]; + xlate->code = code; xlate++; - dev_dbg(dev, "Providing format %s using %s\n", - pxa_camera_formats[0].name, - icd->formats[idx].name); + dev_dbg(dev, "Providing format %s using code %d\n", + pxa_camera_formats[0].name, code); } - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_RGB555: - formats++; - if (xlate) { - xlate->host_fmt = icd->formats + idx; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = buswidth; - xlate++; + case V4L2_MBUS_FMT_YVYU8_2X8_BE: + case V4L2_MBUS_FMT_YUYV8_2X8_LE: + case V4L2_MBUS_FMT_YVYU8_2X8_LE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE: + if (xlate) dev_dbg(dev, "Providing format %s packed\n", - icd->formats[idx].name); - } + fmt->name); break; default: - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = icd->formats + idx; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = icd->formats[idx].depth; - xlate++; + if (!pxa_camera_packing_supported(fmt)) + return 0; + if (xlate) dev_dbg(dev, "Providing format %s in pass-through mode\n", - icd->formats[idx].name); - } + fmt->name); + } + + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; } return formats; @@ -1320,11 +1336,11 @@ static void pxa_camera_put_formats(struct soc_camera_device *icd) icd->host_priv = NULL; } -static int pxa_camera_check_frame(struct v4l2_pix_format *pix) +static int pxa_camera_check_frame(u32 width, u32 height) { /* limit to pxa hardware capabilities */ - return pix->height < 32 || pix->height > 2048 || pix->width < 48 || - pix->width > 2048 || (pix->width & 0x01); + return height < 32 || height > 2048 || width < 48 || width > 2048 || + (width & 0x01); } static int pxa_camera_set_crop(struct soc_camera_device *icd, @@ -1339,9 +1355,9 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - struct v4l2_format f; - struct v4l2_pix_format *pix = &f.fmt.pix, pix_tmp; + struct v4l2_mbus_framefmt mf; struct pxa_cam *cam = icd->host_priv; + u32 fourcc = icd->current_fmt->host_fmt->fourcc; int ret; /* If PCLK is used to latch data from the sensor, check sense */ @@ -1358,27 +1374,23 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, return ret; } - f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, g_fmt, &f); + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); if (ret < 0) return ret; - pix_tmp = *pix; - if (pxa_camera_check_frame(pix)) { + if (pxa_camera_check_frame(mf.width, mf.height)) { /* * Camera cropping produced a frame beyond our capabilities. * FIXME: just extract a subframe, that we can process. */ - v4l_bound_align_image(&pix->width, 48, 2048, 1, - &pix->height, 32, 2048, 0, - icd->current_fmt->fourcc == V4L2_PIX_FMT_YUV422P ? - 4 : 0); - ret = v4l2_subdev_call(sd, video, s_fmt, &f); + v4l_bound_align_image(&mf.width, 48, 2048, 1, + &mf.height, 32, 2048, 0, + fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); if (ret < 0) return ret; - if (pxa_camera_check_frame(pix)) { + if (pxa_camera_check_frame(mf.width, mf.height)) { dev_warn(icd->dev.parent, "Inconsistent state. Use S_FMT to repair\n"); return -EINVAL; @@ -1395,10 +1407,10 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, recalculate_fifo_timeout(pcdev, sense.pixel_clock); } - icd->user_width = pix->width; - icd->user_height = pix->height; + icd->user_width = mf.width; + icd->user_height = mf.height; - pxa_camera_setup_cicr(icd, cam->flags, icd->current_fmt->fourcc); + pxa_camera_setup_cicr(icd, cam->flags, fourcc); return ret; } @@ -1410,14 +1422,13 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, struct pxa_camera_dev *pcdev = ici->priv; struct device *dev = icd->dev.parent; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_data_format *cam_fmt = NULL; const struct soc_camera_format_xlate *xlate = NULL; struct soc_camera_sense sense = { .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_format cam_f = *f; + struct v4l2_mbus_framefmt mf; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1426,26 +1437,31 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - cam_fmt = xlate->cam_fmt; - /* If PCLK is used to latch data from the sensor, check sense */ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) + /* The caller holds a mutex. */ icd->sense = &sense; - cam_f.fmt.pix.pixelformat = cam_fmt->fourcc; - ret = v4l2_subdev_call(sd, video, s_fmt, &cam_f); - cam_f.fmt.pix.pixelformat = pix->pixelformat; - *pix = cam_f.fmt.pix; + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; + + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + + if (mf.code != xlate->code) + return -EINVAL; icd->sense = NULL; if (ret < 0) { dev_warn(dev, "Failed to configure for format %x\n", pix->pixelformat); - } else if (pxa_camera_check_frame(pix)) { + } else if (pxa_camera_check_frame(mf.width, mf.height)) { dev_warn(dev, "Camera driver produced an unsupported frame %dx%d\n", - pix->width, pix->height); + mf.width, mf.height); ret = -EINVAL; } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { @@ -1457,10 +1473,14 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, recalculate_fifo_timeout(pcdev, sense.pixel_clock); } - if (!ret) { - icd->buswidth = xlate->buswidth; - icd->current_fmt = xlate->host_fmt; - } + if (ret < 0) + return ret; + + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + icd->current_fmt = xlate; return ret; } @@ -1468,17 +1488,16 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, static int pxa_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_mbus_framefmt mf; __u32 pixfmt = pix->pixelformat; - enum v4l2_field field; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(ici->v4l2_dev.dev, "Format %x not found\n", pixfmt); + dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -1492,22 +1511,36 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, &pix->height, 32, 2048, 0, pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); - pix->bytesperline = pix->width * - DIV_ROUND_UP(xlate->host_fmt->depth, 8); + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; pix->sizeimage = pix->height * pix->bytesperline; - /* camera has to see its format, but the user the original one */ - pix->pixelformat = xlate->cam_fmt->fourcc; /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_fmt, f); - pix->pixelformat = pixfmt; + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; - field = pix->field; + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + if (ret < 0) + return ret; - if (field == V4L2_FIELD_ANY) { - pix->field = V4L2_FIELD_NONE; - } else if (field != V4L2_FIELD_NONE) { - dev_err(icd->dev.parent, "Field type %d unsupported.\n", field); + pix->width = mf.width; + pix->height = mf.height; + pix->colorspace = mf.colorspace; + + switch (mf.field) { + case V4L2_FIELD_ANY: + case V4L2_FIELD_NONE: + pix->field = V4L2_FIELD_NONE; + break; + default: + /* TODO: support interlaced at least in pass-through mode */ + dev_err(icd->dev.parent, "Field type %d unsupported.\n", + mf.field); return -EINVAL; } @@ -1519,10 +1552,12 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf, { int i; - /* This is for locking debugging only. I removed spinlocks and now I + /* + * This is for locking debugging only. I removed spinlocks and now I * check whether .prepare is ever called on a linked buffer, or whether * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered */ + * it hadn't triggered + */ for (i = 0; i < p->count; i++) { struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i], struct pxa_buffer, vb); @@ -1657,8 +1692,10 @@ static int __devinit pxa_camera_probe(struct platform_device *pdev) pcdev->platform_flags = pcdev->pdata->flags; if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { - /* Platform hasn't set available data widths. This is bad. - * Warn and use a default. */ + /* + * Platform hasn't set available data widths. This is bad. + * Warn and use a default. + */ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " "data widths, using default 10 bit\n"); pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c index 373f2a30a677..805226e0d9c1 100644 --- a/drivers/media/video/rj54n1cb0c.c +++ b/drivers/media/video/rj54n1cb0c.c @@ -13,9 +13,11 @@ #include <linux/slab.h> #include <linux/videodev2.h> +#include <media/rj54n1cb0c.h> +#include <media/soc_camera.h> +#include <media/soc_mediabus.h> #include <media/v4l2-subdev.h> #include <media/v4l2-chip-ident.h> -#include <media/soc_camera.h> #define RJ54N1_DEV_CODE 0x0400 #define RJ54N1_DEV_CODE2 0x0401 @@ -38,6 +40,7 @@ #define RJ54N1_H_OBEN_OFS 0x0413 #define RJ54N1_V_OBEN_OFS 0x0414 #define RJ54N1_RESIZE_CONTROL 0x0415 +#define RJ54N1_STILL_CONTROL 0x0417 #define RJ54N1_INC_USE_SEL_H 0x0425 #define RJ54N1_INC_USE_SEL_L 0x0426 #define RJ54N1_MIRROR_STILL_MODE 0x0427 @@ -49,10 +52,21 @@ #define RJ54N1_RA_SEL_UL 0x0530 #define RJ54N1_BYTE_SWAP 0x0531 #define RJ54N1_OUT_SIGPO 0x053b +#define RJ54N1_WB_SEL_WEIGHT_I 0x054e +#define RJ54N1_BIT8_WB 0x0569 +#define RJ54N1_HCAPS_WB 0x056a +#define RJ54N1_VCAPS_WB 0x056b +#define RJ54N1_HCAPE_WB 0x056c +#define RJ54N1_VCAPE_WB 0x056d +#define RJ54N1_EXPOSURE_CONTROL 0x058c #define RJ54N1_FRAME_LENGTH_S_H 0x0595 #define RJ54N1_FRAME_LENGTH_S_L 0x0596 #define RJ54N1_FRAME_LENGTH_P_H 0x0597 #define RJ54N1_FRAME_LENGTH_P_L 0x0598 +#define RJ54N1_PEAK_H 0x05b7 +#define RJ54N1_PEAK_50 0x05b8 +#define RJ54N1_PEAK_60 0x05b9 +#define RJ54N1_PEAK_DIFF 0x05ba #define RJ54N1_IOC 0x05ef #define RJ54N1_TG_BYPASS 0x0700 #define RJ54N1_PLL_L 0x0701 @@ -68,6 +82,7 @@ #define RJ54N1_OCLK_SEL_EN 0x0713 #define RJ54N1_CLK_RST 0x0717 #define RJ54N1_RESET_STANDBY 0x0718 +#define RJ54N1_FWFLG 0x07fe #define E_EXCLK (1 << 7) #define SOFT_STDBY (1 << 4) @@ -78,29 +93,53 @@ #define RESIZE_HOLD_SEL (1 << 2) #define RESIZE_GO (1 << 1) +/* + * When cropping, the camera automatically centers the cropped region, there + * doesn't seem to be a way to specify an explicit location of the rectangle. + */ #define RJ54N1_COLUMN_SKIP 0 #define RJ54N1_ROW_SKIP 0 #define RJ54N1_MAX_WIDTH 1600 #define RJ54N1_MAX_HEIGHT 1200 +#define PLL_L 2 +#define PLL_N 0x31 + /* I2C addresses: 0x50, 0x51, 0x60, 0x61 */ -static const struct soc_camera_data_format rj54n1_colour_formats[] = { - { - .name = "YUYV", - .depth = 16, - .fourcc = V4L2_PIX_FMT_YUYV, - .colorspace = V4L2_COLORSPACE_JPEG, - }, { - .name = "RGB565", - .depth = 16, - .fourcc = V4L2_PIX_FMT_RGB565, - .colorspace = V4L2_COLORSPACE_SRGB, - } +/* RJ54N1CB0C has only one fixed colorspace per pixelcode */ +struct rj54n1_datafmt { + enum v4l2_mbus_pixelcode code; + enum v4l2_colorspace colorspace; +}; + +/* Find a data format by a pixel code in an array */ +static const struct rj54n1_datafmt *rj54n1_find_datafmt( + enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt, + int n) +{ + int i; + for (i = 0; i < n; i++) + if (fmt[i].code == code) + return fmt + i; + + return NULL; +} + +static const struct rj54n1_datafmt rj54n1_colour_fmts[] = { + {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG}, + {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB}, + {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB}, }; struct rj54n1_clock_div { - u8 ratio_tg; + u8 ratio_tg; /* can be 0 or an odd number */ u8 ratio_t; u8 ratio_r; u8 ratio_op; @@ -109,12 +148,14 @@ struct rj54n1_clock_div { struct rj54n1 { struct v4l2_subdev subdev; + struct rj54n1_clock_div clk_div; + const struct rj54n1_datafmt *fmt; struct v4l2_rect rect; /* Sensor window */ + unsigned int tgclk_mhz; + bool auto_wb; unsigned short width; /* Output window */ unsigned short height; unsigned short resize; /* Sensor * 1024 / resize = Output */ - struct rj54n1_clock_div clk_div; - u32 fourcc; unsigned short scale; u8 bank; }; @@ -171,7 +212,7 @@ const static struct rj54n1_reg_val bank_7[] = { {0x714, 0xff}, {0x715, 0xff}, {0x716, 0x1f}, - {0x7FE, 0x02}, + {0x7FE, 2}, }; const static struct rj54n1_reg_val bank_8[] = { @@ -359,7 +400,7 @@ const static struct rj54n1_reg_val bank_8[] = { {0x8BB, 0x00}, {0x8BC, 0xFF}, {0x8BD, 0x00}, - {0x8FE, 0x02}, + {0x8FE, 2}, }; const static struct rj54n1_reg_val bank_10[] = { @@ -440,12 +481,24 @@ static int reg_write_multiple(struct i2c_client *client, return 0; } -static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) +static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) { - /* TODO: start / stop streaming */ + if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts)) + return -EINVAL; + + *code = rj54n1_colour_fmts[index].code; return 0; } +static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct i2c_client *client = sd->priv; + + /* Switch between preview and still shot modes */ + return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80); +} + static int rj54n1_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { @@ -502,6 +555,44 @@ static int rj54n1_commit(struct i2c_client *client) return ret; } +static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, + u32 *out_w, u32 *out_h); + +static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) +{ + struct i2c_client *client = sd->priv; + struct rj54n1 *rj54n1 = to_rj54n1(client); + struct v4l2_rect *rect = &a->c; + unsigned int dummy = 0, output_w, output_h, + input_w = rect->width, input_h = rect->height; + int ret; + + /* arbitrary minimum width and height, edges unimportant */ + soc_camera_limit_side(&dummy, &input_w, + RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH); + + soc_camera_limit_side(&dummy, &input_h, + RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT); + + output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize; + output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize; + + dev_dbg(&client->dev, "Scaling for %ux%u : %u = %ux%u\n", + input_w, input_h, rj54n1->resize, output_w, output_h); + + ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); + if (ret < 0) + return ret; + + rj54n1->width = output_w; + rj54n1->height = output_h; + rj54n1->resize = ret; + rj54n1->rect.width = input_w; + rj54n1->rect.height = input_h; + + return 0; +} + static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) { struct i2c_client *client = sd->priv; @@ -527,16 +618,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int rj54n1_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int rj54n1_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct rj54n1 *rj54n1 = to_rj54n1(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->pixelformat = rj54n1->fourcc; - pix->field = V4L2_FIELD_NONE; - pix->width = rj54n1->width; - pix->height = rj54n1->height; + mf->code = rj54n1->fmt->code; + mf->colorspace = rj54n1->fmt->colorspace; + mf->field = V4L2_FIELD_NONE; + mf->width = rj54n1->width; + mf->height = rj54n1->height; return 0; } @@ -550,11 +642,44 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, u32 *out_w, u32 *out_h) { struct i2c_client *client = sd->priv; + struct rj54n1 *rj54n1 = to_rj54n1(client); unsigned int skip, resize, input_w = *in_w, input_h = *in_h, output_w = *out_w, output_h = *out_h; - u16 inc_sel; + u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom; + unsigned int peak, peak_50, peak_60; int ret; + /* + * We have a problem with crops, where the window is larger than 512x384 + * and output window is larger than a half of the input one. In this + * case we have to either reduce the input window to equal or below + * 512x384 or the output window to equal or below 1/2 of the input. + */ + if (output_w > max(512U, input_w / 2)) { + if (2 * output_w > RJ54N1_MAX_WIDTH) { + input_w = RJ54N1_MAX_WIDTH; + output_w = RJ54N1_MAX_WIDTH / 2; + } else { + input_w = output_w * 2; + } + + dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n", + input_w, output_w); + } + + if (output_h > max(384U, input_h / 2)) { + if (2 * output_h > RJ54N1_MAX_HEIGHT) { + input_h = RJ54N1_MAX_HEIGHT; + output_h = RJ54N1_MAX_HEIGHT / 2; + } else { + input_h = output_h * 2; + } + + dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n", + input_h, output_h); + } + + /* Idea: use the read mode for snapshots, handle separate geometries */ ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L, RJ54N1_Y_OUTPUT_SIZE_S_L, RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h); @@ -566,17 +691,27 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, if (ret < 0) return ret; - if (output_w > input_w || output_h > input_h) { + if (output_w > input_w && output_h > input_h) { input_w = output_w; input_h = output_h; resize = 1024; } else { unsigned int resize_x, resize_y; - resize_x = input_w * 1024 / output_w; - resize_y = input_h * 1024 / output_h; - - resize = min(resize_x, resize_y); + resize_x = (input_w * 1024 + output_w / 2) / output_w; + resize_y = (input_h * 1024 + output_h / 2) / output_h; + + /* We want max(resize_x, resize_y), check if it still fits */ + if (resize_x > resize_y && + (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT) + resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) / + output_h; + else if (resize_y > resize_x && + (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH) + resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) / + output_w; + else + resize = max(resize_x, resize_y); /* Prohibited value ranges */ switch (resize) { @@ -589,12 +724,9 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, case 8160 ... 8191: resize = 8159; break; - case 16320 ... 16383: + case 16320 ... 16384: resize = 16319; } - - input_w = output_w * resize / 1024; - input_h = output_h * resize / 1024; } /* Set scaling */ @@ -607,9 +739,18 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, /* * Configure a skipping bitmask. The sensor will select a skipping value - * among set bits automatically. + * among set bits automatically. This is very unclear in the datasheet + * too. I was told, in this register one enables all skipping values, + * that are required for a specific resize, and the camera selects + * automatically, which ones to use. But it is unclear how to identify, + * which cropping values are needed. Secondly, why don't we just set all + * bits and let the camera choose? Would it increase processing time and + * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to + * improve the image quality or stability for larger frames (see comment + * above), but I didn't check the framerate. */ skip = min(resize / 1024, (unsigned)15); + inc_sel = 1 << skip; if (inc_sel <= 2) @@ -621,6 +762,43 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, if (!ret) ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8); + if (!rj54n1->auto_wb) { + /* Auto white balance window */ + wb_left = output_w / 16; + wb_right = (3 * output_w / 4 - 3) / 4; + wb_top = output_h / 16; + wb_bottom = (3 * output_h / 4 - 3) / 4; + wb_bit8 = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) | + ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1); + + if (!ret) + ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8); + if (!ret) + ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left); + if (!ret) + ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top); + if (!ret) + ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right); + if (!ret) + ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom); + } + + /* Antiflicker */ + peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz / + 10000; + peak_50 = peak / 6; + peak_60 = peak / 5; + + if (!ret) + ret = reg_write(client, RJ54N1_PEAK_H, + ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8)); + if (!ret) + ret = reg_write(client, RJ54N1_PEAK_50, peak_50); + if (!ret) + ret = reg_write(client, RJ54N1_PEAK_60, peak_60); + if (!ret) + ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150); + /* Start resizing */ if (!ret) ret = reg_write(client, RJ54N1_RESIZE_CONTROL, @@ -629,8 +807,6 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, if (ret < 0) return ret; - dev_dbg(&client->dev, "resize %u, skip %u\n", resize, skip); - /* Constant taken from manufacturer's example */ msleep(230); @@ -638,11 +814,14 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, u32 *in_w, u32 *in_h, if (ret < 0) return ret; - *in_w = input_w; - *in_h = input_h; + *in_w = (output_w * resize + 512) / 1024; + *in_h = (output_h * resize + 512) / 1024; *out_w = output_w; *out_h = output_h; + dev_dbg(&client->dev, "Scaled for %ux%u : %u = %ux%u, skip %u\n", + *in_w, *in_h, resize, output_w, output_h, skip); + return resize; } @@ -653,14 +832,14 @@ static int rj54n1_set_clock(struct i2c_client *client) /* Enable external clock */ ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY); - /* Leave stand-by */ + /* Leave stand-by. Note: use this when implementing suspend / resume */ if (!ret) ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK); if (!ret) - ret = reg_write(client, RJ54N1_PLL_L, 2); + ret = reg_write(client, RJ54N1_PLL_L, PLL_L); if (!ret) - ret = reg_write(client, RJ54N1_PLL_N, 0x31); + ret = reg_write(client, RJ54N1_PLL_N, PLL_N); /* TGCLK dividers */ if (!ret) @@ -719,6 +898,7 @@ static int rj54n1_set_clock(struct i2c_client *client) "Resetting RJ54N1CB0C clock failed: %d!\n", ret); return -EIO; } + /* Start the PLL */ ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1); @@ -731,6 +911,7 @@ static int rj54n1_set_clock(struct i2c_client *client) static int rj54n1_reg_init(struct i2c_client *client) { + struct rj54n1 *rj54n1 = to_rj54n1(client); int ret = rj54n1_set_clock(client); if (!ret) @@ -753,14 +934,26 @@ static int rj54n1_reg_init(struct i2c_client *client) if (!ret) ret = reg_write(client, RJ54N1_Y_GAIN, 0x84); - /* Mirror the image back: default is upside down and left-to-right... */ + /* + * Mirror the image back: default is upside down and left-to-right... + * Set manual preview / still shot switching + */ if (!ret) - ret = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 3, 3); + ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27); if (!ret) ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4)); + + /* Auto exposure area */ if (!ret) + ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80); + /* Check current auto WB config */ + if (!ret) + ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I); + if (ret >= 0) { + rj54n1->auto_wb = ret & 0x80; ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5)); + } if (!ret) ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8)); @@ -777,8 +970,9 @@ static int rj54n1_reg_init(struct i2c_client *client) ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX); + /* Start register update? Same register as 0x?FE in many bank_* sets */ if (!ret) - ret = reg_write(client, 0x7fe, 2); + ret = reg_write(client, RJ54N1_FWFLG, 2); /* Constant taken from manufacturer's example */ msleep(700); @@ -786,27 +980,44 @@ static int rj54n1_reg_init(struct i2c_client *client) return ret; } -/* FIXME: streaming output only up to 800x600 is functional */ -static int rj54n1_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int rj54n1_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { - struct v4l2_pix_format *pix = &f->fmt.pix; + struct i2c_client *client = sd->priv; + struct rj54n1 *rj54n1 = to_rj54n1(client); + const struct rj54n1_datafmt *fmt; + int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE || + mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE; + + dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", + __func__, mf->code, mf->width, mf->height); + + fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, + ARRAY_SIZE(rj54n1_colour_fmts)); + if (!fmt) { + fmt = rj54n1->fmt; + mf->code = fmt->code; + } - pix->field = V4L2_FIELD_NONE; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = fmt->colorspace; - if (pix->width > 800) - pix->width = 800; - if (pix->height > 600) - pix->height = 600; + v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, + &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); return 0; } -static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int rj54n1_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct rj54n1 *rj54n1 = to_rj54n1(client); - struct v4l2_pix_format *pix = &f->fmt.pix; - unsigned int output_w, output_h, + const struct rj54n1_datafmt *fmt; + unsigned int output_w, output_h, max_w, max_h, input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; int ret; @@ -814,14 +1025,13 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) * The host driver can call us without .try_fmt(), so, we have to take * care ourseleves */ - ret = rj54n1_try_fmt(sd, f); + rj54n1_try_fmt(sd, mf); /* * Verify if the sensor has just been powered on. TODO: replace this * with proper PM, when a suitable API is available. */ - if (!ret) - ret = reg_read(client, RJ54N1_RESET_STANDBY); + ret = reg_read(client, RJ54N1_RESET_STANDBY); if (ret < 0) return ret; @@ -831,50 +1041,105 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) return ret; } + dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", + __func__, mf->code, mf->width, mf->height); + /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ - switch (pix->pixelformat) { - case V4L2_PIX_FMT_YUYV: + switch (mf->code) { + case V4L2_MBUS_FMT_YUYV8_2X8_LE: ret = reg_write(client, RJ54N1_OUT_SEL, 0); if (!ret) ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); break; - case V4L2_PIX_FMT_RGB565: + case V4L2_MBUS_FMT_YVYU8_2X8_LE: + ret = reg_write(client, RJ54N1_OUT_SEL, 0); + if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); + break; + case V4L2_MBUS_FMT_RGB565_2X8_LE: + ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); + if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); + break; + case V4L2_MBUS_FMT_RGB565_2X8_BE: ret = reg_write(client, RJ54N1_OUT_SEL, 0x11); if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); + break; + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE: + ret = reg_write(client, RJ54N1_OUT_SEL, 4); + if (!ret) ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); + if (!ret) + ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); + break; + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE: + ret = reg_write(client, RJ54N1_OUT_SEL, 4); + if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8); + if (!ret) + ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); + break; + case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE: + ret = reg_write(client, RJ54N1_OUT_SEL, 4); + if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); + if (!ret) + ret = reg_write(client, RJ54N1_RA_SEL_UL, 0); + break; + case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE: + ret = reg_write(client, RJ54N1_OUT_SEL, 4); + if (!ret) + ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8); + if (!ret) + ret = reg_write(client, RJ54N1_RA_SEL_UL, 8); + break; + case V4L2_MBUS_FMT_SBGGR10_1X10: + ret = reg_write(client, RJ54N1_OUT_SEL, 5); break; default: ret = -EINVAL; } + /* Special case: a raw mode with 10 bits of data per clock tick */ + if (!ret) + ret = reg_set(client, RJ54N1_OCLK_SEL_EN, + (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2); + if (ret < 0) return ret; - /* Supported scales 1:1 - 1:16 */ - if (pix->width < input_w / 16) - pix->width = input_w / 16; - if (pix->height < input_h / 16) - pix->height = input_h / 16; + /* Supported scales 1:1 >= scale > 1:16 */ + max_w = mf->width * (16 * 1024 - 1) / 1024; + if (input_w > max_w) + input_w = max_w; + max_h = mf->height * (16 * 1024 - 1) / 1024; + if (input_h > max_h) + input_h = max_h; - output_w = pix->width; - output_h = pix->height; + output_w = mf->width; + output_h = mf->height; ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h); if (ret < 0) return ret; - rj54n1->fourcc = pix->pixelformat; + fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts, + ARRAY_SIZE(rj54n1_colour_fmts)); + + rj54n1->fmt = fmt; rj54n1->resize = ret; rj54n1->rect.width = input_w; rj54n1->rect.height = input_h; rj54n1->width = output_w; rj54n1->height = output_h; - pix->width = output_w; - pix->height = output_h; - pix->field = V4L2_FIELD_NONE; + mf->width = output_w; + mf->height = output_h; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = fmt->colorspace; - return ret; + return 0; } static int rj54n1_g_chip_ident(struct v4l2_subdev *sd, @@ -963,6 +1228,14 @@ static const struct v4l2_queryctrl rj54n1_controls[] = { .step = 1, .default_value = 66, .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_AUTO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto white balance", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, }, }; @@ -976,6 +1249,7 @@ static struct soc_camera_ops rj54n1_ops = { static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { struct i2c_client *client = sd->priv; + struct rj54n1 *rj54n1 = to_rj54n1(client); int data; switch (ctrl->id) { @@ -998,6 +1272,9 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) ctrl->value = data / 2; break; + case V4L2_CID_AUTO_WHITE_BALANCE: + ctrl->value = rj54n1->auto_wb; + break; } return 0; @@ -1007,6 +1284,7 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) { int data; struct i2c_client *client = sd->priv; + struct rj54n1 *rj54n1 = to_rj54n1(client); const struct v4l2_queryctrl *qctrl; qctrl = soc_camera_find_qctrl(&rj54n1_ops, ctrl->id); @@ -1037,6 +1315,13 @@ static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) else if (reg_write(client, RJ54N1_Y_GAIN, ctrl->value * 2) < 0) return -EIO; break; + case V4L2_CID_AUTO_WHITE_BALANCE: + /* Auto WB area - whole image */ + if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->value << 7, + 0x80) < 0) + return -EIO; + rj54n1->auto_wb = ctrl->value; + break; } return 0; @@ -1054,10 +1339,12 @@ static struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = { static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_stream = rj54n1_s_stream, - .s_fmt = rj54n1_s_fmt, - .g_fmt = rj54n1_g_fmt, - .try_fmt = rj54n1_try_fmt, + .s_mbus_fmt = rj54n1_s_fmt, + .g_mbus_fmt = rj54n1_g_fmt, + .try_mbus_fmt = rj54n1_try_fmt, + .enum_mbus_fmt = rj54n1_enum_fmt, .g_crop = rj54n1_g_crop, + .s_crop = rj54n1_s_crop, .cropcap = rj54n1_cropcap, }; @@ -1066,21 +1353,13 @@ static struct v4l2_subdev_ops rj54n1_subdev_ops = { .video = &rj54n1_subdev_video_ops, }; -static int rj54n1_pin_config(struct i2c_client *client) -{ - /* - * Experimentally found out IOCTRL wired to 0. TODO: add to platform - * data: 0 or 1 << 7. - */ - return reg_write(client, RJ54N1_IOC, 0); -} - /* * Interface active, can use i2c. If it fails, it can indeed mean, that * this wasn't our capture interface, so, we wait for the right one */ static int rj54n1_video_probe(struct soc_camera_device *icd, - struct i2c_client *client) + struct i2c_client *client, + struct rj54n1_pdata *priv) { int data1, data2; int ret; @@ -1101,7 +1380,8 @@ static int rj54n1_video_probe(struct soc_camera_device *icd, goto ei2c; } - ret = rj54n1_pin_config(client); + /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */ + ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7); if (ret < 0) goto ei2c; @@ -1119,6 +1399,7 @@ static int rj54n1_probe(struct i2c_client *client, struct soc_camera_device *icd = client->dev.platform_data; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct soc_camera_link *icl; + struct rj54n1_pdata *rj54n1_priv; int ret; if (!icd) { @@ -1127,11 +1408,13 @@ static int rj54n1_probe(struct i2c_client *client, } icl = to_soc_camera_link(icd); - if (!icl) { + if (!icl || !icl->priv) { dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n"); return -EINVAL; } + rj54n1_priv = icl->priv; + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_warn(&adapter->dev, "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n"); @@ -1153,10 +1436,12 @@ static int rj54n1_probe(struct i2c_client *client, rj54n1->rect.height = RJ54N1_MAX_HEIGHT; rj54n1->width = RJ54N1_MAX_WIDTH; rj54n1->height = RJ54N1_MAX_HEIGHT; - rj54n1->fourcc = V4L2_PIX_FMT_YUYV; + rj54n1->fmt = &rj54n1_colour_fmts[0]; rj54n1->resize = 1024; + rj54n1->tgclk_mhz = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) / + (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1); - ret = rj54n1_video_probe(icd, client); + ret = rj54n1_video_probe(icd, client, rj54n1_priv); if (ret < 0) { icd->ops = NULL; i2c_set_clientdata(client, NULL); @@ -1164,9 +1449,6 @@ static int rj54n1_probe(struct i2c_client *client, return ret; } - icd->formats = rj54n1_colour_formats; - icd->num_formats = ARRAY_SIZE(rj54n1_colour_formats); - return ret; } diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 41765f3c7c28..fb742f1ae711 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c @@ -233,7 +233,6 @@ struct s2255_dev { struct s2255_dmaqueue vidq[MAX_CHANNELS]; struct video_device *vdev[MAX_CHANNELS]; - struct list_head s2255_devlist; struct timer_list timer; struct s2255_fw *fw_data; struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; @@ -313,8 +312,6 @@ struct s2255_fh { /* Channels on box are in reverse order */ static unsigned long G_chnmap[MAX_CHANNELS] = {3, 2, 1, 0}; -static LIST_HEAD(s2255_devlist); - static int debug; static int *s2255_debug = &debug; @@ -1533,32 +1530,24 @@ static int vidioc_s_parm(struct file *file, void *priv, } static int s2255_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct s2255_dev *h, *dev = NULL; + struct video_device *vdev = video_devdata(file); + struct s2255_dev *dev = video_drvdata(file); struct s2255_fh *fh; - struct list_head *list; - enum v4l2_buf_type type = 0; + enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int i = 0; int cur_channel = -1; int state; - dprintk(1, "s2255: open called (minor=%d)\n", minor); + + dprintk(1, "s2255: open called (dev=%s)\n", + video_device_node_name(vdev)); lock_kernel(); - list_for_each(list, &s2255_devlist) { - h = list_entry(list, struct s2255_dev, s2255_devlist); - for (i = 0; i < MAX_CHANNELS; i++) { - if (h->vdev[i]->minor == minor) { - cur_channel = i; - dev = h; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - } - if ((NULL == dev) || (cur_channel == -1)) { - unlock_kernel(); - printk(KERN_INFO "s2255: openv4l no dev\n"); - return -ENODEV; + for (i = 0; i < MAX_CHANNELS; i++) { + if (dev->vdev[i] == vdev) { + cur_channel = i; + break; + } } if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) { @@ -1662,8 +1651,9 @@ static int s2255_open(struct file *file) for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) qctl_regs[i] = s2255_qctrl[i].default_value; - dprintk(1, "s2255drv: open minor=%d type=%s users=%d\n", - minor, v4l2_type_names[type], dev->users[cur_channel]); + dprintk(1, "s2255drv: open dev=%s type=%s users=%d\n", + video_device_node_name(vdev), v4l2_type_names[type], + dev->users[cur_channel]); dprintk(2, "s2255drv: open: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", (unsigned long)fh, (unsigned long)dev, (unsigned long)&dev->vidq[cur_channel]); @@ -1699,7 +1689,6 @@ static unsigned int s2255_poll(struct file *file, static void s2255_destroy(struct kref *kref) { struct s2255_dev *dev = to_s2255_dev(kref); - struct list_head *list; int i; if (!dev) { printk(KERN_ERR "s2255drv: kref problem\n"); @@ -1733,10 +1722,6 @@ static void s2255_destroy(struct kref *kref) usb_put_dev(dev->udev); dprintk(1, "%s", __func__); - while (!list_empty(&s2255_devlist)) { - list = s2255_devlist.next; - list_del(list); - } mutex_unlock(&dev->open_lock); kfree(dev); } @@ -1745,7 +1730,8 @@ static int s2255_close(struct file *file) { struct s2255_fh *fh = file->private_data; struct s2255_dev *dev = fh->dev; - int minor = video_devdata(file)->minor; + struct video_device *vdev = video_devdata(file); + if (!dev) return -ENODEV; @@ -1765,8 +1751,8 @@ static int s2255_close(struct file *file) mutex_unlock(&dev->open_lock); kref_put(&dev->kref, s2255_destroy); - dprintk(1, "s2255: close called (minor=%d, users=%d)\n", - minor, dev->users[fh->channel]); + dprintk(1, "s2255: close called (dev=%s, users=%d)\n", + video_device_node_name(vdev), dev->users[fh->channel]); kfree(fh); return 0; } @@ -1830,7 +1816,6 @@ static struct video_device template = { .name = "s2255v", .fops = &s2255_fops_v4l, .ioctl_ops = &s2255_ioctl_ops, - .minor = -1, .release = video_device_release, .tvnorms = S2255_NORMS, .current_norm = V4L2_STD_NTSC_M, @@ -1843,7 +1828,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) int cur_nr = video_nr; /* initialize all video 4 linux */ - list_add_tail(&dev->s2255_devlist, &s2255_devlist); /* register 4 video devices */ for (i = 0; i < MAX_CHANNELS; i++) { INIT_LIST_HEAD(&dev->vidq[i].active); @@ -1853,6 +1837,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) dev->vdev[i] = video_device_alloc(); memcpy(dev->vdev[i], &template, sizeof(struct video_device)); dev->vdev[i]->parent = &dev->interface->dev; + video_set_drvdata(dev->vdev[i], dev); if (video_nr == -1) ret = video_register_device(dev->vdev[i], VFL_TYPE_GRABBER, @@ -1880,7 +1865,7 @@ static void s2255_exit_v4l(struct s2255_dev *dev) int i; for (i = 0; i < MAX_CHANNELS; i++) { - if (-1 != dev->vdev[i]->minor) { + if (video_is_registered(dev->vdev[i])) { video_unregister_device(dev->vdev[i]); printk(KERN_INFO "s2255 unregistered\n"); } else { diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index b624a4c01fdc..5ab6a0f901c0 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -1036,7 +1036,6 @@ static struct video_device saa_template = .name = "saa5246a", .fops = &saa_fops, .release = video_device_release, - .minor = -1, }; static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 7e40d6d99dd0..03f572708b85 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -7211,9 +7211,31 @@ int saa7134_board_init2(struct saa7134_dev *dev) } case SAA7134_BOARD_FLYDVB_TRIO: { + u8 temp = 0; + int rc; u8 data[] = { 0x3c, 0x33, 0x62}; struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); + + /* + * send weak up message to pic16C505 chip + * @ LifeView FlyDVB Trio + */ + msg.buf = &temp; + 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" + "(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", + dev->name, msg.addr, + (1 == rc) ? "yes" : "no"); + if (rc == 1) + dev->has_remote = SAA7134_REMOTE_I2C; + } break; } case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 0ba7f5af0fc3..a7ad7810fddc 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -420,19 +420,6 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) ctrl |= SAA7134_MAIN_CTRL_TE5; irq |= SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0; - - /* dma: setup channel 5 (= TS) */ - - saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff); - saa_writeb(SAA7134_TS_DMA1, - ((dev->ts.nr_packets - 1) >> 8) & 0xff); - /* TSNOPIT=0, TSCOLAP=0 */ - saa_writeb(SAA7134_TS_DMA2, - (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00); - saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); - saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (dev->ts.pt_ts.dma >> 12)); } /* set task conditions + field handling */ @@ -797,27 +784,28 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, saa7134_boards[dev->board].name); + video_set_drvdata(vfd, dev); return vfd; } static void saa7134_unregister_video(struct saa7134_dev *dev) { if (dev->video_dev) { - if (-1 != dev->video_dev->minor) + if (video_is_registered(dev->video_dev)) video_unregister_device(dev->video_dev); else video_device_release(dev->video_dev); dev->video_dev = NULL; } if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) + if (video_is_registered(dev->vbi_dev)) video_unregister_device(dev->vbi_dev); else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; } if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) + if (video_is_registered(dev->radio_dev)) video_unregister_device(dev->radio_dev); else video_device_release(dev->radio_dev); @@ -1046,8 +1034,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->num); + printk(KERN_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"); @@ -1055,8 +1043,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, vbi_nr[dev->nr]); if (err < 0) goto fail4; - printk(KERN_INFO "%s: registered device vbi%d\n", - dev->name, dev->vbi_dev->num); + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->vbi_dev)); if (card_has_radio(dev)) { dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); @@ -1064,8 +1052,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, radio_nr[dev->nr]); if (err < 0) goto fail4; - printk(KERN_INFO "%s: registered device radio%d\n", - dev->name, dev->radio_dev->num); + printk(KERN_INFO "%s: registered device %s\n", + dev->name, video_device_node_name(dev->radio_dev)); } /* everything worked */ diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index 296788c3bf0e..7dfecfc6017c 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -86,19 +86,11 @@ static int ts_init_encoder(struct saa7134_dev* dev) static int ts_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct saa7134_dev *dev; + struct video_device *vdev = video_devdata(file); + struct saa7134_dev *dev = video_drvdata(file); int err; - lock_kernel(); - list_for_each_entry(dev, &saa7134_devlist, devlist) - if (dev->empress_dev && dev->empress_dev->minor == minor) - goto found; - unlock_kernel(); - return -ENODEV; - found: - - dprintk("open minor=%d\n",minor); + dprintk("open dev=%s\n", video_device_node_name(vdev)); err = -EBUSY; if (!mutex_trylock(&dev->empress_tsq.vb_lock)) goto done; @@ -489,7 +481,6 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = { static struct video_device saa7134_empress_template = { .name = "saa7134-empress", .fops = &ts_fops, - .minor = -1, .ioctl_ops = &ts_ioctl_ops, .tvnorms = SAA7134_NORMS, @@ -531,6 +522,7 @@ static int empress_init(struct saa7134_dev *dev) INIT_WORK(&dev->empress_workqueue, empress_signal_update); + video_set_drvdata(dev->empress_dev, dev); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, empress_nr[dev->nr]); if (err < 0) { @@ -540,8 +532,8 @@ static int empress_init(struct saa7134_dev *dev) dev->empress_dev = NULL; return err; } - printk(KERN_INFO "%s: registered device video%d [mpeg]\n", - dev->name, dev->empress_dev->num); + printk(KERN_INFO "%s: registered device %s [mpeg]\n", + dev->name, video_device_node_name(dev->empress_dev)); videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops, &dev->pci->dev, &dev->slock, diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 744918b1cd47..f8e985989ca0 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -127,6 +127,61 @@ static int build_key(struct saa7134_dev *dev) /* --------------------- Chip specific I2C key builders ----------------- */ +static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) +{ + int gpio; + int attempt = 0; + unsigned char b; + + /* We need this to access GPI Used by the saa_readl macro. */ + struct saa7134_dev *dev = ir->c->adapter->algo_data; + + if (dev == NULL) { + dprintk("get_key_flydvb_trio: " + "gir->c->adapter->algo_data is NULL!\n"); + return -EIO; + } + + /* rising SAA7134_GPIGPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); + + if (0x40000 & ~gpio) + return 0; /* No button press */ + + /* No button press - only before first key pressed */ + if (b == 0xFF) + return 0; + + /* poll IR chip */ + /* weak up the IR chip */ + b = 0; + + while (1 != i2c_master_send(ir->c, &b, 1)) { + if ((attempt++) < 10) { + /* + * wait a bit for next attempt - + * I don't know how make it better + */ + msleep(10); + continue; + } + i2cdprintk("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"); + return -EIO; + } + + *ir_key = b; + *ir_raw = b; + return 1; +} + static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) { @@ -622,6 +677,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x020000; polling = 50; /* ms */ break; + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", @@ -652,7 +708,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci)); - err = ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); + err = ir_input_init(input_dev, &ir->ir, ir_type); if (err < 0) goto err_out_free; @@ -672,7 +728,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) dev->remote = ir; saa7134_ir_start(dev, ir); - err = input_register_device(ir->dev); + err = ir_input_register(ir->dev, ir_codes); if (err) goto err_out_stop; @@ -686,8 +742,6 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa7134_ir_stop(dev); dev->remote = NULL; err_out_free: - ir_input_free(input_dev); - input_free_device(input_dev); kfree(ir); return err; } @@ -698,8 +752,7 @@ void saa7134_input_fini(struct saa7134_dev *dev) return; saa7134_ir_stop(dev); - ir_input_free(dev->remote->dev); - input_unregister_device(dev->remote->dev); + ir_input_unregister(dev->remote->dev); kfree(dev->remote); dev->remote = NULL; } @@ -788,6 +841,12 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: info.addr = 0x40; break; + case SAA7134_BOARD_FLYDVB_TRIO: + dev->init_data.name = "FlyDVB Trio"; + dev->init_data.get_key = get_key_flydvb_trio; + dev->init_data.ir_codes = &ir_codes_flydvb_table; + info.addr = 0x0b; + break; default: dprintk("No I2C IR support for board %x\n", dev->board); return; diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c index 03488ba4c99c..b9817d74943f 100644 --- a/drivers/media/video/saa7134/saa7134-ts.c +++ b/drivers/media/video/saa7134/saa7134-ts.c @@ -250,6 +250,19 @@ int saa7134_ts_start(struct saa7134_dev *dev) BUG_ON(dev->ts_started); + /* dma: setup channel 5 (= TS) */ + saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff); + saa_writeb(SAA7134_TS_DMA1, + ((dev->ts.nr_packets - 1) >> 8) & 0xff); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, + (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00); + saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); + saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (dev->ts.pt_ts.dma >> 12)); + + /* reset hardware TS buffers */ saa_writeb(SAA7134_TS_SERIAL1, 0x00); saa_writeb(SAA7134_TS_SERIAL1, 0x03); saa_writeb(SAA7134_TS_SERIAL1, 0x00); diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 35f8daa3a359..cb732640ac4a 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1326,33 +1326,26 @@ static int saa7134_resource(struct saa7134_fh *fh) static int video_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct saa7134_dev *dev; + struct video_device *vdev = video_devdata(file); + struct saa7134_dev *dev = video_drvdata(file); struct saa7134_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + enum v4l2_buf_type type = 0; int radio = 0; - mutex_lock(&saa7134_devlist_lock); - list_for_each_entry(dev, &saa7134_devlist, devlist) { - if (dev->video_dev && (dev->video_dev->minor == minor)) - goto found; - if (dev->radio_dev && (dev->radio_dev->minor == minor)) { - radio = 1; - goto found; - } - if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) { - type = V4L2_BUF_TYPE_VBI_CAPTURE; - goto found; - } + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + type = V4L2_BUF_TYPE_VBI_CAPTURE; + break; + case VFL_TYPE_RADIO: + radio = 1; + break; } - mutex_unlock(&saa7134_devlist_lock); - return -ENODEV; - -found: - mutex_unlock(&saa7134_devlist_lock); - dprintk("open minor=%d radio=%d type=%s\n",minor,radio, - v4l2_type_names[type]); + dprintk("open dev=%s radio=%d type=%s\n", video_device_node_name(vdev), + radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); @@ -2502,7 +2495,6 @@ struct video_device saa7134_video_template = { .name = "saa7134-video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, - .minor = -1, .tvnorms = SAA7134_NORMS, .current_norm = V4L2_STD_PAL, }; @@ -2511,7 +2503,6 @@ struct video_device saa7134_radio_template = { .name = "saa7134-radio", .fops = &radio_fops, .ioctl_ops = &radio_ioctl_ops, - .minor = -1, }; int saa7134_video_init1(struct saa7134_dev *dev) diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c index 85ffc2cba039..41d0166c0f95 100644 --- a/drivers/media/video/se401.c +++ b/drivers/media/video/se401.c @@ -1428,8 +1428,8 @@ static int se401_probe(struct usb_interface *intf, err("video_register_device failed"); return -EIO; } - dev_info(&intf->dev, "registered new video device: video%d\n", - se401->vdev.num); + dev_info(&intf->dev, "registered new video device: %s\n", + video_device_node_name(&se401->vdev)); usb_set_intfdata(intf, se401); return 0; diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index a4f3472d4db8..f09c7140d6b2 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -38,6 +38,8 @@ #include <media/soc_camera.h> #include <media/sh_mobile_ceu.h> #include <media/videobuf-dma-contig.h> +#include <media/v4l2-mediabus.h> +#include <media/soc_mediabus.h> /* register offsets for sh7722 / sh7723 */ @@ -85,7 +87,7 @@ /* per video frame buffer */ struct sh_mobile_ceu_buffer { struct videobuf_buffer vb; /* v4l buffer must be first */ - const struct soc_camera_data_format *fmt; + enum v4l2_mbus_pixelcode code; }; struct sh_mobile_ceu_dev { @@ -105,7 +107,8 @@ struct sh_mobile_ceu_dev { u32 cflcr; - unsigned int is_interlaced:1; + enum v4l2_field field; + unsigned int image_mode:1; unsigned int is_16bit:1; }; @@ -114,8 +117,8 @@ struct sh_mobile_ceu_cam { struct v4l2_rect ceu_rect; unsigned int cam_width; unsigned int cam_height; - const struct soc_camera_data_format *extra_fmt; - const struct soc_camera_data_format *camera_fmt; + const struct soc_mbus_pixelfmt *extra_fmt; + enum v4l2_mbus_pixelcode code; }; static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev) @@ -197,16 +200,19 @@ static int sh_mobile_ceu_videobuf_setup(struct videobuf_queue *vq, struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; - int bytes_per_pixel = (icd->current_fmt->depth + 7) >> 3; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); + + if (bytes_per_line < 0) + return bytes_per_line; - *size = PAGE_ALIGN(icd->user_width * icd->user_height * - bytes_per_pixel); + *size = bytes_per_line * icd->user_height; if (0 == *count) *count = 2; if (pcdev->video_limit) { - while (*size * *count > pcdev->video_limit) + while (PAGE_ALIGN(*size) * *count > pcdev->video_limit) (*count)--; } @@ -249,10 +255,13 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) { struct soc_camera_device *icd = pcdev->icd; dma_addr_t phys_addr_top, phys_addr_bottom; + unsigned long top1, top2; + unsigned long bottom1, bottom2; u32 status; int ret = 0; - /* The hardware is _very_ picky about this sequence. Especially + /* + * The hardware is _very_ picky about this sequence. Especially * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge * several not-so-well documented interrupt sources in CETCR. */ @@ -276,25 +285,36 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) if (!pcdev->active) return ret; + if (V4L2_FIELD_INTERLACED_BT == pcdev->field) { + top1 = CDBYR; + top2 = CDBCR; + bottom1 = CDAYR; + bottom2 = CDACR; + } else { + top1 = CDAYR; + top2 = CDACR; + bottom1 = CDBYR; + bottom2 = CDBCR; + } + phys_addr_top = videobuf_to_dma_contig(pcdev->active); - ceu_write(pcdev, CDAYR, phys_addr_top); - if (pcdev->is_interlaced) { + ceu_write(pcdev, top1, phys_addr_top); + if (V4L2_FIELD_NONE != pcdev->field) { phys_addr_bottom = phys_addr_top + icd->user_width; - ceu_write(pcdev, CDBYR, phys_addr_bottom); + ceu_write(pcdev, bottom1, phys_addr_bottom); } - switch (icd->current_fmt->fourcc) { + switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: phys_addr_top += icd->user_width * icd->user_height; - ceu_write(pcdev, CDACR, phys_addr_top); - if (pcdev->is_interlaced) { - phys_addr_bottom = phys_addr_top + - icd->user_width; - ceu_write(pcdev, CDBCR, phys_addr_bottom); + ceu_write(pcdev, top2, phys_addr_top); + if (V4L2_FIELD_NONE != pcdev->field) { + phys_addr_bottom = phys_addr_top + icd->user_width; + ceu_write(pcdev, bottom2, phys_addr_bottom); } } @@ -310,8 +330,13 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, { struct soc_camera_device *icd = vq->priv_data; struct sh_mobile_ceu_buffer *buf; + int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, + icd->current_fmt->host_fmt); int ret; + if (bytes_per_line < 0) + return bytes_per_line; + buf = container_of(vb, struct sh_mobile_ceu_buffer, vb); dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%08lx %zd\n", __func__, @@ -321,25 +346,27 @@ static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, WARN_ON(!list_empty(&vb->queue)); #ifdef DEBUG - /* This can be useful if you want to see if we actually fill - * the buffer with something */ + /* + * This can be useful if you want to see if we actually fill + * the buffer with something + */ memset((void *)vb->baddr, 0xaa, vb->bsize); #endif BUG_ON(NULL == icd->current_fmt); - if (buf->fmt != icd->current_fmt || + if (buf->code != icd->current_fmt->code || vb->width != icd->user_width || vb->height != icd->user_height || vb->field != field) { - buf->fmt = icd->current_fmt; + buf->code = icd->current_fmt->code; vb->width = icd->user_width; vb->height = icd->user_height; vb->field = field; vb->state = VIDEOBUF_NEEDS_INIT; } - vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3); + vb->size = vb->height * bytes_per_line; if (0 != vb->baddr && vb->bsize < vb->size) { ret = -EINVAL; goto out; @@ -456,6 +483,7 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; + int ret; if (pcdev->icd) return -EBUSY; @@ -466,9 +494,11 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) pm_runtime_get_sync(ici->v4l2_dev.dev); - pcdev->icd = icd; + ret = sh_mobile_ceu_soft_reset(pcdev); + if (!ret) + pcdev->icd = icd; - return sh_mobile_ceu_soft_reset(pcdev); + return ret; } /* Called with .video_lock held */ @@ -558,24 +588,35 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd, in_width *= 2; left_offset *= 2; } - width = cdwdr_width = out_width; + width = out_width; + cdwdr_width = out_width; } else { - unsigned int w_factor = (icd->current_fmt->depth + 7) >> 3; + int bytes_per_line = soc_mbus_bytes_per_line(out_width, + icd->current_fmt->host_fmt); + unsigned int w_factor; - width = out_width * w_factor / 2; + width = out_width; - if (!pcdev->is_16bit) - w_factor *= 2; + switch (icd->current_fmt->host_fmt->packing) { + case SOC_MBUS_PACKING_2X8_PADHI: + w_factor = 2; + break; + default: + w_factor = 1; + } - in_width = rect->width * w_factor / 2; - left_offset = left_offset * w_factor / 2; + in_width = rect->width * w_factor; + left_offset = left_offset * w_factor; - cdwdr_width = width * 2; + if (bytes_per_line < 0) + cdwdr_width = out_width; + else + cdwdr_width = bytes_per_line; } height = out_height; in_height = rect->height; - if (pcdev->is_interlaced) { + if (V4L2_FIELD_NONE != pcdev->field) { height /= 2; in_height /= 2; top_offset /= 2; @@ -646,6 +687,23 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, if (!common_flags) return -EINVAL; + /* Make choises, based on platform preferences */ + if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { + if (pcdev->pdata->flags & SH_CEU_FLAG_HSYNC_LOW) + common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW; + } + + if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) && + (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) { + if (pcdev->pdata->flags & SH_CEU_FLAG_VSYNC_LOW) + common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH; + else + common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW; + } + ret = icd->ops->set_bus_param(icd, common_flags); if (ret < 0) return ret; @@ -667,24 +725,24 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, value = 0x00000010; /* data fetch by default */ yuv_lineskip = 0; - switch (icd->current_fmt->fourcc) { + switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: yuv_lineskip = 1; /* skip for NV12/21, no skip for NV16/61 */ /* fall-through */ case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV61: - switch (cam->camera_fmt->fourcc) { - case V4L2_PIX_FMT_UYVY: + switch (cam->code) { + case V4L2_MBUS_FMT_YUYV8_2X8_BE: value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */ break; - case V4L2_PIX_FMT_VYUY: + case V4L2_MBUS_FMT_YVYU8_2X8_BE: value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */ break; - case V4L2_PIX_FMT_YUYV: + case V4L2_MBUS_FMT_YUYV8_2X8_LE: value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */ break; - case V4L2_PIX_FMT_YVYU: + case V4L2_MBUS_FMT_YVYU8_2X8_LE: value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */ break; default: @@ -692,8 +750,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, } } - if (icd->current_fmt->fourcc == V4L2_PIX_FMT_NV21 || - icd->current_fmt->fourcc == V4L2_PIX_FMT_NV61) + if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV21 || + icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV61) value ^= 0x00000100; /* swap U, V to change from NV1x->NVx1 */ value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; @@ -702,14 +760,27 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, ceu_write(pcdev, CAMCR, value); ceu_write(pcdev, CAPCR, 0x00300000); - ceu_write(pcdev, CAIFR, pcdev->is_interlaced ? 0x101 : 0); + + switch (pcdev->field) { + case V4L2_FIELD_INTERLACED_TB: + value = 0x101; + break; + case V4L2_FIELD_INTERLACED_BT: + value = 0x102; + break; + default: + value = 0; + break; + } + ceu_write(pcdev, CAIFR, value); sh_mobile_ceu_set_rect(icd, icd->user_width, icd->user_height); mdelay(1); ceu_write(pcdev, CFLCR, pcdev->cflcr); - /* A few words about byte order (observed in Big Endian mode) + /* + * A few words about byte order (observed in Big Endian mode) * * In data fetch mode bytes are received in chunks of 8 bytes. * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) @@ -739,7 +810,8 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd, return 0; } -static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) +static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd, + unsigned char buswidth) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct sh_mobile_ceu_dev *pcdev = ici->priv; @@ -748,48 +820,75 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd) camera_flags = icd->ops->query_bus_param(icd); common_flags = soc_camera_bus_param_compatible(camera_flags, make_bus_param(pcdev)); - if (!common_flags) + if (!common_flags || buswidth > 16 || + (buswidth > 8 && !(common_flags & SOCAM_DATAWIDTH_16))) return -EINVAL; return 0; } -static const struct soc_camera_data_format sh_mobile_ceu_formats[] = { - { - .name = "NV12", - .depth = 12, - .fourcc = V4L2_PIX_FMT_NV12, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - { - .name = "NV21", - .depth = 12, - .fourcc = V4L2_PIX_FMT_NV21, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - { - .name = "NV16", - .depth = 16, - .fourcc = V4L2_PIX_FMT_NV16, - .colorspace = V4L2_COLORSPACE_JPEG, - }, +static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = { { - .name = "NV61", - .depth = 16, - .fourcc = V4L2_PIX_FMT_NV61, - .colorspace = V4L2_COLORSPACE_JPEG, + .fourcc = V4L2_PIX_FMT_NV12, + .name = "NV12", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, { + .fourcc = V4L2_PIX_FMT_NV21, + .name = "NV21", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, { + .fourcc = V4L2_PIX_FMT_NV16, + .name = "NV16", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .name = "NV61", + .bits_per_sample = 16, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, }, }; +/* This will be corrected as we get more formats */ +static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt) +{ + return fmt->packing == SOC_MBUS_PACKING_NONE || + (fmt->bits_per_sample == 8 && + fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) || + (fmt->bits_per_sample > 8 && + fmt->packing == SOC_MBUS_PACKING_EXTEND16); +} + static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, struct soc_camera_format_xlate *xlate) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; int ret, k, n; int formats = 0; struct sh_mobile_ceu_cam *cam; + enum v4l2_mbus_pixelcode code; + const struct soc_mbus_pixelfmt *fmt; - ret = sh_mobile_ceu_try_bus_param(icd); + ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + if (ret < 0) + /* No more formats */ + return 0; + + fmt = soc_mbus_get_fmtdesc(code); + if (!fmt) { + dev_err(icd->dev.parent, + "Invalid format code #%d: %d\n", idx, code); + return -EINVAL; + } + + ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample); if (ret < 0) return 0; @@ -807,13 +906,13 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, if (!idx) cam->extra_fmt = NULL; - switch (icd->formats[idx].fourcc) { - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: + switch (code) { + case V4L2_MBUS_FMT_YUYV8_2X8_BE: + case V4L2_MBUS_FMT_YVYU8_2X8_BE: + case V4L2_MBUS_FMT_YUYV8_2X8_LE: + case V4L2_MBUS_FMT_YVYU8_2X8_LE: if (cam->extra_fmt) - goto add_single_format; + break; /* * Our case is simple so far: for any of the above four camera @@ -824,32 +923,31 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, * the host_priv pointer and check whether the format you're * going to add now is already there. */ - cam->extra_fmt = (void *)sh_mobile_ceu_formats; + cam->extra_fmt = sh_mobile_ceu_formats; n = ARRAY_SIZE(sh_mobile_ceu_formats); formats += n; for (k = 0; xlate && k < n; k++) { - xlate->host_fmt = &sh_mobile_ceu_formats[k]; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = icd->formats[idx].depth; + xlate->host_fmt = &sh_mobile_ceu_formats[k]; + xlate->code = code; xlate++; - dev_dbg(dev, "Providing format %s using %s\n", - sh_mobile_ceu_formats[k].name, - icd->formats[idx].name); + dev_dbg(dev, "Providing format %s using code %d\n", + sh_mobile_ceu_formats[k].name, code); } + break; default: -add_single_format: - /* Generic pass-through */ - formats++; - if (xlate) { - xlate->host_fmt = icd->formats + idx; - xlate->cam_fmt = icd->formats + idx; - xlate->buswidth = icd->formats[idx].depth; - xlate++; - dev_dbg(dev, - "Providing format %s in pass-through mode\n", - icd->formats[idx].name); - } + if (!sh_mobile_ceu_packing_supported(fmt)) + return 0; + } + + /* Generic pass-through */ + formats++; + if (xlate) { + xlate->host_fmt = fmt; + xlate->code = code; + xlate++; + dev_dbg(dev, "Providing format %s in pass-through mode\n", + xlate->host_fmt->name); } return formats; @@ -1029,17 +1127,15 @@ static int client_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *crop, static int get_camera_scales(struct v4l2_subdev *sd, struct v4l2_rect *rect, unsigned int *scale_h, unsigned int *scale_v) { - struct v4l2_format f; + struct v4l2_mbus_framefmt mf; int ret; - f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, g_fmt, &f); + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); if (ret < 0) return ret; - *scale_h = calc_generic_scale(rect->width, f.fmt.pix.width); - *scale_v = calc_generic_scale(rect->height, f.fmt.pix.height); + *scale_h = calc_generic_scale(rect->width, mf.width); + *scale_v = calc_generic_scale(rect->height, mf.height); return 0; } @@ -1054,32 +1150,29 @@ static int get_camera_subwin(struct soc_camera_device *icd, if (!ceu_rect->width) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; - struct v4l2_format f; - struct v4l2_pix_format *pix = &f.fmt.pix; + struct v4l2_mbus_framefmt mf; int ret; /* First time */ - f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = v4l2_subdev_call(sd, video, g_fmt, &f); + ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); if (ret < 0) return ret; - dev_geo(dev, "camera fmt %ux%u\n", pix->width, pix->height); + dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); - if (pix->width > 2560) { + if (mf.width > 2560) { ceu_rect->width = 2560; - ceu_rect->left = (pix->width - 2560) / 2; + ceu_rect->left = (mf.width - 2560) / 2; } else { - ceu_rect->width = pix->width; + ceu_rect->width = mf.width; ceu_rect->left = 0; } - if (pix->height > 1920) { + if (mf.height > 1920) { ceu_rect->height = 1920; - ceu_rect->top = (pix->height - 1920) / 2; + ceu_rect->top = (mf.height - 1920) / 2; } else { - ceu_rect->height = pix->height; + ceu_rect->height = mf.height; ceu_rect->top = 0; } @@ -1096,13 +1189,12 @@ static int get_camera_subwin(struct soc_camera_device *icd, return 0; } -static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, - bool ceu_can_scale) +static int client_s_fmt(struct soc_camera_device *icd, + struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; - struct v4l2_pix_format *pix = &f->fmt.pix; - unsigned int width = pix->width, height = pix->height, tmp_w, tmp_h; + unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; unsigned int max_width, max_height; struct v4l2_cropcap cap; int ret; @@ -1116,29 +1208,29 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, max_width = min(cap.bounds.width, 2560); max_height = min(cap.bounds.height, 1920); - ret = v4l2_subdev_call(sd, video, s_fmt, f); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); if (ret < 0) return ret; - dev_geo(dev, "camera scaled to %ux%u\n", pix->width, pix->height); + dev_geo(dev, "camera scaled to %ux%u\n", mf->width, mf->height); - if ((width == pix->width && height == pix->height) || !ceu_can_scale) + if ((width == mf->width && height == mf->height) || !ceu_can_scale) return 0; /* Camera set a format, but geometry is not precise, try to improve */ - tmp_w = pix->width; - tmp_h = pix->height; + tmp_w = mf->width; + tmp_h = mf->height; /* width <= max_width && height <= max_height - guaranteed by try_fmt */ while ((width > tmp_w || height > tmp_h) && tmp_w < max_width && tmp_h < max_height) { tmp_w = min(2 * tmp_w, max_width); tmp_h = min(2 * tmp_h, max_height); - pix->width = tmp_w; - pix->height = tmp_h; - ret = v4l2_subdev_call(sd, video, s_fmt, f); + mf->width = tmp_w; + mf->height = tmp_h; + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", - pix->width, pix->height); + mf->width, mf->height); if (ret < 0) { /* This shouldn't happen */ dev_err(dev, "Client failed to set format: %d\n", ret); @@ -1156,27 +1248,26 @@ static int client_s_fmt(struct soc_camera_device *icd, struct v4l2_format *f, */ static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, struct v4l2_rect *sub_rect, struct v4l2_rect *ceu_rect, - struct v4l2_format *f, bool ceu_can_scale) + struct v4l2_mbus_framefmt *mf, bool ceu_can_scale) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct sh_mobile_ceu_cam *cam = icd->host_priv; struct device *dev = icd->dev.parent; - struct v4l2_format f_tmp = *f; - struct v4l2_pix_format *pix_tmp = &f_tmp.fmt.pix; + struct v4l2_mbus_framefmt mf_tmp = *mf; unsigned int scale_h, scale_v; int ret; /* 5. Apply iterative camera S_FMT for camera user window. */ - ret = client_s_fmt(icd, &f_tmp, ceu_can_scale); + ret = client_s_fmt(icd, &mf_tmp, ceu_can_scale); if (ret < 0) return ret; dev_geo(dev, "5: camera scaled to %ux%u\n", - pix_tmp->width, pix_tmp->height); + mf_tmp.width, mf_tmp.height); /* 6. Retrieve camera output window (g_fmt) */ - /* unneeded - it is already in "f_tmp" */ + /* unneeded - it is already in "mf_tmp" */ /* 7. Calculate new camera scales. */ ret = get_camera_scales(sd, rect, &scale_h, &scale_v); @@ -1185,10 +1276,11 @@ static int client_scale(struct soc_camera_device *icd, struct v4l2_rect *rect, dev_geo(dev, "7: camera scales %u:%u\n", scale_h, scale_v); - cam->cam_width = pix_tmp->width; - cam->cam_height = pix_tmp->height; - f->fmt.pix.width = pix_tmp->width; - f->fmt.pix.height = pix_tmp->height; + cam->cam_width = mf_tmp.width; + cam->cam_height = mf_tmp.height; + mf->width = mf_tmp.width; + mf->height = mf_tmp.height; + mf->colorspace = mf_tmp.colorspace; /* * 8. Calculate new CEU crop - apply camera scales to previously @@ -1252,8 +1344,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, struct v4l2_rect *cam_rect = &cam_crop.c, *ceu_rect = &cam->ceu_rect; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; - struct v4l2_format f; - struct v4l2_pix_format *pix = &f.fmt.pix; + struct v4l2_mbus_framefmt mf; unsigned int scale_comb_h, scale_comb_v, scale_ceu_h, scale_ceu_v, out_width, out_height; u32 capsr, cflcr; @@ -1302,26 +1393,25 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, * 5. Using actual input window and calculated combined scales calculate * camera target output window. */ - pix->width = scale_down(cam_rect->width, scale_comb_h); - pix->height = scale_down(cam_rect->height, scale_comb_v); + mf.width = scale_down(cam_rect->width, scale_comb_h); + mf.height = scale_down(cam_rect->height, scale_comb_v); - dev_geo(dev, "5: camera target %ux%u\n", pix->width, pix->height); + dev_geo(dev, "5: camera target %ux%u\n", mf.width, mf.height); /* 6. - 9. */ - pix->pixelformat = cam->camera_fmt->fourcc; - pix->colorspace = cam->camera_fmt->colorspace; + mf.code = cam->code; + mf.field = pcdev->field; capsr = capture_save_reset(pcdev); dev_dbg(dev, "CAPSR 0x%x, CFLCR 0x%x\n", capsr, pcdev->cflcr); /* Make relative to camera rectangle */ - rect->left -= cam_rect->left; - rect->top -= cam_rect->top; + rect->left -= cam_rect->left; + rect->top -= cam_rect->top; - f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - ret = client_scale(icd, cam_rect, rect, ceu_rect, &f, - pcdev->image_mode && !pcdev->is_interlaced); + ret = client_scale(icd, cam_rect, rect, ceu_rect, &mf, + pcdev->image_mode && + V4L2_FIELD_NONE == pcdev->field); dev_geo(dev, "6-9: %d\n", ret); @@ -1368,8 +1458,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, struct sh_mobile_ceu_dev *pcdev = ici->priv; struct sh_mobile_ceu_cam *cam = icd->host_priv; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_format cam_f = *f; - struct v4l2_pix_format *cam_pix = &cam_f.fmt.pix; + struct v4l2_mbus_framefmt mf; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->dev.parent; __u32 pixfmt = pix->pixelformat; @@ -1379,18 +1468,20 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, unsigned int scale_cam_h, scale_cam_v; u16 scale_v, scale_h; int ret; - bool is_interlaced, image_mode; + bool image_mode; + enum v4l2_field field; switch (pix->field) { - case V4L2_FIELD_INTERLACED: - is_interlaced = true; - break; - case V4L2_FIELD_ANY: default: pix->field = V4L2_FIELD_NONE; /* fall-through */ + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: case V4L2_FIELD_NONE: - is_interlaced = false; + field = pix->field; + break; + case V4L2_FIELD_INTERLACED: + field = V4L2_FIELD_INTERLACED_TB; break; } @@ -1438,9 +1529,11 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, * 4. Calculate camera output window by applying combined scales to real * input window. */ - cam_pix->width = scale_down(cam_rect->width, scale_h); - cam_pix->height = scale_down(cam_rect->height, scale_v); - cam_pix->pixelformat = xlate->cam_fmt->fourcc; + mf.width = scale_down(cam_rect->width, scale_h); + mf.height = scale_down(cam_rect->height, scale_v); + mf.field = pix->field; + mf.colorspace = pix->colorspace; + mf.code = xlate->code; switch (pixfmt) { case V4L2_PIX_FMT_NV12: @@ -1453,51 +1546,61 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, image_mode = false; } - dev_geo(dev, "4: camera output %ux%u\n", - cam_pix->width, cam_pix->height); + dev_geo(dev, "4: camera output %ux%u\n", mf.width, mf.height); /* 5. - 9. */ - ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &cam_f, - image_mode && !is_interlaced); + ret = client_scale(icd, cam_rect, &cam_subrect, &ceu_rect, &mf, + image_mode && V4L2_FIELD_NONE == field); dev_geo(dev, "5-9: client scale %d\n", ret); /* Done with the camera. Now see if we can improve the result */ dev_dbg(dev, "Camera %d fmt %ux%u, requested %ux%u\n", - ret, cam_pix->width, cam_pix->height, pix->width, pix->height); + ret, mf.width, mf.height, pix->width, pix->height); if (ret < 0) return ret; + if (mf.code != xlate->code) + return -EINVAL; + /* 10. Use CEU scaling to scale to the requested user window. */ /* We cannot scale up */ - if (pix->width > cam_pix->width) - pix->width = cam_pix->width; + if (pix->width > mf.width) + pix->width = mf.width; if (pix->width > ceu_rect.width) pix->width = ceu_rect.width; - if (pix->height > cam_pix->height) - pix->height = cam_pix->height; + if (pix->height > mf.height) + pix->height = mf.height; if (pix->height > ceu_rect.height) pix->height = ceu_rect.height; - /* Let's rock: scale pix->{width x height} down to width x height */ - scale_h = calc_scale(ceu_rect.width, &pix->width); - scale_v = calc_scale(ceu_rect.height, &pix->height); + pix->colorspace = mf.colorspace; + + if (image_mode) { + /* Scale pix->{width x height} down to width x height */ + scale_h = calc_scale(ceu_rect.width, &pix->width); + scale_v = calc_scale(ceu_rect.height, &pix->height); + + pcdev->cflcr = scale_h | (scale_v << 16); + } else { + pix->width = ceu_rect.width; + pix->height = ceu_rect.height; + scale_h = scale_v = 0; + pcdev->cflcr = 0; + } dev_geo(dev, "10: W: %u : 0x%x = %u, H: %u : 0x%x = %u\n", ceu_rect.width, scale_h, pix->width, ceu_rect.height, scale_v, pix->height); - pcdev->cflcr = scale_h | (scale_v << 16); + cam->code = xlate->code; + cam->ceu_rect = ceu_rect; + icd->current_fmt = xlate; - icd->buswidth = xlate->buswidth; - icd->current_fmt = xlate->host_fmt; - cam->camera_fmt = xlate->cam_fmt; - cam->ceu_rect = ceu_rect; - - pcdev->is_interlaced = is_interlaced; + pcdev->field = field; pcdev->image_mode = image_mode; return 0; @@ -1509,6 +1612,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_framefmt mf; __u32 pixfmt = pix->pixelformat; int width, height; int ret; @@ -1527,18 +1631,27 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, width = pix->width; height = pix->height; - pix->bytesperline = pix->width * - DIV_ROUND_UP(xlate->host_fmt->depth, 8); - pix->sizeimage = pix->height * pix->bytesperline; - - pix->pixelformat = xlate->cam_fmt->fourcc; + pix->bytesperline = soc_mbus_bytes_per_line(width, xlate->host_fmt); + if (pix->bytesperline < 0) + return pix->bytesperline; + pix->sizeimage = height * pix->bytesperline; /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_fmt, f); - pix->pixelformat = pixfmt; + mf.width = pix->width; + mf.height = pix->height; + mf.field = pix->field; + mf.code = xlate->code; + mf.colorspace = pix->colorspace; + + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); if (ret < 0) return ret; + pix->width = mf.width; + pix->height = mf.height; + pix->field = mf.field; + pix->colorspace = mf.colorspace; + switch (pixfmt) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: @@ -1547,21 +1660,25 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, /* FIXME: check against rect_max after converting soc-camera */ /* We can scale precisely, need a bigger image from camera */ if (pix->width < width || pix->height < height) { - int tmp_w = pix->width, tmp_h = pix->height; - pix->width = 2560; - pix->height = 1920; - ret = v4l2_subdev_call(sd, video, try_fmt, f); + /* + * We presume, the sensor behaves sanely, i.e., if + * requested a bigger rectangle, it will not return a + * smaller one. + */ + mf.width = 2560; + mf.height = 1920; + ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ dev_err(icd->dev.parent, - "FIXME: try_fmt() returned %d\n", ret); - pix->width = tmp_w; - pix->height = tmp_h; + "FIXME: client try_fmt() = %d\n", ret); + return ret; } } - if (pix->width > width) + /* We will scale exactly */ + if (mf.width > width) pix->width = width; - if (pix->height > height) + if (mf.height > height) pix->height = height; } @@ -1573,10 +1690,12 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf, { int i; - /* This is for locking debugging only. I removed spinlocks and now I + /* + * This is for locking debugging only. I removed spinlocks and now I * check whether .prepare is ever called on a linked buffer, or whether * a dma IRQ can occur for an in-work or unlinked buffer. Until now - * it hadn't triggered */ + * it hadn't triggered + */ for (i = 0; i < p->count; i++) { struct sh_mobile_ceu_buffer *buf; @@ -1624,8 +1743,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, &sh_mobile_ceu_videobuf_ops, icd->dev.parent, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - pcdev->is_interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, + pcdev->field, sizeof(struct sh_mobile_ceu_buffer), icd); } @@ -1654,7 +1772,7 @@ static int sh_mobile_ceu_set_ctrl(struct soc_camera_device *icd, switch (ctrl->id) { case V4L2_CID_SHARPNESS: - switch (icd->current_fmt->fourcc) { + switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV16: @@ -1709,7 +1827,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); - if (!res || !irq) { + if (!res || (int)irq <= 0) { dev_err(&pdev->dev, "Not enough CEU platform resources.\n"); err = -ENODEV; goto exit; @@ -1825,7 +1943,7 @@ static int sh_mobile_ceu_runtime_nop(struct device *dev) return 0; } -static struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { +static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { .runtime_suspend = sh_mobile_ceu_runtime_nop, .runtime_resume = sh_mobile_ceu_runtime_nop, }; @@ -1836,7 +1954,7 @@ static struct platform_driver sh_mobile_ceu_driver = { .pm = &sh_mobile_ceu_dev_pm_ops, }, .probe = sh_mobile_ceu_probe, - .remove = __exit_p(sh_mobile_ceu_remove), + .remove = __devexit_p(sh_mobile_ceu_remove), }; static int __init sh_mobile_ceu_init(void) diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c index 4a7711c3e745..cbf8087b286f 100644 --- a/drivers/media/video/sn9c102/sn9c102_core.c +++ b/drivers/media/video/sn9c102/sn9c102_core.c @@ -1007,8 +1007,8 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam) else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. " - "To use it, close and open /dev/video%d again.", - cam->v4ldev->num); + "To use it, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1734,7 +1734,8 @@ static void sn9c102_release_resources(struct kref *kref) cam = container_of(kref, struct sn9c102_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); + DBG(2, "V4L2 device %s deregistered", + video_device_node_name(cam->v4ldev)); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -1791,8 +1792,8 @@ static int sn9c102_open(struct file *filp) } if (cam->users) { - DBG(2, "Device /dev/video%d is already in use", - cam->v4ldev->num); + DBG(2, "Device %s is already in use", + video_device_node_name(cam->v4ldev)); DBG(3, "Simultaneous opens are not supported"); /* open() must follow the open flags and should block @@ -1845,7 +1846,7 @@ static int sn9c102_open(struct file *filp) cam->frame_count = 0; sn9c102_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); + DBG(3, "Video device %s is open", video_device_node_name(cam->v4ldev)); out: mutex_unlock(&cam->open_mutex); @@ -1870,7 +1871,7 @@ static int sn9c102_release(struct file *filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); + DBG(3, "Video device %s closed", video_device_node_name(cam->v4ldev)); kref_put(&cam->kref, sn9c102_release_resources); @@ -2433,8 +2434,8 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -2446,8 +2447,8 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg) nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -2690,8 +2691,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -2702,8 +2703,8 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd, nbuffers != sn9c102_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -2748,9 +2749,9 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg) err += sn9c102_set_compression(cam, &jc); if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; - DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->num); + DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware problems. " + "To use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -3328,7 +3329,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); cam->v4ldev->fops = &sn9c102_fops; - cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; cam->v4ldev->parent = &udev->dev; @@ -3346,7 +3346,8 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); + DBG(2, "V4L2 device registered as %s", + video_device_node_name(cam->v4ldev)); video_set_drvdata(cam->v4ldev, cam); cam->module_param.force_munmap = force_munmap[dev_nr]; @@ -3398,9 +3399,9 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf) DBG(2, "Disconnecting %s...", cam->v4ldev->name); if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " - "memory deallocation are deferred.", - cam->v4ldev->num); + DBG(2, "Device %s is open! Deregistration and memory " + "deallocation are deferred.", + video_device_node_name(cam->v4ldev)); cam->state |= DEV_MISCONFIGURED; sn9c102_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 95fdeb23c2c1..6b3fbcca7747 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -31,6 +31,7 @@ #include <media/v4l2-ioctl.h> #include <media/v4l2-dev.h> #include <media/videobuf-core.h> +#include <media/soc_mediabus.h> /* Default to VGA resolution */ #define DEFAULT_WIDTH 640 @@ -40,18 +41,6 @@ static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */ -const struct soc_camera_data_format *soc_camera_format_by_fourcc( - struct soc_camera_device *icd, unsigned int fourcc) -{ - unsigned int i; - - for (i = 0; i < icd->num_formats; i++) - if (icd->formats[i].fourcc == fourcc) - return icd->formats + i; - return NULL; -} -EXPORT_SYMBOL(soc_camera_format_by_fourcc); - const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc( struct soc_camera_device *icd, unsigned int fourcc) { @@ -207,21 +196,26 @@ static int soc_camera_dqbuf(struct file *file, void *priv, /* Always entered with .video_lock held */ static int soc_camera_init_user_formats(struct soc_camera_device *icd) { + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - int i, fmts = 0, ret; + int i, fmts = 0, raw_fmts = 0, ret; + enum v4l2_mbus_pixelcode code; + + while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) + raw_fmts++; if (!ici->ops->get_formats) /* * Fallback mode - the host will have to serve all * sensor-provided formats one-to-one to the user */ - fmts = icd->num_formats; + fmts = raw_fmts; else /* * First pass - only count formats this host-sensor * configuration can provide */ - for (i = 0; i < icd->num_formats; i++) { + for (i = 0; i < raw_fmts; i++) { ret = ici->ops->get_formats(icd, i, NULL); if (ret < 0) return ret; @@ -242,11 +236,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) /* Second pass - actually fill data formats */ fmts = 0; - for (i = 0; i < icd->num_formats; i++) + for (i = 0; i < raw_fmts; i++) if (!ici->ops->get_formats) { - icd->user_formats[i].host_fmt = icd->formats + i; - icd->user_formats[i].cam_fmt = icd->formats + i; - icd->user_formats[i].buswidth = icd->formats[i].depth; + v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); + icd->user_formats[i].host_fmt = + soc_mbus_get_fmtdesc(code); + icd->user_formats[i].code = code; } else { ret = ici->ops->get_formats(icd, i, &icd->user_formats[fmts]); @@ -255,7 +250,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) fmts += ret; } - icd->current_fmt = icd->user_formats[0].host_fmt; + icd->current_fmt = &icd->user_formats[0]; return 0; @@ -281,7 +276,7 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) #define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \ ((x) >> 24) & 0xff -/* Called with .vb_lock held */ +/* Called with .vb_lock held, or from the first open(2), see comment there */ static int soc_camera_set_fmt(struct soc_camera_file *icf, struct v4l2_format *f) { @@ -302,7 +297,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, if (ret < 0) { return ret; } else if (!icd->current_fmt || - icd->current_fmt->fourcc != pix->pixelformat) { + icd->current_fmt->host_fmt->fourcc != pix->pixelformat) { dev_err(&icd->dev, "Host driver hasn't set up current format correctly!\n"); return -EINVAL; @@ -310,6 +305,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, icd->user_width = pix->width; icd->user_height = pix->height; + icd->colorspace = pix->colorspace; icf->vb_vidq.field = icd->field = pix->field; @@ -369,8 +365,9 @@ static int soc_camera_open(struct file *file) .width = icd->user_width, .height = icd->user_height, .field = icd->field, - .pixelformat = icd->current_fmt->fourcc, - .colorspace = icd->current_fmt->colorspace, + .colorspace = icd->colorspace, + .pixelformat = + icd->current_fmt->host_fmt->fourcc, }, }; @@ -390,7 +387,12 @@ static int soc_camera_open(struct file *file) goto eiciadd; } - /* Try to configure with default parameters */ + /* + * Try to configure with default parameters. Notice: this is the + * very first open, so, we cannot race against other calls, + * apart from someone else calling open() simultaneously, but + * .video_lock is protecting us against it. + */ ret = soc_camera_set_fmt(icf, &f); if (ret < 0) goto esfmt; @@ -534,7 +536,7 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - const struct soc_camera_data_format *format; + const struct soc_mbus_pixelfmt *format; WARN_ON(priv != file->private_data); @@ -543,7 +545,8 @@ static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv, format = icd->user_formats[f->index].host_fmt; - strlcpy(f->description, format->name, sizeof(f->description)); + if (format->name) + strlcpy(f->description, format->name, sizeof(f->description)); f->pixelformat = format->fourcc; return 0; } @@ -560,12 +563,15 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv, pix->width = icd->user_width; pix->height = icd->user_height; pix->field = icf->vb_vidq.field; - pix->pixelformat = icd->current_fmt->fourcc; - pix->bytesperline = pix->width * - DIV_ROUND_UP(icd->current_fmt->depth, 8); + pix->pixelformat = icd->current_fmt->host_fmt->fourcc; + pix->bytesperline = soc_mbus_bytes_per_line(pix->width, + icd->current_fmt->host_fmt); + pix->colorspace = icd->colorspace; + if (pix->bytesperline < 0) + return pix->bytesperline; pix->sizeimage = pix->height * pix->bytesperline; dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", - icd->current_fmt->fourcc); + icd->current_fmt->host_fmt->fourcc); return 0; } @@ -621,8 +627,10 @@ static int soc_camera_streamoff(struct file *file, void *priv, mutex_lock(&icd->video_lock); - /* This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop capture */ + /* + * This calls buf_release from host driver's videobuf_queue_ops for all + * remaining buffers. When the last buffer is freed, stop capture + */ videobuf_streamoff(&icf->vb_vidq); v4l2_subdev_call(sd, video, s_stream, 0); @@ -892,7 +900,7 @@ static int soc_camera_probe(struct device *dev) struct soc_camera_link *icl = to_soc_camera_link(icd); struct device *control = NULL; struct v4l2_subdev *sd; - struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE}; + struct v4l2_mbus_framefmt mf; int ret; dev_info(dev, "Probing %s\n", dev_name(dev)); @@ -963,9 +971,11 @@ static int soc_camera_probe(struct device *dev) /* Try to improve our guess of a reasonable window format */ sd = soc_camera_to_subdev(icd); - if (!v4l2_subdev_call(sd, video, g_fmt, &f)) { - icd->user_width = f.fmt.pix.width; - icd->user_height = f.fmt.pix.height; + if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { + icd->user_width = mf.width; + icd->user_height = mf.height; + icd->colorspace = mf.colorspace; + icd->field = mf.field; } /* Do we have to sysfs_remove_link() before device_unregister()? */ @@ -1004,8 +1014,10 @@ epower: return ret; } -/* This is called on device_unregister, which only means we have to disconnect - * from the host, but not remove ourselves from the device list */ +/* + * This is called on device_unregister, which only means we have to disconnect + * from the host, but not remove ourselves from the device list + */ static int soc_camera_remove(struct device *dev) { struct soc_camera_device *icd = to_soc_camera_dev(dev); @@ -1205,8 +1217,10 @@ static int soc_camera_device_register(struct soc_camera_device *icd) } if (num < 0) - /* ok, we have 256 cameras on this host... - * man, stay reasonable... */ + /* + * ok, we have 256 cameras on this host... + * man, stay reasonable... + */ return -ENOMEM; icd->devnum = num; @@ -1268,7 +1282,6 @@ static int video_dev_create(struct soc_camera_device *icd) vdev->fops = &soc_camera_fops; vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; - vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN; icd->vdev = vdev; @@ -1291,8 +1304,7 @@ static int soc_camera_video_start(struct soc_camera_device *icd) !icd->ops->set_bus_param) return -EINVAL; - ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, - icd->vdev->minor); + ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { dev_err(&icd->dev, "video_register_device failed: %d\n", ret); return ret; @@ -1335,9 +1347,11 @@ escdevreg: return ret; } -/* Only called on rmmod for each platform device, since they are not +/* + * Only called on rmmod for each platform device, since they are not * hot-pluggable. Now we know, that all our users - hosts and devices have - * been unloaded already */ + * been unloaded already + */ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) { struct soc_camera_device *icd = platform_get_drvdata(pdev); diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c index b6a575ce5da2..10b003a8be83 100644 --- a/drivers/media/video/soc_camera_platform.c +++ b/drivers/media/video/soc_camera_platform.c @@ -22,7 +22,6 @@ struct soc_camera_platform_priv { struct v4l2_subdev subdev; - struct soc_camera_data_format format; }; static struct soc_camera_platform_priv *get_priv(struct platform_device *pdev) @@ -58,36 +57,36 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd) } static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd, - struct v4l2_format *f) + struct v4l2_mbus_framefmt *mf) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - struct v4l2_pix_format *pix = &f->fmt.pix; - pix->width = p->format.width; - pix->height = p->format.height; + mf->width = p->format.width; + mf->height = p->format.height; + mf->code = p->format.code; + mf->colorspace = p->format.colorspace; + return 0; } -static void soc_camera_platform_video_probe(struct soc_camera_device *icd, - struct platform_device *pdev) +static struct v4l2_subdev_core_ops platform_subdev_core_ops; + +static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) { - struct soc_camera_platform_priv *priv = get_priv(pdev); - struct soc_camera_platform_info *p = pdev->dev.platform_data; + struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - priv->format.name = p->format_name; - priv->format.depth = p->format_depth; - priv->format.fourcc = p->format.pixelformat; - priv->format.colorspace = p->format.colorspace; + if (index) + return -EINVAL; - icd->formats = &priv->format; - icd->num_formats = 1; + *code = p->format.code; + return 0; } -static struct v4l2_subdev_core_ops platform_subdev_core_ops; - static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .s_stream = soc_camera_platform_s_stream, - .try_fmt = soc_camera_platform_try_fmt, + .try_mbus_fmt = soc_camera_platform_try_fmt, + .enum_mbus_fmt = soc_camera_platform_enum_fmt, }; static struct v4l2_subdev_ops platform_subdev_ops = { @@ -128,13 +127,10 @@ static int soc_camera_platform_probe(struct platform_device *pdev) /* Set the control device reference */ dev_set_drvdata(&icd->dev, &pdev->dev); - icd->y_skip_top = 0; - icd->ops = &soc_camera_platform_ops; + icd->ops = &soc_camera_platform_ops; ici = to_soc_camera_host(icd->dev.parent); - soc_camera_platform_video_probe(icd, pdev); - v4l2_subdev_init(&priv->subdev, &platform_subdev_ops); v4l2_set_subdevdata(&priv->subdev, p); strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE); diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c new file mode 100644 index 000000000000..f8d5c87dc2aa --- /dev/null +++ b/drivers/media/video/soc_mediabus.c @@ -0,0 +1,157 @@ +/* + * soc-camera media bus helper routines + * + * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include <media/v4l2-device.h> +#include <media/v4l2-mediabus.h> +#include <media/soc_mediabus.h> + +#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1) + +static const struct soc_mbus_pixelfmt mbus_fmt[] = { + [MBUS_IDX(YUYV8_2X8_LE)] = { + .fourcc = V4L2_PIX_FMT_YUYV, + .name = "YUYV", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(YVYU8_2X8_LE)] = { + .fourcc = V4L2_PIX_FMT_YVYU, + .name = "YVYU", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(YUYV8_2X8_BE)] = { + .fourcc = V4L2_PIX_FMT_UYVY, + .name = "UYVY", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(YVYU8_2X8_BE)] = { + .fourcc = V4L2_PIX_FMT_VYUY, + .name = "VYUY", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(RGB555_2X8_PADHI_LE)] = { + .fourcc = V4L2_PIX_FMT_RGB555, + .name = "RGB555", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(RGB555_2X8_PADHI_BE)] = { + .fourcc = V4L2_PIX_FMT_RGB555X, + .name = "RGB555X", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(RGB565_2X8_LE)] = { + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(RGB565_2X8_BE)] = { + .fourcc = V4L2_PIX_FMT_RGB565X, + .name = "RGB565X", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(SBGGR8_1X8)] = { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .name = "Bayer 8 BGGR", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(SBGGR10_1X10)] = { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .name = "Bayer 10 BGGR", + .bits_per_sample = 10, + .packing = SOC_MBUS_PACKING_EXTEND16, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(GREY8_1X8)] = { + .fourcc = V4L2_PIX_FMT_GREY, + .name = "Grey", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_NONE, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(Y10_1X10)] = { + .fourcc = V4L2_PIX_FMT_Y10, + .name = "Grey 10bit", + .bits_per_sample = 10, + .packing = SOC_MBUS_PACKING_EXTEND16, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .name = "Bayer 10 BGGR", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .name = "Bayer 10 BGGR", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADLO, + .order = SOC_MBUS_ORDER_LE, + }, [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .name = "Bayer 10 BGGR", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_BE, + }, [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .name = "Bayer 10 BGGR", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADLO, + .order = SOC_MBUS_ORDER_BE, + }, +}; + +s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) +{ + switch (mf->packing) { + case SOC_MBUS_PACKING_NONE: + return width * mf->bits_per_sample / 8; + case SOC_MBUS_PACKING_2X8_PADHI: + case SOC_MBUS_PACKING_2X8_PADLO: + case SOC_MBUS_PACKING_EXTEND16: + return width * 2; + } + return -EINVAL; +} +EXPORT_SYMBOL(soc_mbus_bytes_per_line); + +const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc( + enum v4l2_mbus_pixelcode code) +{ + if ((unsigned int)(code - V4L2_MBUS_FMT_FIXED) > ARRAY_SIZE(mbus_fmt)) + return NULL; + return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1; +} +EXPORT_SYMBOL(soc_mbus_get_fmtdesc); + +static int __init soc_mbus_init(void) +{ + return 0; +} + +static void __exit soc_mbus_exit(void) +{ +} + +module_init(soc_mbus_init); +module_exit(soc_mbus_exit); + +MODULE_DESCRIPTION("soc-camera media bus interface"); +MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index 6b41865f42bd..f07a0f6b71c4 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -1307,7 +1307,6 @@ static void stk_v4l_dev_release(struct video_device *vd) static struct video_device stk_v4l_data = { .name = "stkwebcam", - .minor = -1, .tvnorms = V4L2_STD_UNKNOWN, .current_norm = V4L2_STD_UNKNOWN, .fops = &v4l_stk_fops, @@ -1327,8 +1326,8 @@ static int stk_register_video_device(struct stk_camera *dev) if (err) STK_ERROR("v4l registration failed\n"); else - STK_INFO("Syntek USB2.0 Camera is now controlling video device" - " /dev/video%d\n", dev->vdev.num); + STK_INFO("Syntek USB2.0 Camera is now controlling device %s\n", + video_device_node_name(&dev->vdev)); return err; } @@ -1418,8 +1417,8 @@ static void stk_camera_disconnect(struct usb_interface *interface) wake_up_interruptible(&dev->wait_frame); stk_remove_sysfs_files(&dev->vdev); - STK_INFO("Syntek USB2.0 Camera release resources " - "video device /dev/video%d\n", dev->vdev.num); + STK_INFO("Syntek USB2.0 Camera release resources device %s\n", + video_device_node_name(&dev->vdev)); video_unregister_device(&dev->vdev); } diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c index eaada39c76fd..a057824e7ebc 100644 --- a/drivers/media/video/stradis.c +++ b/drivers/media/video/stradis.c @@ -1921,7 +1921,6 @@ static const struct v4l2_file_operations saa_fops = { static struct video_device saa_template = { .name = "SAA7146A", .fops = &saa_fops, - .minor = -1, .release = video_device_release_empty, }; @@ -1972,7 +1971,6 @@ static int __devinit configure_saa7146(struct pci_dev *pdev, int num) saa->id = pdev->device; saa->irq = pdev->irq; - saa->video_dev.minor = -1; saa->saa7146_adr = pci_resource_start(pdev, 0); pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision); @@ -2134,7 +2132,7 @@ static void stradis_release_saa(struct pci_dev *pdev) free_irq(saa->irq, saa); if (saa->saa7146_mem) iounmap(saa->saa7146_mem); - if (saa->video_dev.minor != -1) + if (video_is_registered(&saa->video_dev)) video_unregister_device(&saa->video_dev); } diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c index 6a91714125d2..5938ad8702ef 100644 --- a/drivers/media/video/stv680.c +++ b/drivers/media/video/stv680.c @@ -1405,7 +1405,6 @@ static struct video_device stv680_template = { .name = "STV0680 USB camera", .fops = &stv680_fops, .release = video_device_release, - .minor = -1, }; static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id) @@ -1467,8 +1466,8 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id retval = -EIO; goto error_vdev; } - PDEBUG(0, "STV(i): registered new video device: video%d", - stv680->vdev->num); + PDEBUG(0, "STV(i): registered new video device: %s", + video_device_node_name(stv680->vdev)); usb_set_intfdata (intf, stv680); retval = stv680_create_sysfs_files(stv680->vdev); diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c index 269ab044072a..5b801a6e1eea 100644 --- a/drivers/media/video/tw9910.c +++ b/drivers/media/video/tw9910.c @@ -29,7 +29,7 @@ #include <media/tw9910.h> #define GET_ID(val) ((val & 0xF8) >> 3) -#define GET_ReV(val) (val & 0x07) +#define GET_REV(val) (val & 0x07) /* * register offset @@ -117,7 +117,7 @@ #define LCTL24 0x68 #define LCTL25 0x69 #define LCTL26 0x6A -#define HSGEGIN 0x6B +#define HSBEGIN 0x6B #define HSEND 0x6C #define OVSDLY 0x6D #define OVSEND 0x6E @@ -152,7 +152,10 @@ /* 1 : non-auto */ #define VSCTL 0x08 /* 1 : Vertical out ctrl by DVALID */ /* 0 : Vertical out ctrl by HACTIVE and DVALID */ -#define OEN 0x04 /* Output Enable together with TRI_SEL. */ +#define OEN_TRI_SEL_MASK 0x07 +#define OEN_TRI_SEL_ALL_ON 0x00 /* Enable output for Rev0/Rev1 */ +#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */ +#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */ /* OUTCTR1 */ #define VSP_LO 0x00 /* 0 : VS pin output polarity is active low */ @@ -178,11 +181,18 @@ * but all register content remain unchanged. * This bit is self-resetting. */ +#define ACNTL1_PDN_MASK 0x0e +#define CLK_PDN 0x08 /* system clock power down */ +#define Y_PDN 0x04 /* Luma ADC power down */ +#define C_PDN 0x02 /* Chroma ADC power down */ + +/* ACNTL2 */ +#define ACNTL2_PDN_MASK 0x40 +#define PLL_PDN 0x40 /* PLL power down */ /* VBICNTL */ -/* RTSEL : control the real time signal -* output from the MPOUT pin -*/ + +/* RTSEL : control the real time signal output from the MPOUT pin */ #define RTSEL_MASK 0x07 #define RTSEL_VLOSS 0x00 /* 0000 = Video loss */ #define RTSEL_HLOCK 0x01 /* 0001 = H-lock */ @@ -226,28 +236,7 @@ struct tw9910_priv { struct v4l2_subdev subdev; struct tw9910_video_info *info; const struct tw9910_scale_ctrl *scale; -}; - -/* - * register settings - */ - -#define ENDMARKER { 0xff, 0xff } - -static const struct regval_list tw9910_default_regs[] = -{ - { OPFORM, 0x00 }, - { OUTCTR1, VSP_LO | VSSL_VVALID | HSP_HI | HSSL_HSYNC }, - ENDMARKER, -}; - -static const struct soc_camera_data_format tw9910_color_fmt[] = { - { - .name = "VYUY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = 16, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - } + u32 revision; }; static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = { @@ -340,13 +329,6 @@ static const struct tw9910_scale_ctrl tw9910_pal_scales[] = { }, }; -static const struct tw9910_cropping_ctrl tw9910_cropping_ctrl = { - .vdelay = 0x0012, - .vactive = 0x00F0, - .hdelay = 0x0010, - .hactive = 0x02D0, -}; - static const struct tw9910_hsync_ctrl tw9910_hsync_ctrl = { .start = 0x0260, .end = 0x0300, @@ -361,6 +343,19 @@ static struct tw9910_priv *to_tw9910(const struct i2c_client *client) subdev); } +static int tw9910_mask_set(struct i2c_client *client, u8 command, + u8 mask, u8 set) +{ + s32 val = i2c_smbus_read_byte_data(client, command); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + return i2c_smbus_write_byte_data(client, command, val); +} + static int tw9910_set_scale(struct i2c_client *client, const struct tw9910_scale_ctrl *scale) { @@ -383,47 +378,14 @@ static int tw9910_set_scale(struct i2c_client *client, return ret; } -static int tw9910_set_cropping(struct i2c_client *client, - const struct tw9910_cropping_ctrl *cropping) -{ - int ret; - - ret = i2c_smbus_write_byte_data(client, CROP_HI, - (cropping->vdelay & 0x0300) >> 2 | - (cropping->vactive & 0x0300) >> 4 | - (cropping->hdelay & 0x0300) >> 6 | - (cropping->hactive & 0x0300) >> 8); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, VDELAY_LO, - cropping->vdelay & 0x00FF); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, VACTIVE_LO, - cropping->vactive & 0x00FF); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, HDELAY_LO, - cropping->hdelay & 0x00FF); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, HACTIVE_LO, - cropping->hactive & 0x00FF); - - return ret; -} - static int tw9910_set_hsync(struct i2c_client *client, const struct tw9910_hsync_ctrl *hsync) { + struct tw9910_priv *priv = to_tw9910(client); int ret; /* bit 10 - 3 */ - ret = i2c_smbus_write_byte_data(client, HSGEGIN, + ret = i2c_smbus_write_byte_data(client, HSBEGIN, (hsync->start & 0x07F8) >> 3); if (ret < 0) return ret; @@ -434,50 +396,41 @@ static int tw9910_set_hsync(struct i2c_client *client, if (ret < 0) return ret; + /* So far only revisions 0 and 1 have been seen */ /* bit 2 - 0 */ - ret = i2c_smbus_read_byte_data(client, HSLOWCTL); - if (ret < 0) - return ret; - - ret = i2c_smbus_write_byte_data(client, HSLOWCTL, - (ret & 0x88) | - (hsync->start & 0x0007) << 4 | - (hsync->end & 0x0007)); + if (1 == priv->revision) + ret = tw9910_mask_set(client, HSLOWCTL, 0x77, + (hsync->start & 0x0007) << 4 | + (hsync->end & 0x0007)); return ret; } -static int tw9910_write_array(struct i2c_client *client, - const struct regval_list *vals) +static void tw9910_reset(struct i2c_client *client) { - while (vals->reg_num != 0xff) { - int ret = i2c_smbus_write_byte_data(client, - vals->reg_num, - vals->value); - if (ret < 0) - return ret; - vals++; - } - return 0; + tw9910_mask_set(client, ACNTL1, SRESET, SRESET); + msleep(1); } -static int tw9910_mask_set(struct i2c_client *client, u8 command, - u8 mask, u8 set) +static int tw9910_power(struct i2c_client *client, int enable) { - s32 val = i2c_smbus_read_byte_data(client, command); - if (val < 0) - return val; + int ret; + u8 acntl1; + u8 acntl2; - val &= ~mask; - val |= set & mask; + if (enable) { + acntl1 = 0; + acntl2 = 0; + } else { + acntl1 = CLK_PDN | Y_PDN | C_PDN; + acntl2 = PLL_PDN; + } - return i2c_smbus_write_byte_data(client, command, val); -} + ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1); + if (ret < 0) + return ret; -static void tw9910_reset(struct i2c_client *client) -{ - i2c_smbus_write_byte_data(client, ACNTL1, SRESET); - msleep(1); + return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2); } static const struct tw9910_scale_ctrl* @@ -518,27 +471,62 @@ static int tw9910_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = sd->priv; struct tw9910_priv *priv = to_tw9910(client); + u8 val; + int ret; - if (!enable) - return 0; + if (!enable) { + switch (priv->revision) { + case 0: + val = OEN_TRI_SEL_ALL_OFF_r0; + break; + case 1: + val = OEN_TRI_SEL_ALL_OFF_r1; + break; + default: + dev_err(&client->dev, "un-supported revision\n"); + return -EINVAL; + } + } else { + val = OEN_TRI_SEL_ALL_ON; - if (!priv->scale) { - dev_err(&client->dev, "norm select error\n"); - return -EPERM; + if (!priv->scale) { + dev_err(&client->dev, "norm select error\n"); + return -EPERM; + } + + dev_dbg(&client->dev, "%s %dx%d\n", + priv->scale->name, + priv->scale->width, + priv->scale->height); } - dev_dbg(&client->dev, "%s %dx%d\n", - priv->scale->name, - priv->scale->width, - priv->scale->height); + ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val); + if (ret < 0) + return ret; - return 0; + return tw9910_power(client, enable); } static int tw9910_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { - return 0; + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct i2c_client *client = sd->priv; + u8 val = VSSL_VVALID | HSSL_DVALID; + + /* + * set OUTCTR1 + * + * We use VVALID and DVALID signals to control VSYNC and HSYNC + * outputs, in this mode their polarity is inverted. + */ + if (flags & SOCAM_HSYNC_ACTIVE_LOW) + val |= HSP_HI; + + if (flags & SOCAM_VSYNC_ACTIVE_LOW) + val |= VSP_HI; + + return i2c_smbus_write_byte_data(client, OUTCTR1, val); } static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) @@ -548,6 +536,7 @@ static unsigned long tw9910_query_bus_param(struct soc_camera_device *icd) struct soc_camera_link *icl = to_soc_camera_link(icd); unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | + SOCAM_VSYNC_ACTIVE_LOW | SOCAM_HSYNC_ACTIVE_LOW | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; return soc_camera_apply_sensor_flags(icl, flags); @@ -576,8 +565,11 @@ static int tw9910_enum_input(struct soc_camera_device *icd, static int tw9910_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *id) { + struct i2c_client *client = sd->priv; + struct tw9910_priv *priv = to_tw9910(client); + id->ident = V4L2_IDENT_TW9910; - id->revision = 0; + id->revision = priv->revision; return 0; } @@ -596,7 +588,8 @@ static int tw9910_g_register(struct v4l2_subdev *sd, if (ret < 0) return ret; - /* ret = int + /* + * ret = int * reg->val = __u64 */ reg->val = (__u64)ret; @@ -637,9 +630,6 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) * reset hardware */ tw9910_reset(client); - ret = tw9910_write_array(client, tw9910_default_regs); - if (ret < 0) - goto tw9910_set_fmt_error; /* * set bus width @@ -688,13 +678,6 @@ static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) goto tw9910_set_fmt_error; /* - * set cropping - */ - ret = tw9910_set_cropping(client, &tw9910_cropping_ctrl); - if (ret < 0) - goto tw9910_set_fmt_error; - - /* * set hsync */ ret = tw9910_set_hsync(client, &tw9910_hsync_ctrl); @@ -762,11 +745,11 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int tw9910_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct tw9910_priv *priv = to_tw9910(client); - struct v4l2_pix_format *pix = &f->fmt.pix; if (!priv->scale) { int ret; @@ -783,74 +766,76 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) return ret; } - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - pix->width = priv->scale->width; - pix->height = priv->scale->height; - pix->pixelformat = V4L2_PIX_FMT_VYUY; - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->field = V4L2_FIELD_INTERLACED; + mf->width = priv->scale->width; + mf->height = priv->scale->height; + mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; + mf->colorspace = V4L2_COLORSPACE_JPEG; + mf->field = V4L2_FIELD_INTERLACED_BT; return 0; } -static int tw9910_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int tw9910_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct tw9910_priv *priv = to_tw9910(client); - struct v4l2_pix_format *pix = &f->fmt.pix; /* See tw9910_s_crop() - no proper cropping support */ struct v4l2_crop a = { .c = { .left = 0, .top = 0, - .width = pix->width, - .height = pix->height, + .width = mf->width, + .height = mf->height, }, }; - int i, ret; + int ret; + + WARN_ON(mf->field != V4L2_FIELD_ANY && + mf->field != V4L2_FIELD_INTERLACED_BT); /* * check color format */ - for (i = 0; i < ARRAY_SIZE(tw9910_color_fmt); i++) - if (pix->pixelformat == tw9910_color_fmt[i].fourcc) - break; - - if (i == ARRAY_SIZE(tw9910_color_fmt)) + if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE) return -EINVAL; + mf->colorspace = V4L2_COLORSPACE_JPEG; + ret = tw9910_s_crop(sd, &a); if (!ret) { - pix->width = priv->scale->width; - pix->height = priv->scale->height; + mf->width = priv->scale->width; + mf->height = priv->scale->height; } return ret; } -static int tw9910_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) +static int tw9910_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = sd->priv; struct soc_camera_device *icd = client->dev.platform_data; - struct v4l2_pix_format *pix = &f->fmt.pix; const struct tw9910_scale_ctrl *scale; - if (V4L2_FIELD_ANY == pix->field) { - pix->field = V4L2_FIELD_INTERLACED; - } else if (V4L2_FIELD_INTERLACED != pix->field) { - dev_err(&client->dev, "Field type invalid.\n"); + if (V4L2_FIELD_ANY == mf->field) { + mf->field = V4L2_FIELD_INTERLACED_BT; + } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { + dev_err(&client->dev, "Field type %d invalid.\n", mf->field); return -EINVAL; } + mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE; + mf->colorspace = V4L2_COLORSPACE_JPEG; + /* * select suitable norm */ - scale = tw9910_select_norm(icd, pix->width, pix->height); + scale = tw9910_select_norm(icd, mf->width, mf->height); if (!scale) return -EINVAL; - pix->width = scale->width; - pix->height = scale->height; + mf->width = scale->width; + mf->height = scale->height; return 0; } @@ -859,7 +844,7 @@ static int tw9910_video_probe(struct soc_camera_device *icd, struct i2c_client *client) { struct tw9910_priv *priv = to_tw9910(client); - s32 val; + s32 id; /* * We must have a parent by now. And it cannot be a wrong one. @@ -878,23 +863,24 @@ static int tw9910_video_probe(struct soc_camera_device *icd, return -ENODEV; } - icd->formats = tw9910_color_fmt; - icd->num_formats = ARRAY_SIZE(tw9910_color_fmt); - /* * check and show Product ID + * So far only revisions 0 and 1 have been seen */ - val = i2c_smbus_read_byte_data(client, ID); + id = i2c_smbus_read_byte_data(client, ID); + priv->revision = GET_REV(id); + id = GET_ID(id); - if (0x0B != GET_ID(val) || - 0x00 != GET_ReV(val)) { + if (0x0B != id || + 0x01 < priv->revision) { dev_err(&client->dev, - "Product ID error %x:%x\n", GET_ID(val), GET_ReV(val)); + "Product ID error %x:%x\n", + id, priv->revision); return -ENODEV; } dev_info(&client->dev, - "tw9910 Product ID %0x:%0x\n", GET_ID(val), GET_ReV(val)); + "tw9910 Product ID %0x:%0x\n", id, priv->revision); icd->vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL; icd->vdev->current_norm = V4L2_STD_NTSC; @@ -917,14 +903,25 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { #endif }; +static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index) + return -EINVAL; + + *code = V4L2_MBUS_FMT_YUYV8_2X8_BE; + return 0; +} + static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_stream = tw9910_s_stream, - .g_fmt = tw9910_g_fmt, - .s_fmt = tw9910_s_fmt, - .try_fmt = tw9910_try_fmt, + .g_mbus_fmt = tw9910_g_fmt, + .s_mbus_fmt = tw9910_s_fmt, + .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, .s_crop = tw9910_s_crop, + .enum_mbus_fmt = tw9910_enum_fmt, }; static struct v4l2_subdev_ops tw9910_subdev_ops = { @@ -954,10 +951,10 @@ static int tw9910_probe(struct i2c_client *client, } icl = to_soc_camera_link(icd); - if (!icl) + if (!icl || !icl->priv) return -EINVAL; - info = container_of(icl, struct tw9910_video_info, link); + info = icl->priv; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, @@ -975,7 +972,7 @@ static int tw9910_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops); icd->ops = &tw9910_ops; - icd->iface = info->link.bus_id; + icd->iface = icl->bus_id; ret = tw9910_video_probe(icd, client); if (ret) { diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c index dea8b321fb4a..5ac37c6c4313 100644 --- a/drivers/media/video/usbvideo/usbvideo.c +++ b/drivers/media/video/usbvideo/usbvideo.c @@ -1053,9 +1053,9 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) "%s: video_register_device() successful\n", __func__); } - dev_info(&uvd->dev->dev, "%s on /dev/video%d: canvas=%s videosize=%s\n", + dev_info(&uvd->dev->dev, "%s on %s: canvas=%s videosize=%s\n", (uvd->handle != NULL) ? uvd->handle->drvName : "???", - uvd->vdev.num, tmp2, tmp1); + video_device_node_name(&uvd->vdev), tmp2, tmp1); usb_get_dev(uvd->dev); return 0; diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 45fce39ec9ad..6030410c6677 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -796,7 +796,6 @@ static const struct v4l2_file_operations vicam_fops = { static struct video_device vicam_template = { .name = "ViCam-based USB Camera", .fops = &vicam_fops, - .minor = -1, .release = video_device_release_empty, }; @@ -873,8 +872,8 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) return -EIO; } - printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n", - cam->vdev.num); + printk(KERN_INFO "ViCam webcam driver now controlling device %s\n", + video_device_node_name(&cam->vdev)); usb_set_intfdata (intf, cam); diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c index c19f51dba2ee..0613922997e0 100644 --- a/drivers/media/video/usbvision/usbvision-i2c.c +++ b/drivers/media/video/usbvision/usbvision-i2c.c @@ -215,8 +215,8 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision) memcpy(&usbvision->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); - sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name), - " #%d", usbvision->vdev->num); + sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name, + usbvision->dev->bus->busnum, usbvision->dev->devpath); PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name); usbvision->i2c_adap.dev.parent = &usbvision->dev->dev; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index c07b0ac452ab..1054546db908 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -1328,7 +1328,6 @@ static struct video_device usbvision_video_template = { .ioctl_ops = &usbvision_ioctl_ops, .name = "usbvision-video", .release = video_device_release, - .minor = -1, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL }; @@ -1362,7 +1361,6 @@ static struct video_device usbvision_radio_template = { .fops = &usbvision_radio_fops, .name = "usbvision-radio", .release = video_device_release, - .minor = -1, .ioctl_ops = &usbvision_radio_ioctl_ops, .tvnorms = USBVISION_NORMS, @@ -1382,7 +1380,6 @@ static struct video_device usbvision_vbi_template= .fops = &usbvision_vbi_fops, .release = video_device_release, .name = "usbvision-vbi", - .minor = -1, }; @@ -1404,7 +1401,6 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision, return NULL; } *vdev = *vdev_template; -// vdev->minor = -1; vdev->v4l2_dev = &usbvision->v4l2_dev; snprintf(vdev->name, sizeof(vdev->name), "%s", name); video_set_drvdata(vdev, usbvision); @@ -1416,9 +1412,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) { // vbi Device: if (usbvision->vbi) { - PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", - usbvision->vbi->num); - if (usbvision->vbi->minor != -1) { + PDEBUG(DBG_PROBE, "unregister %s [v4l2]", + video_device_node_name(usbvision->vbi)); + if (video_is_registered(usbvision->vbi)) { video_unregister_device(usbvision->vbi); } else { video_device_release(usbvision->vbi); @@ -1428,9 +1424,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Radio Device: if (usbvision->rdev) { - PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", - usbvision->rdev->num); - if (usbvision->rdev->minor != -1) { + PDEBUG(DBG_PROBE, "unregister %s [v4l2]", + video_device_node_name(usbvision->rdev)); + if (video_is_registered(usbvision->rdev)) { video_unregister_device(usbvision->rdev); } else { video_device_release(usbvision->rdev); @@ -1440,9 +1436,9 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) // Video Device: if (usbvision->vdev) { - PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", - usbvision->vdev->num); - if (usbvision->vdev->minor != -1) { + PDEBUG(DBG_PROBE, "unregister %s [v4l2]", + video_device_node_name(usbvision->vdev)); + if (video_is_registered(usbvision->vdev)) { video_unregister_device(usbvision->vdev); } else { video_device_release(usbvision->vdev); @@ -1466,8 +1462,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) video_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", - usbvision->nr, usbvision->vdev->num); + printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", + usbvision->nr, video_device_node_name(usbvision->vdev)); // Radio Device: if (usbvision_device_data[usbvision->DevModel].Radio) { @@ -1483,8 +1479,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) radio_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", - usbvision->nr, usbvision->rdev->num); + printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", + usbvision->nr, video_device_node_name(usbvision->rdev)); } // vbi Device: if (usbvision_device_data[usbvision->DevModel].vbi) { @@ -1499,8 +1495,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision) vbi_nr)<0) { goto err_exit; } - printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", - usbvision->nr, usbvision->vbi->num); + printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device %s [v4l2] (Not Working Yet!)\n", + usbvision->nr, video_device_node_name(usbvision->vbi)); } // all done return 0; diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 0469d7a876a8..ec8ef8c5560a 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -1393,7 +1393,7 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity) size = entity->processing.bControlSize; for (i = 0; i < ARRAY_SIZE(blacklist); ++i) { - if (!usb_match_id(dev->intf, &blacklist[i].id)) + if (!usb_match_one_id(dev->intf, &blacklist[i].id)) continue; if (blacklist[i].index >= 8 * size || diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index c31bc50113bc..391cccca7ffc 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1651,7 +1651,6 @@ static int uvc_register_video(struct uvc_device *dev, * get another one. */ vdev->parent = &dev->intf->dev; - vdev->minor = -1; vdev->fops = &uvc_fops; vdev->release = uvc_release; strlcpy(vdev->name, dev->name, sizeof vdev->name); diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index f854698c4061..ea11839cba4a 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -59,9 +59,9 @@ * returns immediately. * * When the buffer is full, the completion handler removes it from the irq - * queue, marks it as ready (UVC_BUF_STATE_DONE) and wakes its wait queue. + * queue, marks it as done (UVC_BUF_STATE_DONE) and wakes its wait queue. * At that point, any process waiting on the buffer will be woken up. If a - * process tries to dequeue a buffer after it has been marked ready, the + * process tries to dequeue a buffer after it has been marked done, the * dequeing will succeed immediately. * * 2. Buffers are queued, user is waiting on a buffer and the device gets @@ -201,6 +201,7 @@ static void __uvc_query_buffer(struct uvc_buffer *buf, break; case UVC_BUF_STATE_QUEUED: case UVC_BUF_STATE_ACTIVE: + case UVC_BUF_STATE_READY: v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED; break; case UVC_BUF_STATE_IDLE: @@ -295,13 +296,15 @@ static int uvc_queue_waiton(struct uvc_buffer *buf, int nonblocking) { if (nonblocking) { return (buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE) + buf->state != UVC_BUF_STATE_ACTIVE && + buf->state != UVC_BUF_STATE_READY) ? 0 : -EAGAIN; } return wait_event_interruptible(buf->wait, buf->state != UVC_BUF_STATE_QUEUED && - buf->state != UVC_BUF_STATE_ACTIVE); + buf->state != UVC_BUF_STATE_ACTIVE && + buf->state != UVC_BUF_STATE_READY); } /* @@ -348,6 +351,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue, case UVC_BUF_STATE_IDLE: case UVC_BUF_STATE_QUEUED: case UVC_BUF_STATE_ACTIVE: + case UVC_BUF_STATE_READY: default: uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state %u " "(driver bug?).\n", buf->state); @@ -489,6 +493,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); + buf->state = UVC_BUF_STATE_DONE; if (!list_empty(&queue->irqqueue)) nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 05139a4f14f6..7dcf534a0cf3 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -145,7 +145,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non " "compliance - GET_MIN/MAX(PROBE) incorrectly " "supported. Enabling workaround.\n"); - memset(ctrl, 0, sizeof ctrl); + memset(ctrl, 0, sizeof *ctrl); ctrl->wCompQuality = le16_to_cpup((__le16 *)data); ret = 0; goto out; @@ -441,7 +441,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, if (fid != stream->last_fid && buf->buf.bytesused != 0) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit " "toggled).\n"); - buf->state = UVC_BUF_STATE_DONE; + buf->state = UVC_BUF_STATE_READY; return -EAGAIN; } @@ -470,7 +470,7 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, /* Complete the current frame if the buffer size was exceeded. */ if (len > maxlen) { uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n"); - buf->state = UVC_BUF_STATE_DONE; + buf->state = UVC_BUF_STATE_READY; } } @@ -482,7 +482,7 @@ static void uvc_video_decode_end(struct uvc_streaming *stream, uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); if (data[0] == len) uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n"); - buf->state = UVC_BUF_STATE_DONE; + buf->state = UVC_BUF_STATE_READY; if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) stream->last_fid ^= UVC_STREAM_FID; } @@ -568,8 +568,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, uvc_video_decode_end(stream, buf, mem, urb->iso_frame_desc[i].actual_length); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) + if (buf->state == UVC_BUF_STATE_READY) buf = uvc_queue_next_buffer(&stream->queue, buf); } } @@ -627,8 +626,7 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, if (!stream->bulk.skip_payload && buf != NULL) { uvc_video_decode_end(stream, buf, stream->bulk.header, stream->bulk.payload_size); - if (buf->state == UVC_BUF_STATE_DONE || - buf->state == UVC_BUF_STATE_ERROR) + if (buf->state == UVC_BUF_STATE_READY) buf = uvc_queue_next_buffer(&stream->queue, buf); } @@ -669,7 +667,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, stream->bulk.payload_size == stream->bulk.max_payload_size) { if (buf->buf.bytesused == stream->queue.buf_used) { stream->queue.buf_used = 0; - buf->state = UVC_BUF_STATE_DONE; + buf->state = UVC_BUF_STATE_READY; uvc_queue_next_buffer(&stream->queue, buf); stream->last_fid ^= UVC_STREAM_FID; } @@ -924,10 +922,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) { struct usb_interface *intf = stream->intf; - struct usb_host_interface *alts; - struct usb_host_endpoint *ep = NULL; - int intfnum = stream->intfnum; - unsigned int bandwidth, psize, i; + struct usb_host_endpoint *ep; + unsigned int i; int ret; stream->last_fid = -1; @@ -936,6 +932,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) stream->bulk.payload_size = 0; if (intf->num_altsetting > 1) { + struct usb_host_endpoint *best_ep = NULL; + unsigned int best_psize = 3 * 1024; + unsigned int bandwidth; + unsigned int uninitialized_var(altsetting); + int intfnum = stream->intfnum; + /* Isochronous endpoint, select the alternate setting. */ bandwidth = stream->ctrl.dwMaxPayloadTransferSize; @@ -949,6 +951,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) } for (i = 0; i < intf->num_altsetting; ++i) { + struct usb_host_interface *alts; + unsigned int psize; + alts = &intf->altsetting[i]; ep = uvc_find_endpoint(alts, stream->header.bEndpointAddress); @@ -958,21 +963,27 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) /* Check if the bandwidth is high enough. */ psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - if (psize >= bandwidth) - break; + if (psize >= bandwidth && psize <= best_psize) { + altsetting = i; + best_psize = psize; + best_ep = ep; + } } - if (i >= intf->num_altsetting) { + if (best_ep == NULL) { uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting " "for requested bandwidth.\n"); return -EIO; } - ret = usb_set_interface(stream->dev->udev, intfnum, i); + uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u " + "(%u B/frame bandwidth).\n", altsetting, best_psize); + + ret = usb_set_interface(stream->dev->udev, intfnum, altsetting); if (ret < 0) return ret; - ret = uvc_init_video_isoc(stream, ep, gfp_flags); + ret = uvc_init_video_isoc(stream, best_ep, gfp_flags); } else { /* Bulk endpoint, proceed to URB initialization. */ ep = uvc_find_endpoint(&intf->altsetting[0], diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 7ec9a04ced50..2337585001ea 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -365,8 +365,9 @@ enum uvc_buffer_state { UVC_BUF_STATE_IDLE = 0, UVC_BUF_STATE_QUEUED = 1, UVC_BUF_STATE_ACTIVE = 2, - UVC_BUF_STATE_DONE = 3, - UVC_BUF_STATE_ERROR = 4, + UVC_BUF_STATE_READY = 3, + UVC_BUF_STATE_DONE = 4, + UVC_BUF_STATE_ERROR = 5, }; struct uvc_buffer { diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index e8e5affbabce..36b5cb86fb57 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -1024,3 +1024,50 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } } EXPORT_SYMBOL_GPL(v4l_bound_align_image); + +/** + * v4l_fill_dv_preset_info - fill description of a digital video preset + * @preset - preset value + * @info - pointer to struct v4l2_dv_enum_preset + * + * drivers can use this helper function to fill description of dv preset + * in info. + */ +int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) +{ + static const struct v4l2_dv_preset_info { + u16 width; + u16 height; + const char *name; + } dv_presets[] = { + { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ + { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ + { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ + { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ + { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ + { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ + { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ + { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ + { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ + { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ + { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ + { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ + { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ + { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ + { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ + { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ + { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ + { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ + { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ + }; + + if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) + return -EINVAL; + + info->preset = preset; + info->width = dv_presets[preset].width; + info->height = dv_presets[preset].height; + strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); + return 0; +} +EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c index 997975d5e024..c4150bd26337 100644 --- a/drivers/media/video/v4l2-compat-ioctl32.c +++ b/drivers/media/video/v4l2-compat-ioctl32.c @@ -1077,6 +1077,12 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_G_CHIP_IDENT: case VIDIOC_S_HW_FREQ_SEEK: + case VIDIOC_ENUM_DV_PRESETS: + case VIDIOC_S_DV_PRESET: + case VIDIOC_G_DV_PRESET: + case VIDIOC_QUERY_DV_PRESET: + case VIDIOC_S_DV_TIMINGS: + case VIDIOC_G_DV_TIMINGS: ret = do_video_ioctl(file, cmd, arg); break; diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 500cbe9891ac..709069916068 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -189,7 +189,7 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf, if (!vdev->fops->read) return -EINVAL; - if (video_is_unregistered(vdev)) + if (!video_is_registered(vdev)) return -EIO; return vdev->fops->read(filp, buf, sz, off); } @@ -201,7 +201,7 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf, if (!vdev->fops->write) return -EINVAL; - if (video_is_unregistered(vdev)) + if (!video_is_registered(vdev)) return -EIO; return vdev->fops->write(filp, buf, sz, off); } @@ -210,7 +210,7 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll) { struct video_device *vdev = video_devdata(filp); - if (!vdev->fops->poll || video_is_unregistered(vdev)) + if (!vdev->fops->poll || !video_is_registered(vdev)) return DEFAULT_POLLMASK; return vdev->fops->poll(filp, poll); } @@ -250,7 +250,7 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp, if (!vdev->fops->get_unmapped_area) return -ENOSYS; - if (video_is_unregistered(vdev)) + if (!video_is_registered(vdev)) return -ENODEV; return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); } @@ -260,8 +260,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) { struct video_device *vdev = video_devdata(filp); - if (!vdev->fops->mmap || - video_is_unregistered(vdev)) + if (!vdev->fops->mmap || !video_is_registered(vdev)) return -ENODEV; return vdev->fops->mmap(filp, vm); } @@ -277,7 +276,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) vdev = video_devdata(filp); /* return ENODEV if the video device has been removed already or if it is not registered anymore. */ - if (vdev == NULL || video_is_unregistered(vdev)) { + if (vdev == NULL || !video_is_registered(vdev)) { mutex_unlock(&videodev_lock); return -ENODEV; } @@ -551,10 +550,11 @@ static int __video_register_device(struct video_device *vdev, int type, int nr, vdev->dev.release = v4l2_device_release; if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) - printk(KERN_WARNING "%s: requested %s%d, got %s%d\n", - __func__, name_base, nr, name_base, vdev->num); + printk(KERN_WARNING "%s: requested %s%d, got %s\n", __func__, + name_base, nr, video_device_node_name(vdev)); /* Part 5: Activate this minor. The char device can now be used. */ + set_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_lock(&videodev_lock); video_device[vdev->minor] = vdev; mutex_unlock(&videodev_lock); @@ -593,11 +593,11 @@ EXPORT_SYMBOL(video_register_device_no_warn); void video_unregister_device(struct video_device *vdev) { /* Check if vdev was ever registered at all */ - if (!vdev || vdev->minor < 0) + if (!vdev || !video_is_registered(vdev)) return; mutex_lock(&videodev_lock); - set_bit(V4L2_FL_UNREGISTERED, &vdev->flags); + clear_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_unlock(&videodev_lock); device_unregister(&vdev->dev); } diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 30cc3347ae52..4b11257c3184 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -284,6 +284,12 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT", [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK", #endif + [_IOC_NR(VIDIOC_ENUM_DV_PRESETS)] = "VIDIOC_ENUM_DV_PRESETS", + [_IOC_NR(VIDIOC_S_DV_PRESET)] = "VIDIOC_S_DV_PRESET", + [_IOC_NR(VIDIOC_G_DV_PRESET)] = "VIDIOC_G_DV_PRESET", + [_IOC_NR(VIDIOC_QUERY_DV_PRESET)] = "VIDIOC_QUERY_DV_PRESET", + [_IOC_NR(VIDIOC_S_DV_TIMINGS)] = "VIDIOC_S_DV_TIMINGS", + [_IOC_NR(VIDIOC_G_DV_TIMINGS)] = "VIDIOC_G_DV_TIMINGS", }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -1135,6 +1141,19 @@ static long __video_do_ioctl(struct file *file, { struct v4l2_input *p = arg; + /* + * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & + * CAP_STD here based on ioctl handler provided by the + * driver. If the driver doesn't support these + * for a specific input, it must override these flags. + */ + if (ops->vidioc_s_std) + p->capabilities |= V4L2_IN_CAP_STD; + if (ops->vidioc_s_dv_preset) + p->capabilities |= V4L2_IN_CAP_PRESETS; + if (ops->vidioc_s_dv_timings) + p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS; + if (!ops->vidioc_enum_input) break; @@ -1179,6 +1198,19 @@ static long __video_do_ioctl(struct file *file, if (!ops->vidioc_enum_output) break; + /* + * We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS & + * CAP_STD here based on ioctl handler provided by the + * driver. If the driver doesn't support these + * for a specific output, it must override these flags. + */ + if (ops->vidioc_s_std) + p->capabilities |= V4L2_OUT_CAP_STD; + if (ops->vidioc_s_dv_preset) + p->capabilities |= V4L2_OUT_CAP_PRESETS; + if (ops->vidioc_s_dv_timings) + p->capabilities |= V4L2_OUT_CAP_CUSTOM_TIMINGS; + ret = ops->vidioc_enum_output(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " @@ -1794,6 +1826,121 @@ static long __video_do_ioctl(struct file *file, } break; } + case VIDIOC_ENUM_DV_PRESETS: + { + struct v4l2_dv_enum_preset *p = arg; + + if (!ops->vidioc_enum_dv_presets) + break; + + ret = ops->vidioc_enum_dv_presets(file, fh, p); + if (!ret) + dbgarg(cmd, + "index=%d, preset=%d, name=%s, width=%d," + " height=%d ", + p->index, p->preset, p->name, p->width, + p->height); + break; + } + case VIDIOC_S_DV_PRESET: + { + struct v4l2_dv_preset *p = arg; + + if (!ops->vidioc_s_dv_preset) + break; + + dbgarg(cmd, "preset=%d\n", p->preset); + ret = ops->vidioc_s_dv_preset(file, fh, p); + break; + } + case VIDIOC_G_DV_PRESET: + { + struct v4l2_dv_preset *p = arg; + + if (!ops->vidioc_g_dv_preset) + break; + + ret = ops->vidioc_g_dv_preset(file, fh, p); + if (!ret) + dbgarg(cmd, "preset=%d\n", p->preset); + break; + } + case VIDIOC_QUERY_DV_PRESET: + { + struct v4l2_dv_preset *p = arg; + + if (!ops->vidioc_query_dv_preset) + break; + + ret = ops->vidioc_query_dv_preset(file, fh, p); + if (!ret) + dbgarg(cmd, "preset=%d\n", p->preset); + break; + } + case VIDIOC_S_DV_TIMINGS: + { + struct v4l2_dv_timings *p = arg; + + if (!ops->vidioc_s_dv_timings) + break; + + switch (p->type) { + case V4L2_DV_BT_656_1120: + dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld," + " width=%d, height=%d, polarities=%x," + " hfrontporch=%d, hsync=%d, hbackporch=%d," + " vfrontporch=%d, vsync=%d, vbackporch=%d," + " il_vfrontporch=%d, il_vsync=%d," + " il_vbackporch=%d\n", + p->bt.interlaced, p->bt.pixelclock, + p->bt.width, p->bt.height, p->bt.polarities, + p->bt.hfrontporch, p->bt.hsync, + p->bt.hbackporch, p->bt.vfrontporch, + p->bt.vsync, p->bt.vbackporch, + p->bt.il_vfrontporch, p->bt.il_vsync, + p->bt.il_vbackporch); + ret = ops->vidioc_s_dv_timings(file, fh, p); + break; + default: + dbgarg2("Unknown type %d!\n", p->type); + break; + } + break; + } + case VIDIOC_G_DV_TIMINGS: + { + struct v4l2_dv_timings *p = arg; + + if (!ops->vidioc_g_dv_timings) + break; + + ret = ops->vidioc_g_dv_timings(file, fh, p); + if (!ret) { + switch (p->type) { + case V4L2_DV_BT_656_1120: + dbgarg2("bt-656/1120:interlaced=%d," + " pixelclock=%lld," + " width=%d, height=%d, polarities=%x," + " hfrontporch=%d, hsync=%d," + " hbackporch=%d, vfrontporch=%d," + " vsync=%d, vbackporch=%d," + " il_vfrontporch=%d, il_vsync=%d," + " il_vbackporch=%d\n", + p->bt.interlaced, p->bt.pixelclock, + p->bt.width, p->bt.height, + p->bt.polarities, p->bt.hfrontporch, + p->bt.hsync, p->bt.hbackporch, + p->bt.vfrontporch, p->bt.vsync, + p->bt.vbackporch, p->bt.il_vfrontporch, + p->bt.il_vsync, p->bt.il_vbackporch); + break; + default: + dbgarg2("Unknown type %d!\n", p->type); + break; + } + } + break; + } default: { diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c index d25f28461da1..22c01097e8a8 100644 --- a/drivers/media/video/videobuf-dma-contig.c +++ b/drivers/media/video/videobuf-dma-contig.c @@ -141,9 +141,11 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, struct vm_area_struct *vma; unsigned long prev_pfn, this_pfn; unsigned long pages_done, user_address; + unsigned int offset; int ret; - mem->size = PAGE_ALIGN(vb->size); + offset = vb->baddr & ~PAGE_MASK; + mem->size = PAGE_ALIGN(vb->size + offset); mem->is_userptr = 0; ret = -EINVAL; @@ -166,7 +168,7 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem, break; if (pages_done == 0) - mem->dma_handle = this_pfn << PAGE_SHIFT; + mem->dma_handle = (this_pfn << PAGE_SHIFT) + offset; else if (this_pfn != (prev_pfn + 1)) ret = -EFAULT; diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index b034a81d2b1c..a15d1e7cbed8 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -4068,7 +4068,6 @@ static struct video_device vdev_template = { .fops = &vino_fops, .ioctl_ops = &vino_ioctl_ops, .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, - .minor = -1, }; static void vino_module_cleanup(int stage) diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 7705fc6baf00..37632a064966 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c @@ -1148,7 +1148,8 @@ static int vivi_open(struct file *file) return -EBUSY; } - dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num, + dprintk(dev, 1, "open %s type=%s users=%d\n", + video_device_node_name(dev->vfd), v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users); /* allocate + initialize per filehandle data */ @@ -1221,8 +1222,7 @@ static int vivi_close(struct file *file) struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; - - int minor = video_devdata(file)->minor; + struct video_device *vdev = video_devdata(file); vivi_stop_thread(vidq); videobuf_stop(&fh->vb_vidq); @@ -1234,8 +1234,8 @@ static int vivi_close(struct file *file) dev->users--; mutex_unlock(&dev->mutex); - dprintk(dev, 1, "close called (minor=%d, users=%d)\n", - minor, dev->users); + dprintk(dev, 1, "close called (dev=%s, users=%d)\n", + video_device_node_name(vdev), dev->users); return 0; } @@ -1296,7 +1296,6 @@ static struct video_device vivi_template = { .name = "vivi", .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, - .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_525_60, @@ -1317,8 +1316,8 @@ static int vivi_release(void) list_del(list); dev = list_entry(list, struct vivi_dev, vivi_devlist); - v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n", - dev->vfd->num); + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(dev->vfd)); video_unregister_device(dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); @@ -1372,15 +1371,12 @@ static int __init vivi_create_instance(int inst) /* Now that everything is fine, let's add it to device list */ list_add_tail(&dev->vivi_devlist, &vivi_devlist); - snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", - vivi_template.name, vfd->num); - if (video_nr >= 0) video_nr++; dev->vfd = vfd; - v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n", - vfd->num); + v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", + video_device_node_name(vfd)); return 0; rel_vdev: diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c index 37fcdc447db5..d807eea91757 100644 --- a/drivers/media/video/w9968cf.c +++ b/drivers/media/video/w9968cf.c @@ -2323,9 +2323,9 @@ static int w9968cf_sensor_init(struct w9968cf_device* cam) error: cam->sensor_initialized = 0; cam->sensor = CC_UNKNOWN; - DBG(1, "Image sensor initialization failed for %s (/dev/video%d). " + DBG(1, "Image sensor initialization failed for %s (%s). " "Try to detach and attach this device again", - symbolic(camlist, cam->id), cam->v4ldev->num) + symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev)) return err; } @@ -2571,7 +2571,8 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) { mutex_lock(&w9968cf_devlist_mutex); - DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->num) + DBG(2, "V4L device deregistered: %s", + video_device_node_name(cam->v4ldev)) video_unregister_device(cam->v4ldev); list_del(&cam->v4llist); @@ -2605,17 +2606,19 @@ static int w9968cf_open(struct file *filp) if (cam->sensor == CC_UNKNOWN) { DBG(2, "No supported image sensor has been detected by the " - "'ovcamchip' module for the %s (/dev/video%d). Make " - "sure it is loaded *before* (re)connecting the camera.", - symbolic(camlist, cam->id), cam->v4ldev->num) + "'ovcamchip' module for the %s (%s). Make sure " + "it is loaded *before* (re)connecting the camera.", + symbolic(camlist, cam->id), + video_device_node_name(cam->v4ldev)) mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); return -ENODEV; } if (cam->users) { - DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", - symbolic(camlist, cam->id), cam->v4ldev->num, cam->command) + DBG(2, "%s (%s) has been already occupied by '%s'", + symbolic(camlist, cam->id), + video_device_node_name(cam->v4ldev), cam->command) if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { mutex_unlock(&cam->dev_mutex); up_read(&w9968cf_disconnect); @@ -2636,8 +2639,8 @@ static int w9968cf_open(struct file *filp) mutex_lock(&cam->dev_mutex); } - DBG(5, "Opening '%s', /dev/video%d ...", - symbolic(camlist, cam->id), cam->v4ldev->num) + DBG(5, "Opening '%s', %s ...", + symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev)) cam->streaming = 0; cam->misconfigured = 0; @@ -2874,8 +2877,7 @@ static long w9968cf_v4l_ioctl(struct file *filp, .minwidth = cam->minwidth, .minheight = cam->minheight, }; - sprintf(cap.name, "W996[87]CF USB Camera #%d", - cam->v4ldev->num); + sprintf(cap.name, "W996[87]CF USB Camera"); cap.maxwidth = (cam->upscaling && w9968cf_vpp) ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth) : cam->maxwidth; @@ -3485,7 +3487,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); cam->v4ldev->fops = &w9968cf_fops; - cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; video_set_drvdata(cam->v4ldev, cam); cam->v4ldev->v4l2_dev = &cam->v4l2_dev; @@ -3501,7 +3502,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L device registered as /dev/video%d", cam->v4ldev->num) + DBG(2, "V4L device registered as %s", + video_device_node_name(cam->v4ldev)) /* Set some basic constants */ w9968cf_configure_camera(cam, udev, mod_id, dev_nr); @@ -3557,10 +3559,10 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) wake_up_interruptible_all(&cam->open); if (cam->users) { - DBG(2, "The device is open (/dev/video%d)! " + DBG(2, "The device is open (%s)! " "Process name: %s. Deregistration and memory " "deallocation are deferred on close.", - cam->v4ldev->num, cam->command) + video_device_node_name(cam->v4ldev), cam->command) cam->misconfigured = 1; w9968cf_stop_transfer(cam); wake_up_interruptible(&cam->wait_queue); diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c index 312a71336fd0..e44e4b5f3e50 100644 --- a/drivers/media/video/zc0301/zc0301_core.c +++ b/drivers/media/video/zc0301/zc0301_core.c @@ -538,8 +538,8 @@ static int zc0301_stream_interrupt(struct zc0301_device* cam) else if (cam->stream != STREAM_OFF) { cam->state |= DEV_MISCONFIGURED; DBG(1, "URB timeout reached. The camera is misconfigured. To " - "use it, close and open /dev/video%d again.", - cam->v4ldev->num); + "use it, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -640,7 +640,8 @@ static void zc0301_release_resources(struct kref *kref) { struct zc0301_device *cam = container_of(kref, struct zc0301_device, kref); - DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->num); + DBG(2, "V4L2 device %s deregistered", + video_device_node_name(cam->v4ldev)); video_set_drvdata(cam->v4ldev, NULL); video_unregister_device(cam->v4ldev); usb_put_dev(cam->usbdev); @@ -679,7 +680,8 @@ static int zc0301_open(struct file *filp) } if (cam->users) { - DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->num); + DBG(2, "Device %s is busy...", + video_device_node_name(cam->v4ldev)); DBG(3, "Simultaneous opens are not supported"); if ((filp->f_flags & O_NONBLOCK) || (filp->f_flags & O_NDELAY)) { @@ -722,7 +724,8 @@ static int zc0301_open(struct file *filp) cam->frame_count = 0; zc0301_empty_framequeues(cam); - DBG(3, "Video device /dev/video%d is open", cam->v4ldev->num); + DBG(3, "Video device %s is open", + video_device_node_name(cam->v4ldev)); out: mutex_unlock(&cam->open_mutex); @@ -746,7 +749,8 @@ static int zc0301_release(struct file *filp) cam->users--; wake_up_interruptible_nr(&cam->wait_open, 1); - DBG(3, "Video device /dev/video%d closed", cam->v4ldev->num); + DBG(3, "Video device %s closed", + video_device_node_name(cam->v4ldev)); kref_put(&cam->kref, zc0301_release_resources); @@ -1276,8 +1280,8 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1289,8 +1293,8 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg) nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -1471,8 +1475,8 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1483,8 +1487,8 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd, nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) { cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To " - "use the camera, close and open /dev/video%d again.", - cam->v4ldev->num); + "use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -ENOMEM; } @@ -1530,8 +1534,8 @@ zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg) if (err) { /* atomic, no rollback in ioctl() */ cam->state |= DEV_MISCONFIGURED; DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware " - "problems. To use the camera, close and open " - "/dev/video%d again.", cam->v4ldev->num); + "problems. To use the camera, close and open %s again.", + video_device_node_name(cam->v4ldev)); return -EIO; } @@ -1984,7 +1988,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); cam->v4ldev->fops = &zc0301_fops; - cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); @@ -2003,7 +2006,8 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) goto fail; } - DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->num); + DBG(2, "V4L2 device registered as %s", + video_device_node_name(cam->v4ldev)); cam->module_param.force_munmap = force_munmap[dev_nr]; cam->module_param.frame_timeout = frame_timeout[dev_nr]; @@ -2040,9 +2044,9 @@ static void zc0301_usb_disconnect(struct usb_interface* intf) DBG(2, "Disconnecting %s...", cam->v4ldev->name); if (cam->users) { - DBG(2, "Device /dev/video%d is open! Deregistration and " + DBG(2, "Device %s is open! Deregistration and " "memory deallocation are deferred.", - cam->v4ldev->num); + video_device_node_name(cam->v4ldev)); cam->state |= DEV_MISCONFIGURED; zc0301_stop_transfer(cam); cam->state |= DEV_DISCONNECTED; diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c index e9f72ca458f1..2ddffed019ee 100644 --- a/drivers/media/video/zoran/zoran_driver.c +++ b/drivers/media/video/zoran/zoran_driver.c @@ -3387,6 +3387,5 @@ struct video_device zoran_template __devinitdata = { .ioctl_ops = &zoran_ioctl_ops, .release = &zoran_vdev_release, .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, - .minor = -1 }; diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 2ef110b5221b..f0eae83e3d89 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -1455,7 +1455,6 @@ static struct video_device zr364xx_template = { .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, .release = video_device_release, - .minor = -1, }; @@ -1635,8 +1634,8 @@ static int zr364xx_probe(struct usb_interface *intf, spin_lock_init(&cam->slock); - dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n", - cam->vdev->num); + dev_info(&udev->dev, DRIVER_DESC " controlling device %s\n", + video_device_node_name(cam->vdev)); return 0; } |