diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-04-28 19:45:20 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-04-28 19:45:20 -0300 |
commit | b254ef22ff520250431995106e98ce08a9cd0af2 (patch) | |
tree | 4e730e629127c5ceaef2f24c45f4d2857289c3a0 | |
parent | 931c58dd0134b10194c570d8e5d47f774dd6fb5d (diff) | |
parent | ba369d468ab5439d1b514a0c52eca6b6e3186211 (diff) | |
download | mediapointer-dvb-s2-b254ef22ff520250431995106e98ce08a9cd0af2.tar.gz mediapointer-dvb-s2-b254ef22ff520250431995106e98ce08a9cd0af2.tar.bz2 |
merge: http://linuxtv.org/hg/~dheitmueller/v4l-dvb-dvicofix
From: Mauro Carvalho Chehab <mchehab@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
31 files changed, 1219 insertions, 605 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.saa7134 b/linux/Documentation/video4linux/CARDLIST.saa7134 index fb3098d56..112ff4f4f 100644 --- a/linux/Documentation/video4linux/CARDLIST.saa7134 +++ b/linux/Documentation/video4linux/CARDLIST.saa7134 @@ -124,10 +124,10 @@ 123 -> Beholder BeholdTV 407 [0000:4070] 124 -> Beholder BeholdTV 407 FM [0000:4071] 125 -> Beholder BeholdTV 409 [0000:4090] -126 -> Beholder BeholdTV 505 FM/RDS [0000:5051,0000:505B,5ace:5050] -127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090] +126 -> Beholder BeholdTV 505 FM [5ace:5050] +127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090] 128 -> Beholder BeholdTV Columbus TVFM [0000:5201] -129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093] +129 -> Beholder BeholdTV 607 FM [5ace:6070] 130 -> Beholder BeholdTV M6 [5ace:6190] 131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022] 132 -> Genius TVGO AM11MCE @@ -157,3 +157,13 @@ 156 -> Hauppauge WinTV-HVR1110r3 [0070:6707,0070:6709,0070:670a] 157 -> Avermedia AVerTV Studio 507UA [1461:a11b] 158 -> AVerMedia Cardbus TV/Radio (E501R) [1461:b7e9] +159 -> Beholder BeholdTV 505 RDS [0000:505B] +160 -> Beholder BeholdTV 507 RDS [0000:5071] +161 -> Beholder BeholdTV 507 RDS [0000:507B] +162 -> Beholder BeholdTV 607 FM [5ace:6071] +163 -> Beholder BeholdTV 609 FM [5ace:6090] +164 -> Beholder BeholdTV 609 FM [5ace:6091] +165 -> Beholder BeholdTV 607 RDS [5ace:6072] +166 -> Beholder BeholdTV 607 RDS [5ace:6073] +167 -> Beholder BeholdTV 609 RDS [5ace:6092] +168 -> Beholder BeholdTV 609 RDS [5ace:6093] diff --git a/linux/Documentation/video4linux/pxa_camera.txt b/linux/Documentation/video4linux/pxa_camera.txt index b1137f9a5..4f6d0ca01 100644 --- a/linux/Documentation/video4linux/pxa_camera.txt +++ b/linux/Documentation/video4linux/pxa_camera.txt @@ -26,6 +26,55 @@ Global video workflow Once the last buffer is filled in, the QCI interface stops. + c) Capture global finite state machine schema + + +----+ +---+ +----+ + | DQ | | Q | | DQ | + | v | v | v + +-----------+ +------------------------+ + | STOP | | Wait for capture start | + +-----------+ Q +------------------------+ ++-> | QCI: stop | ------------------> | QCI: run | <------------+ +| | DMA: stop | | DMA: stop | | +| +-----------+ +-----> +------------------------+ | +| / | | +| / +---+ +----+ | | +|capture list empty / | Q | | DQ | | QCI Irq EOF | +| / | v | v v | +| +--------------------+ +----------------------+ | +| | DMA hotlink missed | | Capture running | | +| +--------------------+ +----------------------+ | +| | QCI: run | +-----> | QCI: run | <-+ | +| | DMA: stop | / | DMA: run | | | +| +--------------------+ / +----------------------+ | Other | +| ^ /DMA still | | channels | +| | capture list / running | DMA Irq End | not | +| | not empty / | | finished | +| | / v | yet | +| +----------------------+ +----------------------+ | | +| | Videobuf released | | Channel completed | | | +| +----------------------+ +----------------------+ | | ++-- | QCI: run | | QCI: run | --+ | + | DMA: run | | DMA: run | | + +----------------------+ +----------------------+ | + ^ / | | + | no overrun / | overrun | + | / v | + +--------------------+ / +----------------------+ | + | Frame completed | / | Frame overran | | + +--------------------+ <-----+ +----------------------+ restart frame | + | QCI: run | | QCI: stop | --------------+ + | DMA: run | | DMA: stop | + +--------------------+ +----------------------+ + + Legend: - each box is a FSM state + - each arrow is the condition to transition to another state + - an arrow with a comment is a mandatory transition (no condition) + - arrow "Q" means : a buffer was enqueued + - arrow "DQ" means : a buffer was dequeued + - "QCI: stop" means the QCI interface is not enabled + - "DMA: stop" means all 3 DMA channels are stopped + - "DMA: run" means at least 1 DMA channel is still running DMA usage --------- diff --git a/linux/arch/arm/mach-pxa/pcm990-baseboard.c b/linux/arch/arm/mach-pxa/pcm990-baseboard.c index 7a95c80ab..9ce1ef2e5 100644 --- a/linux/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/linux/arch/arm/mach-pxa/pcm990-baseboard.c @@ -22,46 +22,21 @@ #include <linux/irq.h> #include <linux/platform_device.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#include <linux/ide.h> -#endif #include <linux/i2c.h> #include <linux/pwm_backlight.h> #include <media/soc_camera.h> #include <asm/gpio.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#include <asm/arch/i2c.h> -#include <asm/arch/camera.h> -#else #include <mach/i2c.h> #include <mach/camera.h> -#endif #include <asm/mach/map.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#include <asm/arch/pxa-regs.h> -#include <asm/arch/audio.h> -#include <asm/arch/mmc.h> -#include <asm/arch/ohci.h> -#include <asm/arch/pcm990_baseboard.h> -#include <asm/arch/pxafb.h> -#include <asm/arch/mfp-pxa27x.h> -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) -#include <mach/pxa-regs.h> -#else #include <mach/pxa27x.h> -#endif #include <mach/audio.h> #include <mach/mmc.h> #include <mach/ohci.h> #include <mach/pcm990_baseboard.h> #include <mach/pxafb.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) -#include <mach/mfp-pxa27x.h> -#endif -#endif #include "devices.h" #include "generic.h" @@ -402,15 +377,15 @@ struct pxacamera_platform_data pcm990_pxacamera_platform_data = { #include <linux/i2c/pca953x.h> static struct pca953x_platform_data pca9536_data = { - .gpio_base = NR_BUILTIN_GPIO + 1, + .gpio_base = NR_BUILTIN_GPIO, }; -static int gpio_bus_switch; +static int gpio_bus_switch = -EINVAL; static int pcm990_camera_set_bus_param(struct soc_camera_link *link, - unsigned long flags) + unsigned long flags) { - if (gpio_bus_switch <= 0) { + if (gpio_bus_switch < 0) { if (flags == SOCAM_DATAWIDTH_10) return 0; else @@ -429,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link) { int ret; - if (!gpio_bus_switch) { - ret = gpio_request(NR_BUILTIN_GPIO + 1, "camera"); + if (gpio_bus_switch < 0) { + ret = gpio_request(NR_BUILTIN_GPIO, "camera"); if (!ret) { - gpio_bus_switch = NR_BUILTIN_GPIO + 1; + gpio_bus_switch = NR_BUILTIN_GPIO; gpio_direction_output(gpio_bus_switch, 0); - } else - gpio_bus_switch = -EINVAL; + } } - if (gpio_bus_switch > 0) + if (gpio_bus_switch >= 0) return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10; else return SOCAM_DATAWIDTH_10; } +static void pcm990_camera_free_bus(struct soc_camera_link *link) +{ + if (gpio_bus_switch < 0) + return; + + gpio_free(gpio_bus_switch); + gpio_bus_switch = -EINVAL; +} + static struct soc_camera_link iclink = { .bus_id = 0, /* Must match with the camera ID above */ .query_bus_param = pcm990_camera_query_bus_param, .set_bus_param = pcm990_camera_set_bus_param, + .free_bus = pcm990_camera_free_bus, }; /* Board I2C devices. */ diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index 3f1a0350a..7aefac643 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -134,10 +134,6 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ -obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o -obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o -obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o -obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o @@ -147,6 +143,11 @@ obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o +# soc-camera host drivers have to be linked after camera drivers +obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o +obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o +obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o +obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_VIDEO_AU0828) += au0828/ diff --git a/linux/drivers/media/video/cx18/cx18-audio.c b/linux/drivers/media/video/cx18/cx18-audio.c index 7a8ad5963..352689239 100644 --- a/linux/drivers/media/video/cx18/cx18-audio.c +++ b/linux/drivers/media/video/cx18/cx18-audio.c @@ -26,14 +26,18 @@ #include "cx18-cards.h" #include "cx18-audio.h" -#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 /* Selects the audio input and output according to the current settings. */ int cx18_audio_set_io(struct cx18 *cx) { const struct cx18_card_audio_input *in; - u32 val; + u32 u, v; int err; /* Determine which input to use */ @@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx) return err; /* FIXME - this internal mux should be abstracted to a subdev */ - val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30; - val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 : - (in->audio_input << 4); - cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30); + u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + v = u & ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + v |= CX18_AI1_MUX_I2S1; + break; + case CX18_AV_AUDIO_SERIAL2: + v |= CX18_AI1_MUX_I2S2; + break; + default: + v |= CX18_AI1_MUX_843_I2S; + break; + } + if (v == u) { + /* force a toggle of some AI1 MUX control bits */ + u &= ~CX18_AI1_MUX_MASK; + switch (in->audio_input) { + case CX18_AV_AUDIO_SERIAL1: + u |= CX18_AI1_MUX_843_I2S; + break; + case CX18_AV_AUDIO_SERIAL2: + u |= CX18_AI1_MUX_843_I2S; + break; + default: + u |= CX18_AI1_MUX_I2S1; + break; + } + cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, + u, CX18_AI1_MUX_MASK); + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); return 0; } diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index 49a55cc8d..b9e8cc5d2 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -24,15 +24,63 @@ #include "cx18-io.h" #include <linux/firmware.h> -#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_AI1_MUX_MASK 0x30 +#define CX18_AI1_MUX_I2S1 0x00 +#define CX18_AI1_MUX_I2S2 0x10 +#define CX18_AI1_MUX_843_I2S 0x20 +#define CX18_AI1_MUX_INVALID 0x30 + #define FWFILE "v4l-cx23418-dig.fw" +static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) +{ + struct v4l2_subdev *sd = &cx->av_state.sd; + int ret = 0; + const u8 *data; + u32 size; + int addr; + u32 expected, dl_control; + + /* Ensure we put the 8051 in reset and enable firmware upload mode */ + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + do { + dl_control &= 0x00ffffff; + dl_control |= 0x0f000000; + cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } while ((dl_control & 0xff000000) != 0x0f000000); + + /* Read and auto increment until at address 0x0000 */ + while (dl_control & 0x3fff) + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + + data = fw->data; + size = fw->size; + for (addr = 0; addr < size; addr++) { + dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ + expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; + if (expected != dl_control) { + CX18_ERR_DEV(sd, "verification of %s firmware load " + "failed: expected %#010x got %#010x\n", + FWFILE, expected, dl_control); + ret = -EIO; + break; + } + dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); + } + if (ret == 0) + CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n", + FWFILE, size); + return ret; +} + int cx18_av_loadfw(struct cx18 *cx) { struct v4l2_subdev *sd = &cx->av_state.sd; const struct firmware *fw = NULL; u32 size; - u32 v; + u32 u, v; const u8 *ptr; int i; int retries1 = 0; @@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx) } cx18_av_write4_expect(cx, CXADEC_DL_CTL, + 0x03000000 | fw->size, 0x03000000, 0x13000000); + + CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); + + if (cx18_av_verifyfw(cx, fw) == 0) + cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x13000000 | fw->size, 0x13000000, 0x13000000); /* Output to the 416 */ @@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE, 0, 0x400); + /* Toggle the AI1 MUX */ + v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); + u = v & CX18_AI1_MUX_MASK; + v &= ~CX18_AI1_MUX_MASK; + if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) { + /* Switch to I2S1 */ + v |= CX18_AI1_MUX_I2S1; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to the A/V decoder core I2S output */ + v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S; + } else { + /* Switch to the A/V decoder core I2S output */ + v |= CX18_AI1_MUX_843_I2S; + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Switch back to I2S1 or I2S2 */ + v = (v & ~CX18_AI1_MUX_MASK) | u; + } + cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, + v, CX18_AI1_MUX_MASK); + /* Enable WW auto audio standard detection */ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); v |= 0xFF; /* Auto by default */ @@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx) cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); release_firmware(fw); - - CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); return 0; } diff --git a/linux/drivers/media/video/cx18/cx18-controls.c b/linux/drivers/media/video/cx18/cx18-controls.c index 82fc2f9d4..8e35c3aed 100644 --- a/linux/drivers/media/video/cx18/cx18-controls.c +++ b/linux/drivers/media/video/cx18/cx18-controls.c @@ -176,8 +176,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, return -EBUSY; if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || - type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) { - /* We don't do VBI insertion aside from IVTV format in a PS */ + !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || + type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { + /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " "the MPEG stream\n"); diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index 062129fb5..41997dd18 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -30,6 +30,7 @@ #include "cx18-irq.h" #include "cx18-gpio.h" #include "cx18-firmware.h" +#include "cx18-queue.h" #include "cx18-streams.h" #include "cx18-av-core.h" #include "cx18-scb.h" @@ -546,6 +547,45 @@ done: cx->card_i2c = cx->card->i2c; } +static int __devinit cx18_create_in_workq(struct cx18 *cx) +{ + snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", + cx->v4l2_dev.name); + cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name); + if (cx->in_work_queue == NULL) { + CX18_ERR("Unable to create incoming mailbox handler thread\n"); + return -ENOMEM; + } + return 0; +} + +static int __devinit cx18_create_out_workq(struct cx18 *cx) +{ + snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out", + cx->v4l2_dev.name); + cx->out_work_queue = create_workqueue(cx->out_workq_name); + if (cx->out_work_queue == NULL) { + CX18_ERR("Unable to create outgoing mailbox handler threads\n"); + return -ENOMEM; + } + return 0; +} + +static void __devinit cx18_init_in_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { + cx->in_work_order[i].cx = cx; + cx->in_work_order[i].str = cx->epu_debug_str; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) + INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); +#else + INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler, + &cx->in_work_order[i].work); +#endif + } +} + /* Precondition: the cx18 structure has been memset to 0. Only the dev and instance fields have been filled in. No assumptions on the card type may be made here (see cx18_init_struct2 @@ -553,7 +593,7 @@ done: */ static int __devinit cx18_init_struct1(struct cx18 *cx) { - int i; + int ret; cx->base_addr = pci_resource_start(cx->pci_dev, 0); @@ -562,23 +602,18 @@ static int __devinit cx18_init_struct1(struct cx18 *cx) mutex_init(&cx->epu2apu_mb_lock); mutex_init(&cx->epu2cpu_mb_lock); - cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name); - if (cx->work_queue == NULL) { - CX18_ERR("Unable to create work hander thread\n"); - return -ENOMEM; - } + ret = cx18_create_out_workq(cx); + if (ret) + return ret; - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { - cx->epu_work_order[i].cx = cx; - cx->epu_work_order[i].str = cx->epu_debug_str; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) - INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler); -#else - INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler, - &cx->epu_work_order[i].work); -#endif + ret = cx18_create_in_workq(cx); + if (ret) { + destroy_workqueue(cx->out_work_queue); + return ret; } + cx18_init_in_work_orders(cx); + /* start counting open_id at 1 */ cx->open_id = 1; @@ -764,17 +799,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev, retval = -ENODEV; goto err; } - if (cx18_init_struct1(cx)) { - retval = -ENOMEM; + + retval = cx18_init_struct1(cx); + if (retval) goto err; - } CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); /* PCI Device Setup */ retval = cx18_setup_pci(cx, pci_dev, pci_id); if (retval != 0) - goto free_workqueue; + goto free_workqueues; /* map io memory */ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", @@ -948,8 +983,9 @@ free_map: cx18_iounmap(cx); free_mem: release_mem_region(cx->base_addr, CX18_MEM_SIZE); -free_workqueue: - destroy_workqueue(cx->work_queue); +free_workqueues: + destroy_workqueue(cx->in_work_queue); + destroy_workqueue(cx->out_work_queue); err: if (retval == 0) retval = -ENODEV; @@ -1059,11 +1095,19 @@ int cx18_init_on_first_open(struct cx18 *cx) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) -static void cx18_cancel_epu_work_orders(struct cx18 *cx) +static void cx18_cancel_in_work_orders(struct cx18 *cx) { int i; - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) - cancel_work_sync(&cx->epu_work_order[i].work); + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) + cancel_work_sync(&cx->in_work_order[i].work); +} + +static void cx18_cancel_out_work_orders(struct cx18 *cx) +{ + int i; + for (i = 0; i < CX18_MAX_STREAMS; i++) + if (&cx->streams[i].video_dev != NULL) + cancel_work_sync(&cx->streams[i].out_work_order); } #endif @@ -1080,24 +1124,25 @@ static void cx18_remove(struct pci_dev *pci_dev) if (atomic_read(&cx->tot_capturing) > 0) cx18_stop_all_captures(cx); - /* Interrupts */ + /* Stop interrupts that cause incoming work to be queued */ cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - cx18_halt_firmware(cx); - cx18_cancel_epu_work_orders(cx); + /* Incoming work can cause outgoing work, so clean up incoming first */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + cx18_cancel_in_work_orders(cx); + cx18_cancel_out_work_orders(cx); #else + flush_workqueue(cx->in_work_queue); + flush_workqueue(cx->out_work_queue); +#endif - flush_workqueue(cx->work_queue); - + /* Stop ack interrupts that may have been needed for work to finish */ cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); cx18_halt_firmware(cx); -#endif - destroy_workqueue(cx->work_queue); + destroy_workqueue(cx->in_work_queue); + destroy_workqueue(cx->out_work_queue); cx18_streams_cleanup(cx, 1); diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index ece4f281e..f89b82367 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -254,6 +254,7 @@ struct cx18_options { #define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ #define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ #define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ +#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */ /* per-cx18, i_flags */ #define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ @@ -285,6 +286,7 @@ struct cx18_queue { struct list_head list; atomic_t buffers; u32 bytesused; + spinlock_t lock; }; struct cx18_dvb { @@ -305,7 +307,7 @@ struct cx18_scb; /* forward reference */ #define CX18_MAX_MDL_ACKS 2 -#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) +#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 @@ -313,7 +315,7 @@ struct cx18_scb; /* forward reference */ #define CX18_F_EWO_MB_STALE \ (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC) -struct cx18_epu_work_order { +struct cx18_in_work_order { struct work_struct work; atomic_t pending; struct cx18 *cx; @@ -337,7 +339,6 @@ struct cx18_stream { unsigned mdl_offset; u32 id; - struct mutex qlock; /* locks access to the queues */ unsigned long s_flags; /* status flags, see above */ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or @@ -353,6 +354,8 @@ struct cx18_stream { struct cx18_queue q_busy; /* busy buffers - in use by firmware */ struct cx18_queue q_full; /* full buffers - data for user apps */ + struct work_struct out_work_order; + /* DVB / Digital Transport */ struct cx18_dvb dvb; }; @@ -568,10 +571,14 @@ struct cx18 { u32 sw2_irq_mask; u32 hw2_irq_mask; - struct workqueue_struct *work_queue; - struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS]; + struct workqueue_struct *in_work_queue; + char in_workq_name[11]; /* "cx18-NN-in" */ + struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ + struct workqueue_struct *out_work_queue; + char out_workq_name[12]; /* "cx18-NN-out" */ + /* i2c */ struct i2c_adapter i2c_adap[2]; struct i2c_algo_bit_data i2c_algo[2]; diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index 3b86f57cd..e7285a109 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -23,6 +23,7 @@ #include "cx18-version.h" #include "cx18-dvb.h" #include "cx18-io.h" +#include "cx18-queue.h" #include "cx18-streams.h" #include "cx18-cards.h" #include "s5h1409.h" diff --git a/linux/drivers/media/video/cx18/cx18-fileops.c b/linux/drivers/media/video/cx18/cx18-fileops.c index d20ac818f..817bb9263 100644 --- a/linux/drivers/media/video/cx18/cx18-fileops.c +++ b/linux/drivers/media/video/cx18/cx18-fileops.c @@ -301,8 +301,13 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s, * an MPEG-2 Program Pack start code, and provide only * up to that point to the user, so it's easy to insert VBI data * the next time around. + * + * This will not work for an MPEG-2 TS and has only been + * verified by analysis to work for an MPEG-2 PS. Helen Buus + * pointed out this works for the CX23416 MPEG-2 DVD compatible + * stream, and research indicates both the MPEG 2 SVCD and DVD + * stream types use an MPEG-2 PS container. */ - /* FIXME - This only works for an MPEG-2 PS, not a TS */ /* * An MPEG-2 Program Stream (PS) is a series of * MPEG-2 Program Packs terminated by an diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.c b/linux/drivers/media/video/cx18/cx18-mailbox.c index 66964722f..36f4d3dd7 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.c +++ b/linux/drivers/media/video/cx18/cx18-mailbox.c @@ -131,7 +131,7 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) * Functions that run in a work_queue work handling context */ -static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) { u32 handle, mdl_ack_count, id; struct cx18_mailbox *mb; @@ -191,29 +191,30 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) if (buf == NULL) { CX18_WARN("Could not find buf %d for stream %s\n", id, s->name); - /* Put as many buffers as possible back into fw use */ - cx18_stream_load_fw_queue(s); continue; } - if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { - CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", - buf->bytesused); - dvb_dmx_swfilter(&s->dvb.demux, buf->buf, - buf->bytesused); + CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", + s->name, buf->bytesused); + + if (s->type != CX18_ENC_STREAM_TYPE_TS) + cx18_enqueue(s, buf, &s->q_full); + else { + if (s->dvb.enabled) + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + cx18_enqueue(s, buf, &s->q_free); } - /* Put as many buffers as possible back into fw use */ - cx18_stream_load_fw_queue(s); - /* Put back TS buffer, since it was removed from all queues */ - if (s->type == CX18_ENC_STREAM_TYPE_TS) - cx18_stream_put_buf_fw(s, buf); } + /* Put as many buffers as possible back into fw use */ + cx18_stream_load_fw_queue(s); + wake_up(&cx->dma_waitq); if (s->id != -1) wake_up(&s->waitq); } -static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) { char *p; char *str = order->str; @@ -224,7 +225,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order) CX18_INFO("FW version: %s\n", p - 1); } -static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order) +static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) { switch (order->rpu) { case CPU: @@ -253,24 +254,24 @@ static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order) } static -void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order) +void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) { atomic_set(&order->pending, 0); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -void cx18_epu_work_handler(struct work_struct *work) +void cx18_in_work_handler(struct work_struct *work) { - struct cx18_epu_work_order *order = - container_of(work, struct cx18_epu_work_order, work); + struct cx18_in_work_order *order = + container_of(work, struct cx18_in_work_order, work); #else -void cx18_epu_work_handler(void *arg) +void cx18_in_work_handler(void *arg) { - struct cx18_epu_work_order *order = arg; + struct cx18_in_work_order *order = arg; #endif struct cx18 *cx = order->cx; epu_cmd(cx, order); - free_epu_work_order(cx, order); + free_in_work_order(cx, order); } @@ -278,7 +279,7 @@ void cx18_epu_work_handler(void *arg) * Functions that run in an interrupt handling context */ -static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) { struct cx18_mailbox __iomem *ack_mb; u32 ack_irq, req; @@ -314,7 +315,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order) return; } -static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) { u32 handle, mdl_ack_offset, mdl_ack_count; struct cx18_mailbox *mb; @@ -340,7 +341,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static -int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) { u32 str_offset; char *str = order->str; @@ -361,7 +362,7 @@ int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static inline -int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order) +int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) { int ret = -1; @@ -393,12 +394,12 @@ int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order) } static inline -struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx) +struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) { int i; - struct cx18_epu_work_order *order = NULL; + struct cx18_in_work_order *order = NULL; - for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { + for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { /* * We only need "pending" atomic to inspect its contents, * and need not do a check and set because: @@ -407,8 +408,8 @@ struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx) * 2. "pending" is only set here, and we're serialized because * we're called in an IRQ handler context. */ - if (atomic_read(&cx->epu_work_order[i].pending) == 0) { - order = &cx->epu_work_order[i]; + if (atomic_read(&cx->in_work_order[i].pending) == 0) { + order = &cx->in_work_order[i]; atomic_set(&order->pending, 1); break; } @@ -420,7 +421,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) { struct cx18_mailbox __iomem *mb; struct cx18_mailbox *order_mb; - struct cx18_epu_work_order *order; + struct cx18_in_work_order *order; int submit; switch (rpu) { @@ -434,7 +435,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) return; } - order = alloc_epu_work_order_irq(cx); + order = alloc_in_work_order_irq(cx); if (order == NULL) { CX18_WARN("Unable to find blank work order form to schedule " "incoming mailbox command processing\n"); @@ -467,7 +468,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) */ submit = epu_cmd_irq(cx, order); if (submit > 0) { - queue_work(cx->work_queue, &order->work); + queue_work(cx->in_work_queue, &order->work); } } @@ -484,9 +485,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) u32 __iomem *xpu_state; wait_queue_head_t *waitq; struct mutex *mb_lock; - long int timeout, ret; + unsigned long int t0, timeout, ret; int i; char argstr[MAX_MB_ARGUMENTS*11+1]; + DEFINE_WAIT(w); if (info == NULL) { CX18_WARN("unknown cmd %x\n", cmd); @@ -568,25 +570,49 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", irq, info->name); + + /* So we don't miss the wakeup, prepare to wait before notifying fw */ + prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - ret = wait_event_timeout( - *waitq, - cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), - timeout); + t0 = jiffies; + ack = cx18_readl(cx, &mb->ack); + if (ack != req) { + schedule_timeout(timeout); + ret = jiffies - t0; + ack = cx18_readl(cx, &mb->ack); + } else { + ret = jiffies - t0; + } - if (ret == 0) { - /* Timed out */ + finish_wait(waitq, &w); + + if (req != ack) { mutex_unlock(mb_lock); - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU " - "acknowledgement\n", - info->name, jiffies_to_msecs(timeout)); + if (ret >= timeout) { + /* Timed out */ + CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " + "for RPU acknowledgement\n", + info->name, jiffies_to_msecs(ret)); + } else { + CX18_DEBUG_WARN("woken up before mailbox ack was ready " + "after submitting %s to RPU. only " + "waited %d msecs on req %u but awakened" + " with unmatched ack %u\n", + info->name, + jiffies_to_msecs(ret), + req, ack); + } return -EINVAL; } - if (ret != timeout) + if (ret >= timeout) + CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " + "sending %s; timed out waiting %d msecs\n", + info->name, jiffies_to_msecs(ret)); + else CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(timeout-ret), info->name); + jiffies_to_msecs(ret), info->name); /* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++) diff --git a/linux/drivers/media/video/cx18/cx18-mailbox.h b/linux/drivers/media/video/cx18/cx18-mailbox.h index a667f1ae4..4bd0ba57f 100644 --- a/linux/drivers/media/video/cx18/cx18-mailbox.h +++ b/linux/drivers/media/video/cx18/cx18-mailbox.h @@ -96,9 +96,9 @@ int cx18_api_func(void *priv, u32 cmd, int in, int out, void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) -void cx18_epu_work_handler(struct work_struct *work); +void cx18_in_work_handler(struct work_struct *work); #else -void cx18_epu_work_handler(void *arg); +void cx18_in_work_handler(void *arg); #endif #endif diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 3046b8e74..fa1ed7897 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -23,8 +23,8 @@ */ #include "cx18-driver.h" -#include "cx18-streams.h" #include "cx18-queue.h" +#include "cx18-streams.h" #include "cx18-scb.h" void cx18_buf_swap(struct cx18_buffer *buf) @@ -53,13 +53,13 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, buf->skipped = 0; } - mutex_lock(&s->qlock); - /* q_busy is restricted to a max buffer count imposed by firmware */ if (q == &s->q_busy && atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM) q = &s->q_free; + spin_lock(&q->lock); + if (to_front) list_add(&buf->list, &q->list); /* LIFO */ else @@ -67,7 +67,7 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, q->bytesused += buf->bytesused - buf->readpos; atomic_inc(&q->buffers); - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); return q; } @@ -75,7 +75,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) { struct cx18_buffer *buf = NULL; - mutex_lock(&s->qlock); + spin_lock(&q->lock); if (!list_empty(&q->list)) { buf = list_first_entry(&q->list, struct cx18_buffer, list); list_del_init(&buf->list); @@ -83,7 +83,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) buf->skipped = 0; atomic_dec(&q->buffers); } - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); return buf; } @@ -94,9 +94,23 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, struct cx18_buffer *buf; struct cx18_buffer *tmp; struct cx18_buffer *ret = NULL; - - mutex_lock(&s->qlock); + LIST_HEAD(sweep_up); + + /* + * We don't have to acquire multiple q locks here, because we are + * serialized by the single threaded work handler. + * Buffers from the firmware will thus remain in order as + * they are moved from q_busy to q_full or to the dvb ring buffer. + */ + spin_lock(&s->q_busy.lock); list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) { + /* + * We should find what the firmware told us is done, + * right at the front of the queue. If we don't, we likely have + * missed a buffer done message from the firmware. + * Once we skip a buffer repeatedly, relative to the size of + * q_busy, we have high confidence we've missed it. + */ if (buf->id != id) { buf->skipped++; if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) { @@ -105,38 +119,41 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, "times - it must have dropped out of " "rotation\n", s->name, buf->id, buf->skipped); - /* move it to q_free */ - list_move_tail(&buf->list, &s->q_free.list); - buf->bytesused = buf->readpos = buf->b_flags = - buf->skipped = 0; + /* Sweep it up to put it back into rotation */ + list_move_tail(&buf->list, &sweep_up); atomic_dec(&s->q_busy.buffers); - atomic_inc(&s->q_free.buffers); } continue; } - - buf->bytesused = bytesused; - /* Sync the buffer before we release the qlock */ - cx18_buf_sync_for_cpu(s, buf); - if (s->type == CX18_ENC_STREAM_TYPE_TS) { - /* - * TS doesn't use q_full. As we pull the buffer off of - * the queue here, the caller will have to put it back. - */ - list_del_init(&buf->list); - } else { - /* Move buffer from q_busy to q_full */ - list_move_tail(&buf->list, &s->q_full.list); - set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); - s->q_full.bytesused += buf->bytesused; - atomic_inc(&s->q_full.buffers); - } + /* + * We pull the desired buffer off of the queue here. Something + * will have to put it back on a queue later. + */ + list_del_init(&buf->list); atomic_dec(&s->q_busy.buffers); - ret = buf; break; } - mutex_unlock(&s->qlock); + spin_unlock(&s->q_busy.lock); + + /* + * We found the buffer for which we were looking. Get it ready for + * the caller to put on q_full or in the dvb ring buffer. + */ + if (ret != NULL) { + ret->bytesused = bytesused; + ret->skipped = 0; + /* readpos and b_flags were 0'ed when the buf went on q_busy */ + cx18_buf_sync_for_cpu(s, ret); + if (s->type != CX18_ENC_STREAM_TYPE_TS) + set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags); + } + + /* Put any buffers the firmware is ignoring back into normal rotation */ + list_for_each_entry_safe(buf, tmp, &sweep_up, list) { + list_del_init(&buf->list); + cx18_enqueue(s, buf, &s->q_free); + } return ret; } @@ -148,7 +165,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) if (q == &s->q_free) return; - mutex_lock(&s->qlock); + spin_lock(&q->lock); while (!list_empty(&q->list)) { buf = list_first_entry(&q->list, struct cx18_buffer, list); list_move_tail(&buf->list, &s->q_free.list); @@ -156,7 +173,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) atomic_inc(&s->q_free.buffers); } cx18_queue_init(q); - mutex_unlock(&s->qlock); + spin_unlock(&q->lock); } void cx18_flush_queues(struct cx18_stream *s) diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 7c1db9c18..142302ba5 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -116,12 +116,21 @@ static void cx18_stream_init(struct cx18 *cx, int type) s->buffers = cx->stream_buffers[type]; s->buf_size = cx->stream_buf_size[type]; - mutex_init(&s->qlock); init_waitqueue_head(&s->waitq); s->id = -1; + spin_lock_init(&s->q_free.lock); cx18_queue_init(&s->q_free); + spin_lock_init(&s->q_busy.lock); cx18_queue_init(&s->q_busy); + spin_lock_init(&s->q_full.lock); cx18_queue_init(&s->q_full); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) + INIT_WORK(&s->out_work_order, cx18_out_work_handler); +#else + INIT_WORK(&s->out_work_order, cx18_out_work_handler, + &s->out_work_order); +#endif } static int cx18_prep_dev(struct cx18 *cx, int type) @@ -431,14 +440,16 @@ static void cx18_vbi_setup(struct cx18_stream *s) cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); } -struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, - struct cx18_buffer *buf) +static +struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) { struct cx18 *cx = s->cx; struct cx18_queue *q; /* Don't give it to the firmware, if we're not running a capture */ if (s->handle == CX18_INVALID_TASK_HANDLE || + test_bit(CX18_F_S_STOPPING, &s->s_flags) || !test_bit(CX18_F_S_STREAMING, &s->s_flags)) return cx18_enqueue(s, buf, &s->q_free); @@ -453,7 +464,8 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, return q; } -void cx18_stream_load_fw_queue(struct cx18_stream *s) +static +void _cx18_stream_load_fw_queue(struct cx18_stream *s) { struct cx18_queue *q; struct cx18_buffer *buf; @@ -467,11 +479,25 @@ void cx18_stream_load_fw_queue(struct cx18_stream *s) buf = cx18_dequeue(s, &s->q_free); if (buf == NULL) break; - q = cx18_stream_put_buf_fw(s, buf); + q = _cx18_stream_put_buf_fw(s, buf); } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM && q == &s->q_busy); } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +void cx18_out_work_handler(struct work_struct *work) +{ +#else +void cx18_out_work_handler(void *arg) +{ + struct work_struct *work = arg; +#endif + struct cx18_stream *s = + container_of(work, struct cx18_stream, out_work_order); + + _cx18_stream_load_fw_queue(s); +} + int cx18_start_v4l2_encode_stream(struct cx18_stream *s) { u32 data[MAX_MB_ARGUMENTS]; @@ -600,19 +626,20 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) /* Init all the cpu_mdls for this stream */ cx18_flush_queues(s); - mutex_lock(&s->qlock); + spin_lock(&s->q_free.lock); list_for_each_entry(buf, &s->q_free.list, list) { cx18_writel(cx, buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); } - mutex_unlock(&s->qlock); - cx18_stream_load_fw_queue(s); + spin_unlock(&s->q_free.lock); + _cx18_stream_load_fw_queue(s); /* begin_capture */ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { CX18_DEBUG_WARN("Error starting capture!\n"); /* Ensure we're really not capturing before releasing MDLs */ + set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); else @@ -622,6 +649,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) == 0) { set_bit(CX18_F_I_EOS, &cx->i_flags); cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); @@ -666,6 +694,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) if (atomic_read(&cx->tot_capturing) == 0) return 0; + set_bit(CX18_F_S_STOPPING, &s->s_flags); if (s->type == CX18_ENC_STREAM_TYPE_MPG) cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); else @@ -716,6 +745,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); s->handle = CX18_INVALID_TASK_HANDLE; + clear_bit(CX18_F_S_STOPPING, &s->s_flags); if (atomic_read(&cx->tot_capturing) > 0) return 0; diff --git a/linux/drivers/media/video/cx18/cx18-streams.h b/linux/drivers/media/video/cx18/cx18-streams.h index 420e0a172..b51a014b5 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.h +++ b/linux/drivers/media/video/cx18/cx18-streams.h @@ -28,10 +28,28 @@ int cx18_streams_setup(struct cx18 *cx); int cx18_streams_register(struct cx18 *cx); void cx18_streams_cleanup(struct cx18 *cx, int unregister); +/* Related to submission of buffers to firmware */ +static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + queue_work(cx->out_work_queue, &s->out_work_order); +} + +static inline void cx18_stream_put_buf_fw(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + /* Put buf on q_free; the out work handler will move buf(s) to q_busy */ + cx18_enqueue(s, buf, &s->q_free); + cx18_stream_load_fw_queue(s); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) +void cx18_out_work_handler(struct work_struct *work); +#else +void cx18_out_work_handler(void *arg); +#endif + /* Capture related */ -void cx18_stream_load_fw_queue(struct cx18_stream *s); -struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, - struct cx18_buffer *buf); int cx18_start_v4l2_encode_stream(struct cx18_stream *s); int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); diff --git a/linux/drivers/media/video/cx18/cx18-version.h b/linux/drivers/media/video/cx18/cx18-version.h index bd9bd44da..45494b094 100644 --- a/linux/drivers/media/video/cx18/cx18-version.h +++ b/linux/drivers/media/video/cx18/cx18-version.h @@ -24,7 +24,7 @@ #define CX18_DRIVER_NAME "cx18" #define CX18_DRIVER_VERSION_MAJOR 1 -#define CX18_DRIVER_VERSION_MINOR 1 +#define CX18_DRIVER_VERSION_MINOR 2 #define CX18_DRIVER_VERSION_PATCHLEVEL 0 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index 83f3cae47..8d61ad30a 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -75,53 +75,50 @@ struct mt9m001 { unsigned char autoexposure; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct i2c_client *client = mt9m001->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } static int mt9m001_init(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; dev_dbg(icd->vdev->parent, "%s\n", __func__); if (icl->power) { - ret = icl->power(&mt9m001->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -131,49 +128,53 @@ static int mt9m001_init(struct soc_camera_device *icd) /* The camera could have been already on, we reset it additionally */ if (icl->reset) - ret = icl->reset(&mt9m001->client->dev); + ret = icl->reset(&client->dev); else ret = -ENODEV; if (ret < 0) { /* Either no platform reset, or platform reset failed */ - ret = reg_write(icd, MT9M001_RESET, 1); + ret = reg_write(client, MT9M001_RESET, 1); if (!ret) - ret = reg_write(icd, MT9M001_RESET, 0); + ret = reg_write(client, MT9M001_RESET, 0); } /* Disable chip, synchronous option update */ if (!ret) - ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); + ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0); return ret; } static int mt9m001_release(struct soc_camera_device *icd) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; /* Disable the chip */ - reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); + reg_write(client, MT9M001_OUTPUT_CONTROL, 0); if (icl->power) - icl->power(&mt9m001->client->dev, 0); + icl->power(&client->dev, 0); return 0; } static int mt9m001_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Switch to master "normal" mode */ - if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0) + if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } static int mt9m001_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Stop sensor readout */ - if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0) + if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0) return -EIO; return 0; } @@ -222,28 +223,29 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd) static int mt9m001_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int ret; const u16 hblank = 9, vblank = 25; /* Blanking and start values - default... */ - ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); + ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank); if (!ret) - ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank); + ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank); /* The caller provides a supported format, as verified per * call to icd->try_fmt() */ if (!ret) - ret = reg_write(icd, MT9M001_COLUMN_START, rect->left); + ret = reg_write(client, MT9M001_COLUMN_START, rect->left); if (!ret) - ret = reg_write(icd, MT9M001_ROW_START, rect->top); + ret = reg_write(client, MT9M001_ROW_START, rect->top); if (!ret) - ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1); + ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1); if (!ret) - ret = reg_write(icd, MT9M001_WINDOW_HEIGHT, + ret = reg_write(client, MT9M001_WINDOW_HEIGHT, rect->height + icd->y_skip_top - 1); if (!ret && mt9m001->autoexposure) { - ret = reg_write(icd, MT9M001_SHUTTER_WIDTH, + ret = reg_write(client, MT9M001_SHUTTER_WIDTH, rect->height + icd->y_skip_top + vblank); if (!ret) { const struct v4l2_queryctrl *qctrl = @@ -312,16 +314,16 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd, static int mt9m001_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9m001->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; reg->size = 2; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -332,15 +334,15 @@ static int mt9m001_get_register(struct soc_camera_device *icd, static int mt9m001_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9m001->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -416,12 +418,13 @@ static struct soc_camera_ops mt9m001_ops = { static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9M001_READ_OPTIONS2); + data = reg_read(client, MT9M001_READ_OPTIONS2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x8000); @@ -435,6 +438,7 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); const struct v4l2_queryctrl *qctrl; int data; @@ -447,9 +451,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000); + data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000); else - data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000); + data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000); if (data < 0) return -EIO; break; @@ -463,7 +467,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; dev_dbg(&icd->dev, "Setting gain %d\n", data); - data = reg_write(icd, MT9M001_GLOBAL_GAIN, data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) return -EIO; } else { @@ -481,8 +485,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((gain - 64) * 7 + 28) / 56 + 96; dev_dbg(&icd->dev, "Setting gain from %d to %d\n", - reg_read(icd, MT9M001_GLOBAL_GAIN), data); - data = reg_write(icd, MT9M001_GLOBAL_GAIN, data); + reg_read(client, MT9M001_GLOBAL_GAIN), data); + data = reg_write(client, MT9M001_GLOBAL_GAIN, data); if (data < 0) return -EIO; } @@ -500,8 +504,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro range / 2) / range + 1; dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n", - reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter); - if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0) + reg_read(client, MT9M001_SHUTTER_WIDTH), shutter); + if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; mt9m001->autoexposure = 0; @@ -510,7 +514,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) { const u16 vblank = 25; - if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height + + if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); @@ -529,8 +533,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro * 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 = to_i2c_client(icd->control); struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); - struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; s32 data; int ret; unsigned long flags; @@ -542,11 +547,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Enable the chip */ - data = reg_write(icd, MT9M001_CHIP_ENABLE, 1); + data = reg_write(client, MT9M001_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); /* Read out the chip version register */ - data = reg_read(icd, MT9M001_CHIP_VERSION); + data = reg_read(client, MT9M001_CHIP_VERSION); /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */ switch (data) { @@ -604,10 +609,13 @@ ei2c: static void mt9m001_video_remove(struct soc_camera_device *icd) { struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct soc_camera_link *icl = mt9m001->client->dev.platform_data; dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr, icd->dev.parent, icd->vdev); soc_camera_video_stop(icd); + if (icl->free_bus) + icl->free_bus(icl); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c index 69498d519..77639ae5c 100644 --- a/linux/drivers/media/video/mt9m111.c +++ b/linux/drivers/media/video/mt9m111.c @@ -113,10 +113,10 @@ * mt9m111: Camera control register addresses (0x200..0x2ff not implemented) */ -#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg) -#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val)) -#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val)) -#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val)) +#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg) +#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val)) +#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val)) +#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val)) #define MT9M111_MIN_DARK_ROWS 8 #define MT9M111_MIN_DARK_COLS 24 @@ -184,58 +184,55 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg) return ret; } -static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg) +static int mt9m111_reg_read(struct i2c_client *client, const u16 reg) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct i2c_client *client = mt9m111->client; int ret; ret = reg_page_map_set(client, reg); if (!ret) ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); - dev_dbg(&icd->dev, "read reg.%03x -> %04x\n", reg, ret); + dev_dbg(&client->dev, "read reg.%03x -> %04x\n", reg, ret); return ret; } -static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_write(struct i2c_client *client, const u16 reg, const u16 data) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct i2c_client *client = mt9m111->client; int ret; ret = reg_page_map_set(client, reg); if (!ret) - ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff), + ret = i2c_smbus_write_word_data(client, (reg & 0xff), swab16(data)); - dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); + dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); return ret; } -static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_set(struct i2c_client *client, const u16 reg, const u16 data) { int ret; - ret = mt9m111_reg_read(icd, reg); + ret = mt9m111_reg_read(client, reg); if (ret >= 0) - ret = mt9m111_reg_write(icd, reg, ret | data); + ret = mt9m111_reg_write(client, reg, ret | data); return ret; } -static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg, +static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg, const u16 data) { int ret; - ret = mt9m111_reg_read(icd, reg); - return mt9m111_reg_write(icd, reg, ret & ~data); + ret = mt9m111_reg_read(client, reg); + return mt9m111_reg_write(client, reg, ret & ~data); } static int mt9m111_set_context(struct soc_camera_device *icd, enum mt9m111_context ctxt) { + struct i2c_client *client = to_i2c_client(icd->control); int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B @@ -252,6 +249,7 @@ static int mt9m111_set_context(struct soc_camera_device *icd, static int mt9m111_setup_rect(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret, is_raw_format; int width = rect->width; @@ -296,6 +294,7 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd, static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) { + struct i2c_client *client = to_i2c_client(icd->control); int ret; ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); @@ -357,12 +356,13 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) static int mt9m111_enable(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9m111->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -378,8 +378,9 @@ static int mt9m111_enable(struct soc_camera_device *icd) static int mt9m111_disable(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); @@ -387,15 +388,15 @@ static int mt9m111_disable(struct soc_camera_device *icd) mt9m111->powered = 0; if (icl->power) - icl->power(&mt9m111->client->dev, 0); + icl->power(&client->dev, 0); return ret; } static int mt9m111_reset(struct soc_camera_device *icd) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); - struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); @@ -406,7 +407,7 @@ static int mt9m111_reset(struct soc_camera_device *icd) | MT9M111_RESET_RESET_SOC); if (icl->reset) - icl->reset(&mt9m111->client->dev); + icl->reset(&client->dev); return ret; } @@ -562,15 +563,14 @@ static int mt9m111_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { int val; - - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) return -EINVAL; - if (reg->match.addr != mt9m111->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - val = mt9m111_reg_read(icd, reg->reg); + val = mt9m111_reg_read(client, reg->reg); reg->size = 2; reg->val = (u64)val; @@ -583,15 +583,15 @@ static int mt9m111_get_register(struct soc_camera_device *icd, static int mt9m111_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) return -EINVAL; - if (reg->match.addr != mt9m111->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0) + if (mt9m111_reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -672,6 +672,7 @@ static struct soc_camera_ops mt9m111_ops = { static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -692,6 +693,7 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) static int mt9m111_get_global_gain(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); int data; data = reg_read(GLOBAL_GAIN); @@ -703,6 +705,7 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd) static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) { + struct i2c_client *client = to_i2c_client(icd->control); u16 val; if (gain > 63 * 2 * 2) @@ -721,6 +724,7 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -737,6 +741,7 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int ret; @@ -754,6 +759,7 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on) static int mt9m111_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); int data; @@ -898,6 +904,7 @@ static int mt9m111_release(struct soc_camera_device *icd) */ static int mt9m111_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); s32 data; int ret; diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c index f4e597e6c..381dd0fbe 100644 --- a/linux/drivers/media/video/mt9t031.c +++ b/linux/drivers/media/video/mt9t031.c @@ -76,64 +76,61 @@ struct mt9t031 { u16 yskip; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct i2c_client *client = mt9t031->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } -static int set_shutter(struct soc_camera_device *icd, const u32 data) +static int set_shutter(struct i2c_client *client, const u32 data) { int ret; - ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); + ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16); if (ret >= 0) - ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff); + ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff); return ret; } -static int get_shutter(struct soc_camera_device *icd, u32 *data) +static int get_shutter(struct i2c_client *client, u32 *data) { int ret; - ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER); + ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER); *data = ret << 16; if (ret >= 0) - ret = reg_read(icd, MT9T031_SHUTTER_WIDTH); + ret = reg_read(client, MT9T031_SHUTTER_WIDTH); *data |= ret & 0xffff; return ret < 0 ? ret : 0; @@ -141,12 +138,12 @@ static int get_shutter(struct soc_camera_device *icd, u32 *data) static int mt9t031_init(struct soc_camera_device *icd) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct soc_camera_link *icl = mt9t031->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9t031->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -155,44 +152,48 @@ static int mt9t031_init(struct soc_camera_device *icd) } /* Disable chip output, synchronous option update */ - ret = reg_write(icd, MT9T031_RESET, 1); + ret = reg_write(client, MT9T031_RESET, 1); if (ret >= 0) - ret = reg_write(icd, MT9T031_RESET, 0); + ret = reg_write(client, MT9T031_RESET, 0); if (ret >= 0) - ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); if (ret < 0 && icl->power) - icl->power(&mt9t031->client->dev, 0); + icl->power(&client->dev, 0); return ret >= 0 ? 0 : -EIO; } static int mt9t031_release(struct soc_camera_device *icd) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); - struct soc_camera_link *icl = mt9t031->client->dev.platform_data; + struct i2c_client *client = to_i2c_client(icd->control); + struct soc_camera_link *icl = client->dev.platform_data; /* Disable the chip */ - reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2); + reg_clear(client, MT9T031_OUTPUT_CONTROL, 2); if (icl->power) - icl->power(&mt9t031->client->dev, 0); + icl->power(&client->dev, 0); return 0; } static int mt9t031_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Switch to master "normal" mode */ - if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) + if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } static int mt9t031_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); + /* Stop sensor readout */ - if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0) + if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0) return -EIO; return 0; } @@ -200,14 +201,16 @@ static int mt9t031_stop_capture(struct soc_camera_device *icd) static int mt9t031_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct i2c_client *client = to_i2c_client(icd->control); + /* The caller should have queried our parameters, check anyway */ if (flags & ~MT9T031_BUS_PARAM) return -EINVAL; if (flags & SOCAM_PCLK_SAMPLE_FALLING) - reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); else - reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); + reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000); return 0; } @@ -235,6 +238,7 @@ static void recalculate_limits(struct soc_camera_device *icd, static int mt9t031_set_params(struct soc_camera_device *icd, struct v4l2_rect *rect, u16 xskip, u16 yskip) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); int ret; u16 xbin, ybin, width, height, left, top; @@ -277,22 +281,22 @@ static int mt9t031_set_params(struct soc_camera_device *icd, } /* Disable register update, reconfigure atomically */ - ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1); + ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1); if (ret < 0) return ret; /* Blanking and start values - default... */ - ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank); + ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank); if (ret >= 0) - ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank); + ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank); if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) { /* Binning, skipping */ if (ret >= 0) - ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE, + ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE, ((xbin - 1) << 4) | (xskip - 1)); if (ret >= 0) - ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE, + ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE, ((ybin - 1) << 4) | (yskip - 1)); } dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top); @@ -300,16 +304,16 @@ static int mt9t031_set_params(struct soc_camera_device *icd, /* 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(icd, MT9T031_COLUMN_START, left); + ret = reg_write(client, MT9T031_COLUMN_START, left); if (ret >= 0) - ret = reg_write(icd, MT9T031_ROW_START, top); + ret = reg_write(client, MT9T031_ROW_START, top); if (ret >= 0) - ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1); + ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1); if (ret >= 0) - ret = reg_write(icd, MT9T031_WINDOW_HEIGHT, + ret = reg_write(client, MT9T031_WINDOW_HEIGHT, height + icd->y_skip_top - 1); if (ret >= 0 && mt9t031->autoexposure) { - ret = set_shutter(icd, height + icd->y_skip_top + vblank); + ret = set_shutter(client, height + icd->y_skip_top + vblank); if (ret >= 0) { const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; const struct v4l2_queryctrl *qctrl = @@ -324,7 +328,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd, /* Re-enable register update, commit all changes */ if (ret >= 0) - ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1); + ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1); return ret < 0 ? ret : 0; } @@ -417,15 +421,15 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd, static int mt9t031_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9t031->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -436,15 +440,15 @@ static int mt9t031_get_register(struct soc_camera_device *icd, static int mt9t031_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9t031->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -528,18 +532,19 @@ static struct soc_camera_ops mt9t031_ops = { static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9T031_READ_MODE_2); + data = reg_read(client, MT9T031_READ_MODE_2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x8000); break; case V4L2_CID_HFLIP: - data = reg_read(icd, MT9T031_READ_MODE_2); + data = reg_read(client, MT9T031_READ_MODE_2); if (data < 0) return -EIO; ctrl->value = !!(data & 0x4000); @@ -553,6 +558,7 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); const struct v4l2_queryctrl *qctrl; int data; @@ -565,17 +571,17 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000); + data = reg_set(client, MT9T031_READ_MODE_2, 0x8000); else - data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000); + data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000); if (data < 0) return -EIO; break; case V4L2_CID_HFLIP: if (ctrl->value) - data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000); + data = reg_set(client, MT9T031_READ_MODE_2, 0x4000); else - data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000); + data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000); if (data < 0) return -EIO; break; @@ -589,7 +595,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range; dev_dbg(&icd->dev, "Setting gain %d\n", data); - data = reg_write(icd, MT9T031_GLOBAL_GAIN, data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; } else { @@ -609,8 +615,8 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60; dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n", - reg_read(icd, MT9T031_GLOBAL_GAIN), data); - data = reg_write(icd, MT9T031_GLOBAL_GAIN, data); + reg_read(client, MT9T031_GLOBAL_GAIN), data); + data = reg_write(client, MT9T031_GLOBAL_GAIN, data); if (data < 0) return -EIO; } @@ -628,10 +634,10 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro range / 2) / range + 1; u32 old; - get_shutter(icd, &old); + get_shutter(client, &old); dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n", old, shutter); - if (set_shutter(icd, shutter) < 0) + if (set_shutter(client, shutter) < 0) return -EIO; icd->exposure = ctrl->value; mt9t031->autoexposure = 0; @@ -641,7 +647,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro if (ctrl->value) { const u16 vblank = MT9T031_VERTICAL_BLANK; const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank; - if (set_shutter(icd, icd->height + + if (set_shutter(client, icd->height + icd->y_skip_top + vblank) < 0) return -EIO; qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); @@ -661,6 +667,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro * this wasn't our capture interface, so, we wait for the right one */ static int mt9t031_video_probe(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd); s32 data; int ret; @@ -672,11 +679,11 @@ static int mt9t031_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Enable the chip */ - data = reg_write(icd, MT9T031_CHIP_ENABLE, 1); + data = reg_write(client, MT9T031_CHIP_ENABLE, 1); dev_dbg(&icd->dev, "write: %d\n", data); /* Read out the chip version register */ - data = reg_read(icd, MT9T031_CHIP_VERSION); + data = reg_read(client, MT9T031_CHIP_VERSION); switch (data) { case 0x1621: diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c index 3bee30caa..016bcdfcf 100644 --- a/linux/drivers/media/video/mt9v022.c +++ b/linux/drivers/media/video/mt9v022.c @@ -91,51 +91,49 @@ struct mt9v022 { u16 chip_control; }; -static int reg_read(struct soc_camera_device *icd, const u8 reg) +static int reg_read(struct i2c_client *client, const u8 reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct i2c_client *client = mt9v022->client; s32 data = i2c_smbus_read_word_data(client, reg); return data < 0 ? data : swab16(data); } -static int reg_write(struct soc_camera_device *icd, const u8 reg, +static int reg_write(struct i2c_client *client, const u8 reg, const u16 data) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data)); + return i2c_smbus_write_word_data(client, reg, swab16(data)); } -static int reg_set(struct soc_camera_device *icd, const u8 reg, +static int reg_set(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret | data); + return reg_write(client, reg, ret | data); } -static int reg_clear(struct soc_camera_device *icd, const u8 reg, +static int reg_clear(struct i2c_client *client, const u8 reg, const u16 data) { int ret; - ret = reg_read(icd, reg); + ret = reg_read(client, reg); if (ret < 0) return ret; - return reg_write(icd, reg, ret & ~data); + return reg_write(client, reg, ret & ~data); } static int mt9v022_init(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; int ret; if (icl->power) { - ret = icl->power(&mt9v022->client->dev, 1); + ret = icl->power(&client->dev, 1); if (ret < 0) { dev_err(icd->vdev->parent, "Platform failed to power-on the camera.\n"); @@ -148,27 +146,27 @@ static int mt9v022_init(struct soc_camera_device *icd) * if available. Soft reset is done in video_probe(). */ if (icl->reset) - icl->reset(&mt9v022->client->dev); + icl->reset(&client->dev); /* 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 */ mt9v022->chip_control |= 0x10; - ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (!ret) - ret = reg_write(icd, MT9V022_READ_MODE, 0x300); + ret = reg_write(client, MT9V022_READ_MODE, 0x300); /* All defaults */ if (!ret) /* AEC, AGC on */ - ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3); + ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3); if (!ret) - ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); if (!ret) /* default - auto */ - ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); + ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); if (!ret) - ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0); + ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0); return ret; } @@ -186,10 +184,11 @@ static int mt9v022_release(struct soc_camera_device *icd) static int mt9v022_start_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); /* Switch to master "normal" mode */ mt9v022->chip_control &= ~0x10; - if (reg_write(icd, MT9V022_CHIP_CONTROL, + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; return 0; @@ -197,10 +196,11 @@ static int mt9v022_start_capture(struct soc_camera_device *icd) static int mt9v022_stop_capture(struct soc_camera_device *icd) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); /* Switch to snapshot mode */ mt9v022->chip_control |= 0x10; - if (reg_write(icd, MT9V022_CHIP_CONTROL, + if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; return 0; @@ -209,8 +209,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd) static int mt9v022_set_bus_param(struct soc_camera_device *icd, unsigned long flags) { + struct i2c_client *client = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK; int ret; u16 pixclk = 0; @@ -243,14 +244,14 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd, if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH)) pixclk |= 0x2; - ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk); + ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk); if (ret < 0) return ret; if (!(flags & SOCAM_MASTER)) mt9v022->chip_control &= ~0x8; - ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control); + ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control); if (ret < 0) return ret; @@ -282,35 +283,36 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd) static int mt9v022_set_crop(struct soc_camera_device *icd, struct v4l2_rect *rect) { + struct i2c_client *client = to_i2c_client(icd->control); int ret; /* Like in example app. Contradicts the datasheet though */ - ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + ret = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (ret >= 0) { if (ret & 1) /* Autoexposure */ - ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, + ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, rect->height + icd->y_skip_top + 43); else - ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH, + ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, rect->height + icd->y_skip_top + 43); } /* Setup frame format: defaults apart from width and height */ if (!ret) - ret = reg_write(icd, MT9V022_COLUMN_START, rect->left); + ret = reg_write(client, MT9V022_COLUMN_START, rect->left); if (!ret) - ret = reg_write(icd, MT9V022_ROW_START, rect->top); + ret = reg_write(client, MT9V022_ROW_START, rect->top); if (!ret) /* Default 94, Phytec driver says: * "width + horizontal blank >= 660" */ - ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING, + ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, rect->width > 660 - 43 ? 43 : 660 - rect->width); if (!ret) - ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45); + ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); if (!ret) - ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width); + ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width); if (!ret) - ret = reg_write(icd, MT9V022_WINDOW_HEIGHT, + ret = reg_write(client, MT9V022_WINDOW_HEIGHT, rect->height + icd->y_skip_top); if (ret < 0) @@ -396,16 +398,16 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd, static int mt9v022_get_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9v022->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; reg->size = 2; - reg->val = reg_read(icd, reg->reg); + reg->val = reg_read(client, reg->reg); if (reg->val > 0xffff) return -EIO; @@ -416,15 +418,15 @@ static int mt9v022_get_register(struct soc_camera_device *icd, static int mt9v022_set_register(struct soc_camera_device *icd, struct v4l2_dbg_register *reg) { - struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct i2c_client *client = to_i2c_client(icd->control); if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff) return -EINVAL; - if (reg->match.addr != mt9v022->client->addr) + if (reg->match.addr != client->addr) return -ENODEV; - if (reg_write(icd, reg->reg, reg->val) < 0) + if (reg_write(client, reg->reg, reg->val) < 0) return -EIO; return 0; @@ -517,29 +519,30 @@ static struct soc_camera_ops mt9v022_ops = { static int mt9v022_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { + struct i2c_client *client = to_i2c_client(icd->control); int data; switch (ctrl->id) { case V4L2_CID_VFLIP: - data = reg_read(icd, MT9V022_READ_MODE); + data = reg_read(client, MT9V022_READ_MODE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x10); break; case V4L2_CID_HFLIP: - data = reg_read(icd, MT9V022_READ_MODE); + data = reg_read(client, MT9V022_READ_MODE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x20); break; case V4L2_CID_EXPOSURE_AUTO: - data = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x1); break; case V4L2_CID_AUTOGAIN: - data = reg_read(icd, MT9V022_AEC_AGC_ENABLE); + data = reg_read(client, MT9V022_AEC_AGC_ENABLE); if (data < 0) return -EIO; ctrl->value = !!(data & 0x2); @@ -552,6 +555,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl) { int data; + struct i2c_client *client = to_i2c_client(icd->control); const struct v4l2_queryctrl *qctrl; qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id); @@ -562,17 +566,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd, switch (ctrl->id) { case V4L2_CID_VFLIP: if (ctrl->value) - data = reg_set(icd, MT9V022_READ_MODE, 0x10); + data = reg_set(client, MT9V022_READ_MODE, 0x10); else - data = reg_clear(icd, MT9V022_READ_MODE, 0x10); + data = reg_clear(client, MT9V022_READ_MODE, 0x10); if (data < 0) return -EIO; break; case V4L2_CID_HFLIP: if (ctrl->value) - data = reg_set(icd, MT9V022_READ_MODE, 0x20); + data = reg_set(client, MT9V022_READ_MODE, 0x20); else - data = reg_clear(icd, MT9V022_READ_MODE, 0x20); + data = reg_clear(client, MT9V022_READ_MODE, 0x20); if (data < 0) return -EIO; break; @@ -593,12 +597,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd, /* The user wants to set gain manually, hope, she * knows, what she's doing... Switch AGC off. */ - if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0) return -EIO; dev_info(&icd->dev, "Setting gain from %d to %lu\n", - reg_read(icd, MT9V022_ANALOG_GAIN), gain); - if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0) + reg_read(client, MT9V022_ANALOG_GAIN), gain); + if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0) return -EIO; icd->gain = ctrl->value; } @@ -614,13 +618,13 @@ static int mt9v022_set_control(struct soc_camera_device *icd, /* The user wants to set shutter width manually, hope, * she knows, what she's doing... Switch AEC off. */ - if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) + if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0) return -EIO; dev_dbg(&icd->dev, "Shutter width from %d to %lu\n", - reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH), + reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH), shutter); - if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH, + if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, shutter) < 0) return -EIO; icd->exposure = ctrl->value; @@ -628,17 +632,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd, break; case V4L2_CID_AUTOGAIN: if (ctrl->value) - data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2); + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2); else - data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2); + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2); if (data < 0) return -EIO; break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->value) - data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1); + data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1); else - data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1); + data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1); if (data < 0) return -EIO; break; @@ -650,8 +654,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd, * 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 = to_i2c_client(icd->control); struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); - struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + struct soc_camera_link *icl = client->dev.platform_data; s32 data; int ret; unsigned long flags; @@ -661,7 +666,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) return -ENODEV; /* Read out the chip version register */ - data = reg_read(icd, MT9V022_CHIP_VERSION); + data = reg_read(client, MT9V022_CHIP_VERSION); /* must be 0x1311 or 0x1313 */ if (data != 0x1311 && data != 0x1313) { @@ -672,12 +677,12 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) } /* Soft reset */ - ret = reg_write(icd, MT9V022_RESET, 1); + ret = reg_write(client, MT9V022_RESET, 1); if (ret < 0) goto ei2c; /* 15 clock cycles */ udelay(200); - if (reg_read(icd, MT9V022_RESET)) { + if (reg_read(client, MT9V022_RESET)) { dev_err(&icd->dev, "Resetting MT9V022 failed!\n"); goto ei2c; } @@ -685,11 +690,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) /* Set monochrome or colour sensor type */ if (sensor_type && (!strcmp("colour", sensor_type) || !strcmp("color", sensor_type))) { - ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATC; icd->formats = mt9v022_colour_formats; } else { - ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11); + ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11); mt9v022->model = V4L2_IDENT_MT9V022IX7ATM; icd->formats = mt9v022_monochrome_formats; } @@ -735,10 +740,13 @@ ei2c: static void mt9v022_video_remove(struct soc_camera_device *icd) { struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct soc_camera_link *icl = mt9v022->client->dev.platform_data; dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr, icd->dev.parent, icd->vdev); soc_camera_video_stop(icd); + if (icl->free_bus) + icl->free_bus(icl); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) diff --git a/linux/drivers/media/video/mx1_camera.c b/linux/drivers/media/video/mx1_camera.c index 86fab56c5..2d075205b 100644 --- a/linux/drivers/media/video/mx1_camera.c +++ b/linux/drivers/media/video/mx1_camera.c @@ -102,10 +102,10 @@ struct mx1_buffer { * Interface. If anyone ever builds hardware to enable more than * 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; struct mx1_camera_pdata *pdata; struct mx1_buffer *active; - struct device *dev; struct resource *res; struct clk *clk; struct list_head capture; @@ -219,7 +219,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) int ret; if (unlikely(!pcdev->active)) { - dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n"); + dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); return -EFAULT; } @@ -229,7 +229,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev) vbuf->size, pcdev->res->start + CSIRXR, DMA_MODE_READ); if (unlikely(ret)) - dev_err(pcdev->dev, "Failed to setup DMA sg list\n"); + dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n"); return ret; } @@ -338,14 +338,14 @@ static void mx1_camera_dma_irq(int channel, void *data) imx_dma_disable(channel); if (unlikely(!pcdev->active)) { - dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n"); + dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n"); goto out; } vb = &pcdev->active->vb; buf = container_of(vb, struct mx1_buffer, vb); WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, + dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb, vb->baddr, vb->bsize); mx1_camera_wakeup(pcdev, vb, buf); @@ -366,7 +366,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx1_camera_dev *pcdev = ici->priv; - videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, pcdev->dev, + videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, @@ -385,7 +385,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev) * they get a nice Oops */ div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; - dev_dbg(pcdev->dev, "System clock %lukHz, target freq %dkHz, " + dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, " "divisor %lu\n", lcdclk / 1000, mclk / 1000, div); return div; @@ -395,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) { unsigned int csicr1 = CSICR1_EN; - dev_dbg(pcdev->dev, "Activate device\n"); + dev_dbg(pcdev->soc_host.dev, "Activate device\n"); clk_enable(pcdev->clk); @@ -411,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev) static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev) { - dev_dbg(pcdev->dev, "Deactivate device\n"); + dev_dbg(pcdev->soc_host.dev, "Deactivate device\n"); /* Disable all CSI interface */ __raw_writel(0x00, pcdev->base + CSICR1); @@ -550,7 +550,7 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -633,12 +633,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = { .querycap = mx1_camera_querycap, }; -/* Should be allocated dynamically too, but we have only one. */ -static struct soc_camera_host mx1_soc_camera_host = { - .drv_name = DRIVER_NAME, - .ops = &mx1_soc_camera_host_ops, -}; - static struct fiq_handler fh = { .name = "csi_sof" }; @@ -673,7 +667,6 @@ static int __init mx1_camera_probe(struct platform_device *pdev) goto exit_put_clk; } - dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->clk = clk; @@ -707,16 +700,15 @@ static int __init mx1_camera_probe(struct platform_device *pdev) } pcdev->irq = irq; pcdev->base = base; - pcdev->dev = &pdev->dev; /* request dma */ pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH); if (pcdev->dma_chan < 0) { - dev_err(pcdev->dev, "Can't request DMA for MX1 CSI\n"); + dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n"); err = -EBUSY; goto exit_iounmap; } - dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan); + dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan); imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL, pcdev); @@ -729,7 +721,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev) /* request irq */ err = claim_fiq(&fh); if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); + dev_err(&pdev->dev, "Camera interrupt register failed \n"); goto exit_free_dma; } @@ -746,10 +738,12 @@ static int __init mx1_camera_probe(struct platform_device *pdev) mxc_set_irq_fiq(irq, 1); enable_fiq(irq); - mx1_soc_camera_host.priv = pcdev; - mx1_soc_camera_host.dev.parent = &pdev->dev; - mx1_soc_camera_host.nr = pdev->id; - err = soc_camera_host_register(&mx1_soc_camera_host); + pcdev->soc_host.drv_name = DRIVER_NAME; + pcdev->soc_host.ops = &mx1_soc_camera_host_ops; + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + err = soc_camera_host_register(&pcdev->soc_host); if (err) goto exit_free_irq; @@ -777,7 +771,9 @@ exit: static int __exit mx1_camera_remove(struct platform_device *pdev) { - struct mx1_camera_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx1_camera_dev *pcdev = container_of(soc_host, + struct mx1_camera_dev, soc_host); struct resource *res; imx_dma_free(pcdev->dma_chan); @@ -787,7 +783,7 @@ static int __exit mx1_camera_remove(struct platform_device *pdev) clk_put(pcdev->clk); - soc_camera_host_unregister(&mx1_soc_camera_host); + soc_camera_host_unregister(soc_host); iounmap(pcdev->base); diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c index c462b811e..4d47eeb14 100644 --- a/linux/drivers/media/video/mx3_camera.c +++ b/linux/drivers/media/video/mx3_camera.c @@ -87,7 +87,6 @@ struct mx3_camera_buffer { * @soc_host: embedded soc_host object */ struct mx3_camera_dev { - struct device *dev; /* * i.MX3x is only supposed to handle one camera on its Camera Sensor * Interface. If anyone ever builds hardware to enable more than one @@ -431,7 +430,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q, struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct mx3_camera_dev *mx3_cam = ici->priv; - videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev, + videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev, &mx3_cam->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE, @@ -599,7 +598,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam, *flags |= SOCAM_DATAWIDTH_4; break; default: - dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth); + dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n", + buswidth); return -EINVAL; } @@ -614,7 +614,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd, unsigned long bus_flags, camera_flags; int ret = test_platform_param(mx3_cam, depth, &bus_flags); - dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret); + dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret); if (ret < 0) return ret; @@ -637,7 +637,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg) if (!rq) return false; - pdata = rq->mx3_cam->dev->platform_data; + pdata = rq->mx3_cam->soc_host.dev->platform_data; return rq->id == chan->chan_id && pdata->dma_dev == chan->device->dev; @@ -697,7 +697,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", mx3_camera_formats[0].name, icd->formats[idx].name); } @@ -709,7 +709,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", mx3_camera_formats[0].name, icd->formats[idx].name); } @@ -722,7 +722,7 @@ passthrough: xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -829,7 +829,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -866,7 +866,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (pixfmt && !xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -933,11 +933,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } - dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", + dev_dbg(ici->dev, "requested bus width %d bit: %d\n", icd->buswidth, ret); if (ret < 0) @@ -947,7 +947,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags); if (!common_flags) { - dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n", + dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n", camera_flags, bus_flags); return -EINVAL; } @@ -1054,7 +1054,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt) csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF); - dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); + dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw); return 0; } @@ -1063,10 +1063,6 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = { .owner = THIS_MODULE, .add = mx3_camera_add_device, .remove = mx3_camera_remove_device, -#ifdef CONFIG_PM - .suspend = mx3_camera_suspend, - .resume = mx3_camera_resume, -#endif .set_crop = mx3_camera_set_crop, .set_fmt = mx3_camera_set_fmt, .try_fmt = mx3_camera_try_fmt, @@ -1106,8 +1102,6 @@ static int mx3_camera_probe(struct platform_device *pdev) goto eclkget; } - dev_set_drvdata(&pdev->dev, mx3_cam); - mx3_cam->pdata = pdev->dev.platform_data; mx3_cam->platform_flags = mx3_cam->pdata->flags; if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 | @@ -1139,14 +1133,14 @@ static int mx3_camera_probe(struct platform_device *pdev) } mx3_cam->base = base; - mx3_cam->dev = &pdev->dev; soc_host = &mx3_cam->soc_host; soc_host->drv_name = MX3_CAM_DRV_NAME; soc_host->ops = &mx3_soc_camera_host_ops; soc_host->priv = mx3_cam; - soc_host->dev.parent = &pdev->dev; + soc_host->dev = &pdev->dev; soc_host->nr = pdev->id; + err = soc_camera_host_register(soc_host); if (err) goto ecamhostreg; @@ -1169,11 +1163,13 @@ egetres: static int __devexit mx3_camera_remove(struct platform_device *pdev) { - struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct mx3_camera_dev *mx3_cam = container_of(soc_host, + struct mx3_camera_dev, soc_host); clk_put(mx3_cam->clk); - soc_camera_host_unregister(&mx3_cam->soc_host); + soc_camera_host_unregister(soc_host); iounmap(mx3_cam->base); diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index cb4491338..35642c430 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -214,7 +214,7 @@ struct pxa_buffer { }; struct pxa_camera_dev { - struct device *dev; + struct soc_camera_host soc_host; /* 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 */ @@ -273,7 +273,6 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) { struct soc_camera_device *icd = vq->priv_data; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct pxa_camera_dev *pcdev = ici->priv; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int i; @@ -290,7 +289,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf) for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) { if (buf->dmas[i].sg_cpu) - dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size, + dma_free_coherent(ici->dev, buf->dmas[i].sg_size, buf->dmas[i].sg_cpu, buf->dmas[i].sg_dma); buf->dmas[i].sg_cpu = NULL; @@ -350,14 +349,14 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, int dma_len = 0, xfer_len = 0; if (pxa_dma->sg_cpu) - dma_free_coherent(pcdev->dev, pxa_dma->sg_size, + dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, pxa_dma->sg_cpu, pxa_dma->sg_dma); sglen = calculate_dma_sglen(*sg_first, dma->sglen, *sg_first_ofs, size); pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc); - pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size, + pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size, &pxa_dma->sg_dma, GFP_KERNEL); if (!pxa_dma->sg_cpu) return -ENOMEM; @@ -365,7 +364,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, pxa_dma->sglen = sglen; offset = *sg_first_ofs; - dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", + dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n", *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma); @@ -388,7 +387,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, pxa_dma->sg_cpu[i].ddadr = pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc); - dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", + dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n", pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc), sg_dma_address(sg) + offset, xfer_len); offset = 0; @@ -500,7 +499,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for Y/RGB failed\n"); goto fail; } @@ -510,7 +509,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1, size_u, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for U failed\n"); goto fail_u; } @@ -520,7 +519,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2, size_v, &sg, &next_ofs); if (ret) { - dev_err(pcdev->dev, + dev_err(pcdev->soc_host.dev, "DMA initialization for V failed\n"); goto fail_v; } @@ -534,10 +533,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq, return 0; fail_v: - dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size, + dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size, buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma); fail_u: - dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size, + dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size, buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma); fail: free_buffer(vq, buf); @@ -561,7 +560,7 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) active = pcdev->active; for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__, + dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__, i, active->dmas[i].sg_dma); DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma; DCSR(pcdev->dma_chans[i]) = DCSR_RUN; @@ -573,7 +572,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) int i; for (i = 0; i < pcdev->channels; i++) { - dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i); + dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i); DCSR(pcdev->dma_chans[i]) = 0; } } @@ -609,7 +608,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) { unsigned long cicr0, cifr; - dev_dbg(pcdev->dev, "%s\n", __func__); + dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); /* Reset the FIFOs */ cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; __raw_writel(cifr, pcdev->base + CIFR); @@ -629,7 +628,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) __raw_writel(cicr0, pcdev->base + CICR0); pcdev->active = NULL; - dev_dbg(pcdev->dev, "%s\n", __func__); + dev_dbg(pcdev->soc_host.dev, "%s\n", __func__); } static void pxa_videobuf_queue(struct videobuf_queue *vq, @@ -698,7 +697,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, do_gettimeofday(&vb->ts); vb->field_count++; wake_up(&vb->done); - dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); + dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb); if (list_empty(&pcdev->capture)) { pxa_camera_stop_capture(pcdev); @@ -734,7 +733,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev) for (i = 0; i < pcdev->channels; i++) if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP) is_dma_stopped = 0; - dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n", + dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n", __func__, pcdev->active, is_dma_stopped); if (pcdev->active && is_dma_stopped) pxa_camera_start_capture(pcdev); @@ -759,12 +758,12 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, overrun |= CISR_IFO_1 | CISR_IFO_2; if (status & DCSR_BUSERR) { - dev_err(pcdev->dev, "DMA Bus Error IRQ!\n"); + dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n"); goto out; } if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) { - dev_err(pcdev->dev, "Unknown DMA IRQ source, " + dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, " "status: 0x%08x\n", status); goto out; } @@ -788,7 +787,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, buf = container_of(vb, struct pxa_buffer, vb); WARN_ON(buf->inwork || list_empty(&vb->queue)); - dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", + dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n", __func__, channel, status & DCSR_STARTINTR ? "SOF " : "", status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel)); @@ -799,7 +798,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev, */ if (camera_status & overrun && !list_is_last(pcdev->capture.next, &pcdev->capture)) { - dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", + dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n", camera_status); pxa_camera_stop_capture(pcdev); pxa_camera_start_capture(pcdev); @@ -866,7 +865,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) /* mclk <= ciclk / 4 (27.4.2) */ if (mclk > lcdclk / 4) { mclk = lcdclk / 4; - dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk); + dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk); } /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ @@ -876,7 +875,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev) if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) pcdev->mclk = lcdclk / (2 * (div + 1)); - dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, " + dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, " "divisor %u\n", lcdclk, mclk, div); return div; @@ -896,12 +895,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) struct pxacamera_platform_data *pdata = pcdev->pdata; u32 cicr4 = 0; - dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n", + dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n", pcdev, pdata); if (pdata && pdata->init) { - dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__); - pdata->init(pcdev->dev); + dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__); + pdata->init(pcdev->soc_host.dev); } /* disable all interrupts */ @@ -943,7 +942,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) struct videobuf_buffer *vb; status = __raw_readl(pcdev->base + CISR); - dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status); + dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status); if (!status) return IRQ_NONE; @@ -1271,7 +1270,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", pxa_camera_formats[0].name, icd->formats[idx].name); } @@ -1286,7 +1285,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = buswidth; xlate++; - dev_dbg(&ici->dev, "Providing format %s packed\n", + dev_dbg(ici->dev, "Providing format %s packed\n", icd->formats[idx].name); } break; @@ -1298,7 +1297,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -1327,11 +1326,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, icd->sense = NULL; if (ret < 0) { - dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n", + dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n", rect->width, rect->height, rect->left, rect->top); } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(&ici->dev, + dev_err(ici->dev, "pixel clock %lu set by the camera too high!", sense.pixel_clock); return -EIO; @@ -1359,7 +1358,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); + dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat); return -EINVAL; } @@ -1375,11 +1374,11 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, icd->sense = NULL; if (ret < 0) { - dev_warn(&ici->dev, "Failed to configure for format %x\n", + dev_warn(ici->dev, "Failed to configure for format %x\n", pix->pixelformat); } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { - dev_err(&ici->dev, + dev_err(ici->dev, "pixel clock %lu set by the camera too high!", sense.pixel_clock); return -EIO; @@ -1407,7 +1406,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -1564,12 +1563,6 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .set_bus_param = pxa_camera_set_bus_param, }; -/* Should be allocated dynamically too, but we have only one. */ -static struct soc_camera_host pxa_soc_camera_host = { - .drv_name = PXA_CAM_DRV_NAME, - .ops = &pxa_soc_camera_host_ops, -}; - static int pxa_camera_probe(struct platform_device *pdev) { struct pxa_camera_dev *pcdev; @@ -1598,7 +1591,6 @@ static int pxa_camera_probe(struct platform_device *pdev) goto exit_kfree; } - dev_set_drvdata(&pdev->dev, pcdev); pcdev->res = res; pcdev->pdata = pdev->dev.platform_data; @@ -1619,7 +1611,6 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->mclk = 20000000; } - pcdev->dev = &pdev->dev; pcdev->mclk_divisor = mclk_get_divisor(pcdev); INIT_LIST_HEAD(&pcdev->capture); @@ -1628,13 +1619,13 @@ static int pxa_camera_probe(struct platform_device *pdev) /* * Request the regions. */ - if (!request_mem_region(res->start, res->end - res->start + 1, + if (!request_mem_region(res->start, resource_size(res), PXA_CAM_DRV_NAME)) { err = -EBUSY; goto exit_clk; } - base = ioremap(res->start, res->end - res->start + 1); + base = ioremap(res->start, resource_size(res)); if (!base) { err = -ENOMEM; goto exit_release; @@ -1646,29 +1637,29 @@ static int pxa_camera_probe(struct platform_device *pdev) err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH, pxa_camera_dma_irq_y, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for Y\n"); + dev_err(&pdev->dev, "Can't request DMA for Y\n"); goto exit_iounmap; } pcdev->dma_chans[0] = err; - dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); + dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]); err = pxa_request_dma("CI_U", DMA_PRIO_HIGH, pxa_camera_dma_irq_u, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for U\n"); + dev_err(&pdev->dev, "Can't request DMA for U\n"); goto exit_free_dma_y; } pcdev->dma_chans[1] = err; - dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); + dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]); err = pxa_request_dma("CI_V", DMA_PRIO_HIGH, pxa_camera_dma_irq_v, pcdev); if (err < 0) { - dev_err(pcdev->dev, "Can't request DMA for V\n"); + dev_err(&pdev->dev, "Can't request DMA for V\n"); goto exit_free_dma_u; } pcdev->dma_chans[2] = err; - dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); + dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; @@ -1678,14 +1669,17 @@ static int pxa_camera_probe(struct platform_device *pdev) err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, pcdev); if (err) { - dev_err(pcdev->dev, "Camera interrupt register failed \n"); + dev_err(&pdev->dev, "Camera interrupt register failed \n"); goto exit_free_dma; } - pxa_soc_camera_host.priv = pcdev; - pxa_soc_camera_host.dev.parent = &pdev->dev; - pxa_soc_camera_host.nr = pdev->id; - err = soc_camera_host_register(&pxa_soc_camera_host); + pcdev->soc_host.drv_name = PXA_CAM_DRV_NAME; + pcdev->soc_host.ops = &pxa_soc_camera_host_ops; + pcdev->soc_host.priv = pcdev; + pcdev->soc_host.dev = &pdev->dev; + pcdev->soc_host.nr = pdev->id; + + err = soc_camera_host_register(&pcdev->soc_host); if (err) goto exit_free_irq; @@ -1702,7 +1696,7 @@ exit_free_dma_y: exit_iounmap: iounmap(base); exit_release: - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); exit_clk: clk_put(pcdev->clk); exit_kfree: @@ -1713,7 +1707,9 @@ exit: static int __devexit pxa_camera_remove(struct platform_device *pdev) { - struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct pxa_camera_dev *pcdev = container_of(soc_host, + struct pxa_camera_dev, soc_host); struct resource *res; clk_put(pcdev->clk); @@ -1723,12 +1719,12 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev) pxa_free_dma(pcdev->dma_chans[2]); free_irq(pcdev->irq, pcdev); - soc_camera_host_unregister(&pxa_soc_camera_host); + soc_camera_host_unregister(soc_host); iounmap(pcdev->base); res = pcdev->res; - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); kfree(pcdev); diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 0fac6af08..12ced841e 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -78,6 +78,8 @@ #define MAX_CHANNELS 4 #define S2255_MARKER_FRAME 0x2255DA4AL #define S2255_MARKER_RESPONSE 0x2255ACACL +#define S2255_RESPONSE_SETMODE 0x01 +#define S2255_RESPONSE_FW 0x10 #define S2255_USB_XFER_SIZE (16 * 1024) #define MAX_CHANNELS 4 #define MAX_PIPE_BUFFERS 1 @@ -179,9 +181,6 @@ struct s2255_bufferi { struct s2255_dmaqueue { struct list_head active; - /* thread for acquisition */ - struct task_struct *kthread; - int frame; struct s2255_dev *dev; int channel; }; @@ -211,16 +210,11 @@ struct s2255_pipeinfo { u32 max_transfer_size; u32 cur_transfer_size; u8 *transfer_buffer; - u32 transfer_flags;; u32 state; - u32 prev_state; - u32 urb_size; void *stream_urb; void *dev; /* back pointer to s2255_dev struct*/ u32 err_count; - u32 buf_index; u32 idx; - u32 priority_set; }; struct s2255_fmt; /*forward declaration */ @@ -240,8 +234,6 @@ struct s2255_dev { struct list_head s2255_devlist; struct timer_list timer; struct s2255_fw *fw_data; - int board_num; - int is_open; struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; struct s2255_bufferi buffer[MAX_CHANNELS]; struct s2255_mode mode[MAX_CHANNELS]; @@ -298,9 +290,10 @@ struct s2255_fh { int resources[MAX_CHANNELS]; }; -#define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ +/* current cypress EEPROM firmware version */ +#define S2255_CUR_USB_FWVER ((3 << 8) | 6) #define S2255_MAJOR_VERSION 1 -#define S2255_MINOR_VERSION 13 +#define S2255_MINOR_VERSION 14 #define S2255_RELEASE 0 #define S2255_VERSION KERNEL_VERSION(S2255_MAJOR_VERSION, \ S2255_MINOR_VERSION, \ @@ -1819,7 +1812,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) INIT_LIST_HEAD(&dev->vidq[i].active); dev->vidq[i].dev = dev; dev->vidq[i].channel = i; - dev->vidq[i].kthread = NULL; /* register 4 video devices */ dev->vdev[i] = video_device_alloc(); memcpy(dev->vdev[i], &template, sizeof(struct video_device)); @@ -1840,7 +1832,9 @@ static int s2255_probe_v4l(struct s2255_dev *dev) return ret; } } - printk(KERN_INFO "Sensoray 2255 V4L driver\n"); + printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n", + S2255_MAJOR_VERSION, + S2255_MINOR_VERSION); return ret; } @@ -1930,14 +1924,14 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if (!(cc >= 0 && cc < MAX_CHANNELS)) break; switch (pdword[2]) { - case 0x01: + case S2255_RESPONSE_SETMODE: /* check if channel valid */ /* set mode ready */ dev->setmode_ready[cc] = 1; wake_up(&dev->wait_setmode[cc]); dprintk(5, "setmode ready %d\n", cc); break; - case 0x10: + case S2255_RESPONSE_FW: dev->chn_ready |= (1 << cc); if ((dev->chn_ready & 0x0f) != 0x0f) @@ -2173,10 +2167,15 @@ static int s2255_board_init(struct s2255_dev *dev) /* query the firmware */ fw_ver = s2255_get_fx2fw(dev); - printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver); - if (fw_ver < CUR_USB_FWVER) + printk(KERN_INFO "2255 usb firmware version %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); + + if (fw_ver < S2255_CUR_USB_FWVER) dev_err(&dev->udev->dev, - "usb firmware not up to date %d\n", fw_ver); + "usb firmware not up to date %d.%d\n", + (fw_ver >> 8) & 0xff, + fw_ver & 0xff); for (j = 0; j < MAX_CHANNELS; j++) { dev->b_acquire[j] = 0; @@ -2284,8 +2283,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) for (i = 0; i < MAX_PIPE_BUFFERS; i++) { pipe_info->state = 1; - pipe_info->buf_index = (u32) i; - pipe_info->priority_set = 0; + pipe_info->err_count = 0; pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL); if (!pipe_info->stream_urb) { dev_err(&dev->udev->dev, @@ -2299,7 +2297,6 @@ static int s2255_start_readpipe(struct s2255_dev *dev) pipe_info->cur_transfer_size, read_pipe_completion, pipe_info); - pipe_info->urb_size = sizeof(pipe_info->stream_urb); dprintk(4, "submitting URB %p\n", pipe_info->stream_urb); retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL); if (retval) { @@ -2404,8 +2401,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) if (pipe_info->state == 0) continue; pipe_info->state = 0; - pipe_info->prev_state = 1; - } } @@ -2543,7 +2538,9 @@ static int s2255_probe(struct usb_interface *interface, s2255_probe_v4l(dev); usb_reset_device(dev->udev); /* load 2255 board specific */ - s2255_board_init(dev); + retval = s2255_board_init(dev); + if (retval) + goto error; dprintk(4, "before probe done %p\n", dev); spin_lock_init(&dev->slock); diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index eca83a3e0..582a56c07 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -4078,7 +4078,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_BEHOLD_505FM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov <d.belimov@gmail.com> */ - .name = "Beholder BeholdTV 505 FM/RDS", + .name = "Beholder BeholdTV 505 FM", .audio_clock = 0x00200000, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, @@ -4091,6 +4091,40 @@ struct saa7134_board saa7134_boards[] = { .vmux = 3, .amux = LINE2, .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_505RDS] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV 505 RDS", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = LINE2, + .tv = 1, },{ .name = name_comp1, .vmux = 1, @@ -4112,7 +4146,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_BEHOLD_507_9FM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov <d.belimov@gmail.com> */ - .name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM", + .name = "Beholder BeholdTV 507 FM / BeholdTV 509 FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, @@ -4139,6 +4173,66 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE2, }, }, + [SAA7134_BOARD_BEHOLD_507RDS_MK5] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV 507 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_507RDS_MK3] = { + /* Beholder Intl. Ltd. 2008 */ + /*Dmitry Belimov <d.belimov@gmail.com> */ + .name = "Beholder BeholdTV 507 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x00008000, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = { /* Beholder Intl. Ltd. 2008 */ /*Dmitry Belimov <d.belimov@gmail.com> */ @@ -4173,9 +4267,37 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x000A8000, }, }, - [SAA7134_BOARD_BEHOLD_607_9FM] = { + [SAA7134_BOARD_BEHOLD_607FM_MK3] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 607 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_609FM_MK3] = { /* Andrey Melnikoff <temnota@kmv.ru> */ - .name = "Beholder BeholdTV 607 / BeholdTV 609", + .name = "Beholder BeholdTV 609 FM", .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, .radio_type = UNSET, @@ -4187,6 +4309,174 @@ struct saa7134_board saa7134_boards[] = { .vmux = 3, .amux = TV, .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_607FM_MK5] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 607 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_609FM_MK5] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 609 FM", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_607RDS_MK3] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 607 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_609RDS_MK3] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 609 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_607RDS_MK5] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 607 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + }, + [SAA7134_BOARD_BEHOLD_609RDS_MK5] = { + /* Andrey Melnikoff <temnota@kmv.ru> */ + .name = "Beholder BeholdTV 609 RDS", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, },{ .name = name_comp1, .vmux = 1, @@ -4281,8 +4571,7 @@ struct saa7134_board saa7134_boards[] = { /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */ .name = "Beholder BeholdTV M6 Extra", .audio_clock = 0x00187de7, - /* FIXME: Must be PHILIPS_FM1216ME_MK5*/ - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */ .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -5770,14 +6059,8 @@ struct pci_device_id saa7134_pci_tbl[] = { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, + .driver_data = SAA7134_BOARD_BEHOLD_505RDS, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, @@ -5789,13 +6072,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0000, .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x0000, .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5819,49 +6102,49 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = 0x5ace, .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x5ace, .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_607_9FM, + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -6325,7 +6608,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_407FM: case SAA7134_BOARD_BEHOLD_409: case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_505RDS: case SAA7134_BOARD_BEHOLD_507_9FM: + case SAA7134_BOARD_BEHOLD_507RDS_MK3: + case SAA7134_BOARD_BEHOLD_507RDS_MK5: case SAA7134_BOARD_GENIUS_TVGO_A11MCE: case SAA7134_BOARD_REAL_ANGEL_220: case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: @@ -6450,7 +6736,14 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_UPMOST_PURPLE_TV: case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: case SAA7134_BOARD_HAUPPAUGE_HVR1110: - case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_607FM_MK3: + case SAA7134_BOARD_BEHOLD_607FM_MK5: + case SAA7134_BOARD_BEHOLD_609FM_MK3: + case SAA7134_BOARD_BEHOLD_609FM_MK5: + case SAA7134_BOARD_BEHOLD_607RDS_MK3: + case SAA7134_BOARD_BEHOLD_607RDS_MK5: + case SAA7134_BOARD_BEHOLD_609RDS_MK3: + case SAA7134_BOARD_BEHOLD_609RDS_MK5: case SAA7134_BOARD_BEHOLD_M6: case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index 87dc1b9bb..80a4cc23d 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -507,7 +507,10 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_407FM: case SAA7134_BOARD_BEHOLD_409: case SAA7134_BOARD_BEHOLD_505FM: + case SAA7134_BOARD_BEHOLD_505RDS: case SAA7134_BOARD_BEHOLD_507_9FM: + case SAA7134_BOARD_BEHOLD_507RDS_MK3: + case SAA7134_BOARD_BEHOLD_507RDS_MK5: ir_codes = ir_codes_manli; mask_keycode = 0x003f00; mask_keyup = 0x004000; @@ -718,7 +721,14 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) ir->get_key = get_key_hvr1110; ir->ir_codes = ir_codes_hauppauge_new; break; - case SAA7134_BOARD_BEHOLD_607_9FM: + case SAA7134_BOARD_BEHOLD_607FM_MK3: + case SAA7134_BOARD_BEHOLD_607FM_MK5: + case SAA7134_BOARD_BEHOLD_609FM_MK3: + case SAA7134_BOARD_BEHOLD_609FM_MK5: + case SAA7134_BOARD_BEHOLD_607RDS_MK3: + case SAA7134_BOARD_BEHOLD_607RDS_MK5: + case SAA7134_BOARD_BEHOLD_609RDS_MK3: + case SAA7134_BOARD_BEHOLD_609RDS_MK5: case SAA7134_BOARD_BEHOLD_M6: case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index bac170935..d961e0861 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -253,7 +253,7 @@ struct saa7134_format { #define SAA7134_BOARD_BEHOLD_505FM 126 #define SAA7134_BOARD_BEHOLD_507_9FM 127 #define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 -#define SAA7134_BOARD_BEHOLD_607_9FM 129 +#define SAA7134_BOARD_BEHOLD_607FM_MK3 129 #define SAA7134_BOARD_BEHOLD_M6 130 #define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131 #define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132 @@ -283,6 +283,16 @@ struct saa7134_format { #define SAA7134_BOARD_HAUPPAUGE_HVR1110R3 156 #define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157 #define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158 +#define SAA7134_BOARD_BEHOLD_505RDS 159 +#define SAA7134_BOARD_BEHOLD_507RDS_MK3 160 +#define SAA7134_BOARD_BEHOLD_507RDS_MK5 161 +#define SAA7134_BOARD_BEHOLD_607FM_MK5 162 +#define SAA7134_BOARD_BEHOLD_609FM_MK3 163 +#define SAA7134_BOARD_BEHOLD_609FM_MK5 164 +#define SAA7134_BOARD_BEHOLD_607RDS_MK3 165 +#define SAA7134_BOARD_BEHOLD_607RDS_MK5 166 +#define SAA7134_BOARD_BEHOLD_609RDS_MK3 167 +#define SAA7134_BOARD_BEHOLD_609RDS_MK5 168 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index cd796b33f..bf0b176f9 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -82,7 +82,6 @@ struct sh_mobile_ceu_buffer { }; struct sh_mobile_ceu_dev { - struct device *dev; struct soc_camera_host ici; struct soc_camera_device *icd; @@ -618,7 +617,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx, xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, "Providing format %s using %s\n", + dev_dbg(ici->dev, "Providing format %s using %s\n", sh_mobile_ceu_formats[k].name, icd->formats[idx].name); } @@ -631,7 +630,7 @@ add_single_format: xlate->cam_fmt = icd->formats + idx; xlate->buswidth = icd->formats[idx].depth; xlate++; - dev_dbg(&ici->dev, + dev_dbg(ici->dev, "Providing format %s in pass-through mode\n", icd->formats[idx].name); } @@ -658,7 +657,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -685,7 +684,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (!xlate) { - dev_warn(&ici->dev, "Format %x not found\n", pixfmt); + dev_warn(ici->dev, "Format %x not found\n", pixfmt); return -EINVAL; } @@ -783,7 +782,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q, videobuf_queue_dma_contig_init(q, &sh_mobile_ceu_videobuf_ops, - &ici->dev, &pcdev->lock, + ici->dev, &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, pcdev->is_interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE, @@ -830,7 +829,6 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit; } - platform_set_drvdata(pdev, pcdev); INIT_LIST_HEAD(&pcdev->capture); spin_lock_init(&pcdev->lock); @@ -841,7 +839,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit_kfree; } - base = ioremap_nocache(res->start, res->end - res->start + 1); + base = ioremap_nocache(res->start, resource_size(res)); if (!base) { err = -ENXIO; dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); @@ -851,13 +849,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) pcdev->irq = irq; pcdev->base = base; pcdev->video_limit = 0; /* only enabled if second resource exists */ - pcdev->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { err = dma_declare_coherent_memory(&pdev->dev, res->start, res->start, - (res->end - res->start) + 1, + resource_size(res), DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); if (!err) { @@ -866,7 +863,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) goto exit_iounmap; } - pcdev->video_limit = (res->end - res->start) + 1; + pcdev->video_limit = resource_size(res); } /* request irq */ @@ -886,7 +883,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) } pcdev->ici.priv = pcdev; - pcdev->ici.dev.parent = &pdev->dev; + pcdev->ici.dev = &pdev->dev; pcdev->ici.nr = pdev->id; pcdev->ici.drv_name = dev_name(&pdev->dev); pcdev->ici.ops = &sh_mobile_ceu_host_ops; @@ -914,9 +911,11 @@ exit: static int sh_mobile_ceu_remove(struct platform_device *pdev) { - struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev); + struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); + struct sh_mobile_ceu_dev *pcdev = container_of(soc_host, + struct sh_mobile_ceu_dev, ici); - soc_camera_host_unregister(&pcdev->ici); + soc_camera_host_unregister(soc_host); clk_put(pcdev->clk); free_irq(pcdev->irq, pcdev); if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 9e432d390..9dca8f470 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -280,7 +280,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, return ret; } else if (!icd->current_fmt || icd->current_fmt->fourcc != pix->pixelformat) { - dev_err(&ici->dev, + dev_err(ici->dev, "Host driver hasn't set up current format correctly!\n"); return -EINVAL; } @@ -795,7 +795,7 @@ static void scan_add_host(struct soc_camera_host *ici) list_for_each_entry(icd, &devices, list) { if (icd->iface == ici->nr) { - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; device_register_link(icd); } } @@ -819,7 +819,7 @@ static int scan_add_device(struct soc_camera_device *icd) list_for_each_entry(ici, &hosts, list) { if (icd->iface == ici->nr) { ret = 1; - icd->dev.parent = &ici->dev; + icd->dev.parent = ici->dev; break; } } @@ -953,7 +953,6 @@ static void dummy_release(struct device *dev) int soc_camera_host_register(struct soc_camera_host *ici) { - int ret; struct soc_camera_host *ix; if (!ici || !ici->ops || @@ -966,12 +965,10 @@ int soc_camera_host_register(struct soc_camera_host *ici) !ici->ops->reqbufs || !ici->ops->add || !ici->ops->remove || - !ici->ops->poll) + !ici->ops->poll || + !ici->dev) return -EINVAL; - /* Number might be equal to the platform device ID */ - dev_set_name(&ici->dev, "camera_host%d", ici->nr); - mutex_lock(&list_lock); list_for_each_entry(ix, &hosts, list) { if (ix->nr == ici->nr) { @@ -980,26 +977,14 @@ int soc_camera_host_register(struct soc_camera_host *ici) } } + dev_set_drvdata(ici->dev, ici); + list_add_tail(&ici->list, &hosts); mutex_unlock(&list_lock); - ici->dev.release = dummy_release; - - ret = device_register(&ici->dev); - - if (ret) - goto edevr; - scan_add_host(ici); return 0; - -edevr: - mutex_lock(&list_lock); - list_del(&ici->list); - mutex_unlock(&list_lock); - - return ret; } EXPORT_SYMBOL(soc_camera_host_register); @@ -1013,7 +998,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) list_del(&ici->list); list_for_each_entry(icd, &devices, list) { - if (icd->dev.parent == &ici->dev) { + if (icd->dev.parent == ici->dev) { device_unregister(&icd->dev); /* Not before device_unregister(), .remove * needs parent to call ici->ops->remove() */ @@ -1024,7 +1009,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici) mutex_unlock(&list_lock); - device_unregister(&ici->dev); + dev_set_drvdata(ici->dev, NULL); } EXPORT_SYMBOL(soc_camera_host_unregister); @@ -1131,7 +1116,7 @@ int soc_camera_video_start(struct soc_camera_device *icd) vdev = video_device_alloc(); if (!vdev) goto evidallocd; - dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev); + dev_dbg(ici->dev, "Allocated video_device %p\n", vdev); strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); diff --git a/linux/include/media/soc_camera.h b/linux/include/media/soc_camera.h index 37013688a..bef5e81d6 100644 --- a/linux/include/media/soc_camera.h +++ b/linux/include/media/soc_camera.h @@ -60,7 +60,7 @@ struct soc_camera_file { struct soc_camera_host { struct list_head list; - struct device dev; + struct device *dev; unsigned char nr; /* Host number */ void *priv; const char *drv_name; @@ -107,6 +107,7 @@ struct soc_camera_link { */ int (*set_bus_param)(struct soc_camera_link *, unsigned long flags); unsigned long (*query_bus_param)(struct soc_camera_link *); + void (*free_bus)(struct soc_camera_link *); }; static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev) @@ -116,7 +117,7 @@ static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev) static inline struct soc_camera_host *to_soc_camera_host(struct device *dev) { - return container_of(dev, struct soc_camera_host, dev); + return dev_get_drvdata(dev); } extern int soc_camera_host_register(struct soc_camera_host *ici); |