From d933990c57b498c092ceef591c7c5d69dbfe9f30 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 23 May 2011 21:39:58 +0000 Subject: viafb: use display information in info not in var for panning As Laurent pointed out we must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Also use the aligned fix.line_length and not the (possible) unaligned xres_virtual. Signed-off-by: Florian Tobias Schandinat Reported-by: Laurent Pinchart Acked-by: Laurent Pinchart Cc: stable@kernel.org --- drivers/video/via/viafbdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 3114a8755c13..aa87529d7d6a 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -348,8 +348,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct viafb_par *viapar = info->par; - u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset) - * (var->bits_per_pixel / 8) + viapar->vram_addr; + u32 vram_addr = viapar->vram_addr + + var->yoffset * info->fix.line_length + + var->xoffset * info->var.bits_per_pixel / 8; DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); if (!viafb_dual_fb) { -- cgit v1.2.3 From 0cf9cd026adeacc3fe5e88e4d3e7f8f3aeff6790 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:03 +0000 Subject: vfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/vfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c index bc67251f1a2f..bf2f78065cf9 100644 --- a/drivers/video/vfb.c +++ b/drivers/video/vfb.c @@ -395,8 +395,8 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, || var->xoffset) return -EINVAL; } else { - if (var->xoffset + var->xres > info->var.xres_virtual || - var->yoffset + var->yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } info->var.xoffset = var->xoffset; -- cgit v1.2.3 From c42a3d543d2bbd2cb72c7179234358a4a33a583d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:07 +0000 Subject: staging: xgifb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Aaro Koskinen Cc: Arnaud Patard Signed-off-by: Paul Mundt --- drivers/staging/xgifb/XGI_main_26.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index cadec2ad0d32..e92f6fa67dcb 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -1365,26 +1365,16 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive, } #ifdef XGIFB_PAN -static int XGIfb_pan_var(struct fb_var_screeninfo *var) +static int XGIfb_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) { unsigned int base; /* printk("Inside pan_var"); */ - if (var->xoffset > (var->xres_virtual - var->xres)) { - /* printk("Pan: xo: %d xv %d xr %d\n", - var->xoffset, var->xres_virtual, var->xres); */ - return -EINVAL; - } - if (var->yoffset > (var->yres_virtual - var->yres)) { - /* printk("Pan: yo: %d yv %d yr %d\n", - var->yoffset, var->yres_virtual, var->yres); */ - return -EINVAL; - } - base = var->yoffset * var->xres_virtual + var->xoffset; + base = var->yoffset * info->var.xres_virtual + var->xoffset; /* calculate base bpp dep. */ - switch (var->bits_per_pixel) { + switch (info->var.bits_per_pixel) { case 16: base >>= 1; break; @@ -1682,9 +1672,9 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var, /* printk("\nInside pan_display:\n"); */ - if (var->xoffset > (var->xres_virtual - var->xres)) + if (var->xoffset > (info->var.xres_virtual - info->var.xres)) return -EINVAL; - if (var->yoffset > (var->yres_virtual - var->yres)) + if (var->yoffset > (info->var.yres_virtual - info->var.yres)) return -EINVAL; if (var->vmode & FB_VMODE_YWRAP) { @@ -1697,7 +1687,7 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var, > info->var.yres_virtual) return -EINVAL; } - err = XGIfb_pan_var(var); + err = XGIfb_pan_var(var, info); if (err < 0) return err; -- cgit v1.2.3 From a1bb7010d494d3fcde3814d7a8ac609f1dff96ee Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:40 +0000 Subject: acornfb: Dont BUG() on invalid pan parameters The driver currently BUG()s if the pan parameters passed directly from userspace are invalid. Return -EINVAL instead. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/acornfb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 6183a57eb69d..3bacc1290548 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -852,7 +852,8 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) if (!(var->vmode & FB_VMODE_YWRAP)) y_bottom += var->yres; - BUG_ON(y_bottom > var->yres_virtual); + if (y_bottom > var->yres_virtual) + return -EINVAL; acornfb_update_dma(info, var); -- cgit v1.2.3 From a4aadc9311ed8459471a1d4580d3199230a88437 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:58 +0000 Subject: s3fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Ondrej Zary Signed-off-by: Paul Mundt --- drivers/video/s3fb.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 4ca5d0c8fe84..0f9af1aa5077 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -1019,12 +1019,13 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) unsigned int offset; /* Calculate the offset */ - if (var->bits_per_pixel == 0) { - offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2); + if (info->var.bits_per_pixel == 0) { + offset = (var->yoffset / 16) * (info->var.xres_virtual / 2) + + (var->xoffset / 2); offset = offset >> 2; } else { offset = (var->yoffset * info->fix.line_length) + - (var->xoffset * var->bits_per_pixel / 8); + (var->xoffset * info->var.bits_per_pixel / 8); offset = offset >> 2; } -- cgit v1.2.3 From 4ee99f7e2edbd32501cb1fc0b701966d7cbe57e4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:53 +0000 Subject: mx3fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Also use the aligned fix.line_length and not the (possible) unaligned xres_virtual. Signed-off-by: Laurent Pinchart Tested-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/mx3fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c index 7e3a490e8d76..bd768588cf10 100644 --- a/drivers/video/mx3fb.c +++ b/drivers/video/mx3fb.c @@ -1062,15 +1062,15 @@ static int mx3fb_pan_display(struct fb_var_screeninfo *var, y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) - y_bottom += var->yres; + y_bottom += fbi->var.yres; if (y_bottom > fbi->var.yres_virtual) return -EINVAL; mutex_lock(&mx3_fbi->mutex); - offset = (var->yoffset * var->xres_virtual + var->xoffset) * - (var->bits_per_pixel / 8); + offset = var->yoffset * fbi->fix.line_length + + var->xoffset * (fbi->var.bits_per_pixel / 8); base = fbi->fix.smem_start + offset; dev_dbg(fbi->device, "Updating SDC BG buf %d address=0x%08lX\n", -- cgit v1.2.3 From 2bdb0278eec7bb466d2b1b31ecf6e48f10b34fbf Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:54 +0000 Subject: neofb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Krzysztof Helt Signed-off-by: Paul Mundt --- drivers/video/neofb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 588527a254c2..feea7b1dc386 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -1185,8 +1185,8 @@ static int neofb_pan_display(struct fb_var_screeninfo *var, DBG("neofb_update_start"); - Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2; - Base *= (var->bits_per_pixel + 7) / 8; + Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2; + Base *= (info->var.bits_per_pixel + 7) / 8; neoUnlock(); -- cgit v1.2.3 From 1388f6a77296b4fa926c6830f884b08c5ef4beab Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:59 +0000 Subject: savagefb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Also use the aligned fix.line_length and not the (possible) unaligned xres_virtual. Signed-off-by: Laurent Pinchart Reviewed-by: Tormod Volden Cc: Antonino Daplas Signed-off-by: Paul Mundt --- drivers/video/savage/savagefb_driver.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index 4de541ca9c52..beb495044b24 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1477,15 +1477,9 @@ static void savagefb_set_par_int(struct savagefb_par *par, struct savage_reg *r vgaHWProtect(par, 0); } -static void savagefb_update_start(struct savagefb_par *par, - struct fb_var_screeninfo *var) +static void savagefb_update_start(struct savagefb_par *par, int base) { - int base; - - base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1)) - * ((var->bits_per_pixel+7) / 8)) >> 2; - - /* now program the start address registers */ + /* program the start address registers */ vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); vga_out8(0x3d4, 0x69, par); @@ -1550,8 +1544,12 @@ static int savagefb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct savagefb_par *par = info->par; + int base; + + base = (var->yoffset * info->fix.line_length + + (var->xoffset & ~1) * ((info->var.bits_per_pixel+7) / 8)) >> 2; - savagefb_update_start(par, var); + savagefb_update_start(par, base); return 0; } -- cgit v1.2.3 From eca7370bd2f29296126011caed64af93c2c73803 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:01 +0000 Subject: sm501fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Ben Dooks Signed-off-by: Paul Mundt --- drivers/video/sm501fb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 87f0be1e78b5..2c9e9d3eb4ba 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -582,7 +582,7 @@ static int sm501fb_pan_crt(struct fb_var_screeninfo *var, { struct sm501fb_par *par = info->par; struct sm501fb_info *fbi = par->info; - unsigned int bytes_pixel = var->bits_per_pixel / 8; + unsigned int bytes_pixel = info->var.bits_per_pixel / 8; unsigned long reg; unsigned long xoffs; @@ -614,10 +614,10 @@ static int sm501fb_pan_pnl(struct fb_var_screeninfo *var, struct sm501fb_info *fbi = par->info; unsigned long reg; - reg = var->xoffset | (var->xres_virtual << 16); + reg = var->xoffset | (info->var.xres_virtual << 16); smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_WIDTH); - reg = var->yoffset | (var->yres_virtual << 16); + reg = var->yoffset | (info->var.yres_virtual << 16); smc501_writel(reg, fbi->regs + SM501_DC_PANEL_FB_HEIGHT); sm501fb_sync_regs(fbi); -- cgit v1.2.3 From c12665ffcf4e5e67b84771d30fb76dd9ff16600e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:50 +0000 Subject: imsttfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/imsttfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c index efb2c10656b0..8149356471e4 100644 --- a/drivers/video/imsttfb.c +++ b/drivers/video/imsttfb.c @@ -749,7 +749,7 @@ set_offset (struct fb_var_screeninfo *var, struct fb_info *info) { struct imstt_par *par = info->par; __u32 off = var->yoffset * (info->fix.line_length >> 3) - + ((var->xoffset * (var->bits_per_pixel >> 3)) >> 3); + + ((var->xoffset * (info->var.bits_per_pixel >> 3)) >> 3); write_reg_le32(par->dc_regs, SSR, off); } -- cgit v1.2.3 From c2d340a403f08e57fb76e738e691fe466a38a8c8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:48 +0000 Subject: gxt4500: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Paul Mackerras Signed-off-by: Paul Mundt --- drivers/video/gxt4500.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/gxt4500.c b/drivers/video/gxt4500.c index 896e53dea906..0fad23f810a3 100644 --- a/drivers/video/gxt4500.c +++ b/drivers/video/gxt4500.c @@ -543,8 +543,8 @@ static int gxt4500_pan_display(struct fb_var_screeninfo *var, if (var->xoffset & 7) return -EINVAL; - if (var->xoffset + var->xres > var->xres_virtual || - var->yoffset + var->yres > var->yres_virtual) + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; writereg(par, REFRESH_START, (var->xoffset << 16) | var->yoffset); -- cgit v1.2.3 From df9306de45529f02d18a1a16b8685ef5c90f98f7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:55 +0000 Subject: pm2fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Krzysztof Helt Signed-off-by: Paul Mundt --- drivers/video/pm2fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 27f93aab6ddc..f4f8ce802d02 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -973,8 +973,8 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var, { struct pm2fb_par *p = info->par; u32 base; - u32 depth = (var->bits_per_pixel + 7) & ~7; - u32 xres = (var->xres + 31) & ~31; + u32 depth = (info->var.bits_per_pixel + 7) & ~7; + u32 xres = (info->var.xres + 31) & ~31; depth = (depth > 32) ? 32 : depth; base = to3264(var->yoffset * xres + var->xoffset, depth, 1); -- cgit v1.2.3 From 5dac1518373824dc36fef9efc4d80491eb0ed50f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:00 +0000 Subject: sisfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Fix checkpatch.pl warnings in the surrounding code. Signed-off-by: Laurent Pinchart Cc: Aaro Koskinen Cc: Thomas Winischhofer Signed-off-by: Paul Mundt --- drivers/video/sis/sis_main.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 75259845933d..078ca2167d6f 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -1333,19 +1333,14 @@ sisfb_set_base_CRT2(struct sis_video_info *ivideo, unsigned int base) } static int -sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var) +sisfb_pan_var(struct sis_video_info *ivideo, struct fb_info *info, + struct fb_var_screeninfo *var) { - if(var->xoffset > (var->xres_virtual - var->xres)) { - return -EINVAL; - } - if(var->yoffset > (var->yres_virtual - var->yres)) { - return -EINVAL; - } - - ivideo->current_base = (var->yoffset * var->xres_virtual) + var->xoffset; + ivideo->current_base = var->yoffset * info->var.xres_virtual + + var->xoffset; /* calculate base bpp dep. */ - switch(var->bits_per_pixel) { + switch (info->var.bits_per_pixel) { case 32: break; case 16: @@ -1635,20 +1630,15 @@ sisfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) struct sis_video_info *ivideo = (struct sis_video_info *)info->par; int err; - if(var->xoffset > (var->xres_virtual - var->xres)) - return -EINVAL; - - if(var->yoffset > (var->yres_virtual - var->yres)) - return -EINVAL; - - if(var->vmode & FB_VMODE_YWRAP) + if (var->vmode & FB_VMODE_YWRAP) return -EINVAL; - if(var->xoffset + info->var.xres > info->var.xres_virtual || - var->yoffset + info->var.yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; - if((err = sisfb_pan_var(ivideo, var)) < 0) + err = sisfb_pan_var(ivideo, info, var); + if (err < 0) return err; info->var.xoffset = var->xoffset; -- cgit v1.2.3 From 895607ec5c7d7b0d840416db6499f83a0ee187af Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:43 +0000 Subject: atmel_lcdfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Nicolas Ferre Signed-off-by: Paul Mundt --- drivers/video/atmel_lcdfb.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 4484c721f0f9..8b5d7552bb65 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -39,7 +39,8 @@ | FBINFO_HWACCEL_YPAN) static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, - struct fb_var_screeninfo *var) + struct fb_var_screeninfo *var, + struct fb_info *info) { } @@ -50,14 +51,16 @@ static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, | FBINFO_HWACCEL_YPAN) static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, - struct fb_var_screeninfo *var) + struct fb_var_screeninfo *var, + struct fb_info *info) { u32 dma2dcfg; u32 pixeloff; - pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; + pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f; - dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; + dma2dcfg = (info-var.xres_virtual - info->var.xres) + * info->var.bits_per_pixel / 8; dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); @@ -249,14 +252,14 @@ static void atmel_lcdfb_update_dma(struct fb_info *info, unsigned long dma_addr; dma_addr = (fix->smem_start + var->yoffset * fix->line_length - + var->xoffset * var->bits_per_pixel / 8); + + var->xoffset * info->var.bits_per_pixel / 8); dma_addr &= ~3UL; /* Set framebuffer DMA base address and pixel offset */ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); - atmel_lcdfb_update_dma2d(sinfo, var); + atmel_lcdfb_update_dma2d(sinfo, var, info); } static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo) -- cgit v1.2.3 From 635e9620e8361005b9a80c9fb0445b6b87d36f8c Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:51 +0000 Subject: intelfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Maik Broemme Signed-off-by: Paul Mundt --- drivers/video/intelfb/intelfbhw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 38065cf94ac4..fbad61da359f 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -390,12 +390,12 @@ int intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) xoffset = ROUND_DOWN_TO(var->xoffset, 8); yoffset = var->yoffset; - if ((xoffset + var->xres > var->xres_virtual) || - (yoffset + var->yres > var->yres_virtual)) + if ((xoffset + info->var.xres > info->var.xres_virtual) || + (yoffset + info->var.yres > info->var.yres_virtual)) return -EINVAL; offset = (yoffset * dinfo->pitch) + - (xoffset * var->bits_per_pixel) / 8; + (xoffset * info->var.bits_per_pixel) / 8; offset += dinfo->fb.offset << 12; -- cgit v1.2.3 From e4c735af0076923643af48577fc9ad6e123a55fa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:02 +0000 Subject: tridentfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Krzysztof Helt Signed-off-by: Paul Mundt --- drivers/video/tridentfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c index c6c77562839d..34cf019bba44 100644 --- a/drivers/video/tridentfb.c +++ b/drivers/video/tridentfb.c @@ -987,8 +987,8 @@ static int tridentfb_pan_display(struct fb_var_screeninfo *var, unsigned int offset; debug("enter\n"); - offset = (var->xoffset + (var->yoffset * var->xres_virtual)) - * var->bits_per_pixel / 32; + offset = (var->xoffset + (var->yoffset * info->var.xres_virtual)) + * info->var.bits_per_pixel / 32; set_screen_start(par, offset); debug("exit\n"); return 0; -- cgit v1.2.3 From 4d3c68a1b468741fcebfbfb0b92ff9e75a063484 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:04 +0000 Subject: vga16fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Antonino A. Daplas Signed-off-by: Paul Mundt --- drivers/video/vga16fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 305c975b1787..0267acd8dc83 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -207,7 +207,7 @@ static void vga16fb_pan_var(struct fb_info *info, * granularity if someone supports xoffset in bit resolution */ vga_io_r(VGA_IS1_RC); /* reset flip-flop */ vga_io_w(VGA_ATT_IW, VGA_ATC_PEL); - if (var->bits_per_pixel == 8) + if (info->var.bits_per_pixel == 8) vga_io_w(VGA_ATT_IW, (xoffset & 3) << 1); else vga_io_w(VGA_ATT_IW, xoffset & 7); -- cgit v1.2.3 From ff55fe9ac19d800bfab02bc877c06e74f3e2537d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:44 +0000 Subject: radeonfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Also use the aligned fix.line_length and not the (possible) unaligned xres_virtual. Signed-off-by: Laurent Pinchart Cc: Benjamin Herrenschmidt Signed-off-by: Paul Mundt --- drivers/video/aty/radeon_base.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 32f8cf6200a7..150684882ef7 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -845,16 +845,16 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var, { struct radeonfb_info *rinfo = info->par; - if ((var->xoffset + var->xres > var->xres_virtual) - || (var->yoffset + var->yres > var->yres_virtual)) - return -EINVAL; + if ((var->xoffset + info->var.xres > info->var.xres_virtual) + || (var->yoffset + info->var.yres > info->var.yres_virtual)) + return -EINVAL; if (rinfo->asleep) return 0; radeon_fifo_wait(2); - OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset) - * var->bits_per_pixel / 8) & ~7); + OUTREG(CRTC_OFFSET, (var->yoffset * info->fix.line_length + + var->xoffset * info->var.bits_per_pixel / 8) & ~7); return 0; } -- cgit v1.2.3 From df2d79810930ead3112b4ebab86ea0f9229ccf70 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:49 +0000 Subject: hgafb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Ferenc Bakonyi Cc: Brent Cook Signed-off-by: Paul Mundt --- drivers/video/hgafb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index 4052718eefaa..4394389caf68 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -422,8 +422,8 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var, var->xoffset) return -EINVAL; } else { - if (var->xoffset + var->xres > info->var.xres_virtual - || var->yoffset + var->yres > info->var.yres_virtual + if (var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual || var->yoffset % 8) return -EINVAL; } -- cgit v1.2.3 From 1fdb518f9f9c804d78e84a54ce1814fe9003bca4 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:56 +0000 Subject: pm3fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Krzysztof Helt Signed-off-by: Paul Mundt --- drivers/video/pm3fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 6666f45a2f8c..8221b5b42da9 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -1147,9 +1147,9 @@ static int pm3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct pm3_par *par = info->par; - const u32 xres = (var->xres + 31) & ~31; + const u32 xres = (info->var.xres + 31) & ~31; - par->base = pm3fb_shift_bpp(var->bits_per_pixel, + par->base = pm3fb_shift_bpp(info->var.bits_per_pixel, (var->yoffset * xres) + var->xoffset); PM3_WAIT(par, 1); -- cgit v1.2.3 From 1dbe8514fdb9ec6c82aa295c57886dfcf17574f1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:41 +0000 Subject: acornfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/acornfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c index 3bacc1290548..b303f1715065 100644 --- a/drivers/video/acornfb.c +++ b/drivers/video/acornfb.c @@ -850,9 +850,9 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) u_int y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) - y_bottom += var->yres; + y_bottom += info->var.yres; - if (y_bottom > var->yres_virtual) + if (y_bottom > info->var.yres_virtual) return -EINVAL; acornfb_update_dma(info, var); -- cgit v1.2.3 From aa7984cf51875bbb867485a72817bca5162fe80d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:46 +0000 Subject: fbdev: unicore32: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Guan Xuetao Signed-off-by: Paul Mundt --- drivers/video/fb-puv3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fb-puv3.c b/drivers/video/fb-puv3.c index 27f2c57e06e9..60a787fa32cf 100644 --- a/drivers/video/fb-puv3.c +++ b/drivers/video/fb-puv3.c @@ -624,8 +624,8 @@ static int unifb_pan_display(struct fb_var_screeninfo *var, || var->xoffset) return -EINVAL; } else { - if (var->xoffset + var->xres > info->var.xres_virtual || - var->yoffset + var->yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } info->var.xoffset = var->xoffset; -- cgit v1.2.3 From 3362903cad196d2a8ba340c0c3c5889db3b65c68 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:57 +0000 Subject: s3c-fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Acked-by: Jingoo Han Signed-off-by: Paul Mundt --- drivers/video/s3c-fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0352afa49a39..42b557c44e84 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c @@ -884,7 +884,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, } } /* Offset in bytes to the end of the displayed area */ - end_boff = start_boff + var->yres * info->fix.line_length; + end_boff = start_boff + info->var.yres * info->fix.line_length; /* Temporarily turn off per-vsync update from shadow registers until * both start and end addresses are updated to prevent corruption */ -- cgit v1.2.3 From f316fe726a0edd3941111b61681bb8bbd4fda2e6 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:52 +0000 Subject: mb862xxfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Anatolij Gustschin Signed-off-by: Paul Mundt --- drivers/video/mb862xx/mb862xxfbdrv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/mb862xx/mb862xxfbdrv.c b/drivers/video/mb862xx/mb862xxfbdrv.c index f70bd63b0187..2191de0bb309 100644 --- a/drivers/video/mb862xx/mb862xxfbdrv.c +++ b/drivers/video/mb862xx/mb862xxfbdrv.c @@ -278,7 +278,7 @@ static int mb862xxfb_pan(struct fb_var_screeninfo *var, reg = pack(var->yoffset, var->xoffset); outreg(disp, GC_L0WY_L0WX, reg); - reg = pack(var->yres_virtual, var->xres_virtual); + reg = pack(info->var.yres_virtual, info->var.xres_virtual); outreg(disp, GC_L0WH_L0WW, reg); return 0; } -- cgit v1.2.3 From 3b30f9f437eed6a1fd7f306fa0d2ab1e18e44a1f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:47 +0000 Subject: g364fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/g364fb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c index d662317d85e3..223896cc5f7d 100644 --- a/drivers/video/g364fb.c +++ b/drivers/video/g364fb.c @@ -149,10 +149,11 @@ int g364fb_cursor(struct fb_info *info, struct fb_cursor *cursor) static int g364fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - if (var->xoffset || var->yoffset + var->yres > var->yres_virtual) + if (var->xoffset || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; - *(unsigned int *) TOP_REG = var->yoffset * var->xres; + *(unsigned int *) TOP_REG = var->yoffset * info->var.xres; return 0; } -- cgit v1.2.3 From 7b8067f202b9dc0b6baea1dee918d95e3112f2a5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:42 +0000 Subject: arkfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Ondrej Zajicek Signed-off-by: Paul Mundt --- drivers/video/arkfb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c index 8686429cbdf0..555dd4c64f5b 100644 --- a/drivers/video/arkfb.c +++ b/drivers/video/arkfb.c @@ -908,13 +908,14 @@ static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info unsigned int offset; /* Calculate the offset */ - if (var->bits_per_pixel == 0) { - offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2); + if (info->var.bits_per_pixel == 0) { + offset = (var->yoffset / 16) * (info->var.xres_virtual / 2) + + (var->xoffset / 2); offset = offset >> 2; } else { offset = (var->yoffset * info->fix.line_length) + - (var->xoffset * var->bits_per_pixel / 8); - offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3); + (var->xoffset * info->var.bits_per_pixel / 8); + offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 3); } /* Set the offset */ -- cgit v1.2.3 From c6990b775d543c432f968808119d7fe33d506a71 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:39 +0000 Subject: 68328fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Signed-off-by: Paul Mundt --- drivers/video/68328fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c index 75a39eab70c3..a425d65d5ba2 100644 --- a/drivers/video/68328fb.c +++ b/drivers/video/68328fb.c @@ -378,8 +378,8 @@ static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, || var->xoffset) return -EINVAL; } else { - if (var->xoffset + var->xres > info->var.xres_virtual || - var->yoffset + var->yres > info->var.yres_virtual) + if (var->xoffset + info->var.xres > info->var.xres_virtual || + var->yoffset + info->var.yres > info->var.yres_virtual) return -EINVAL; } info->var.xoffset = var->xoffset; -- cgit v1.2.3 From 83f0e27c253554b7be329e2786d0814a276fd240 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:06 +0000 Subject: vt8623fb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Ondrej Zajicek Cc: David S. Miller Signed-off-by: Paul Mundt --- drivers/video/vt8623fb.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c index f9b3e3dc2421..4e74d262cf3e 100644 --- a/drivers/video/vt8623fb.c +++ b/drivers/video/vt8623fb.c @@ -620,13 +620,14 @@ static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *i unsigned int offset; /* Calculate the offset */ - if (var->bits_per_pixel == 0) { - offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset; + if (info->var.bits_per_pixel == 0) { + offset = (var->yoffset / 16) * info->var.xres_virtual + + var->xoffset; offset = offset >> 3; } else { offset = (var->yoffset * info->fix.line_length) + - (var->xoffset * var->bits_per_pixel / 8); - offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1); + (var->xoffset * info->var.bits_per_pixel / 8); + offset = offset >> ((info->var.bits_per_pixel == 4) ? 2 : 1); } /* Set the offset */ -- cgit v1.2.3 From 3478b1cd43284ef798974384ba894eadc37fc1d9 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:25:05 +0000 Subject: vt8500lcdfb: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Acked-by: Alexey Charkov Signed-off-by: Paul Mundt --- drivers/video/vt8500lcdfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 0e120d67eb65..c13c246be9a5 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c @@ -210,8 +210,8 @@ static int vt8500lcd_pan_display(struct fb_var_screeninfo *var, struct vt8500lcd_info *fbi = to_vt8500lcd_info(info); writel((1 << 31) - | (((var->xres_virtual - var->xres) * pixlen / 4) << 20) - | (off >> 2), fbi->regbase + 0x20); + | (((info->var.xres_virtual - info->var.xres) * pixlen / 4) << 20) + | (off >> 2), fbi->regbase + 0x20); return 0; } -- cgit v1.2.3 From e6c4d3d43d4d00a0ed945c77e6b89c74b38120d7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 14 Jun 2011 09:24:45 +0000 Subject: fbdev: da8xx: use display information in info not in var for panning We must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Signed-off-by: Laurent Pinchart Cc: Sudhakar Rajashekhara Cc: Martin Ambrose Signed-off-by: Paul Mundt --- drivers/video/da8xx-fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index fcdac872522d..8d4e4ebd9977 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -877,8 +877,8 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var, start = fix->smem_start + new_var.yoffset * fix->line_length + - new_var.xoffset * var->bits_per_pixel / 8; - end = start + var->yres * fix->line_length - 1; + new_var.xoffset * fbi->var.bits_per_pixel / 8; + end = start + fbi->var.yres * fix->line_length - 1; par->dma_start = start; par->dma_end = end; } -- cgit v1.2.3 From c329f606a23e13fe952768cb9c32ea929ed91480 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 10 Jun 2011 15:23:01 +0000 Subject: au1200fb: use framebuffer_alloc() Convert to use framebuffer_alloc() instead of using fb_info embedded into device context (which broke the driver in the past due to un- initialized elements). Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/video/au1200fb.c | 80 ++++++++++++++++++++++++++++-------------------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 5dff32ac8044..442d005e452d 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -150,7 +150,7 @@ struct au1200_lcd_iodata_t { /* Private, per-framebuffer management information (independent of the panel itself) */ struct au1200fb_device { - struct fb_info fb_info; /* FB driver info record */ + struct fb_info *fb_info; /* FB driver info record */ int plane; unsigned char* fb_mem; /* FrameBuffer memory map */ @@ -158,7 +158,7 @@ struct au1200fb_device { dma_addr_t fb_phys; }; -static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS]; +static struct fb_info *_au1200fb_infos[CONFIG_FB_AU1200_DEVS]; /********************************************************************/ /* LCD controller restrictions */ @@ -713,7 +713,7 @@ static int fbinfo2index (struct fb_info *fb_info) int i; for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { - if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) + if (fb_info == _au1200fb_infos[i]) return i; } printk("au1200fb: ERROR: fbinfo2index failed!\n"); @@ -962,7 +962,7 @@ static void au1200_setmode(struct au1200fb_device *fbdev) lcd->window[plane].winctrl2 = ( 0 | LCD_WINCTRL2_CKMODE_00 | LCD_WINCTRL2_DBM - | LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) + | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length) | LCD_WINCTRL2_SCX_1 | LCD_WINCTRL2_SCY_1 ) ; @@ -1050,7 +1050,7 @@ static void au1200fb_update_fbinfo(struct fb_info *fbi) static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) { - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; + struct au1200fb_device *fbdev = fbi->par; u32 pixclock; int screen_size, plane; @@ -1142,7 +1142,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, */ static int au1200fb_fb_set_par(struct fb_info *fbi) { - struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; + struct au1200fb_device *fbdev = fbi->par; au1200fb_update_fbinfo(fbi); au1200_setmode(fbdev); @@ -1246,7 +1246,7 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned int len; unsigned long start=0, off; - struct au1200fb_device *fbdev = (struct au1200fb_device *) info; + struct au1200fb_device *fbdev = info->par; #ifdef CONFIG_PM au1xxx_pm_access(LCD_pm_dev); @@ -1561,10 +1561,9 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id) static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) { - struct fb_info *fbi = &fbdev->fb_info; + struct fb_info *fbi = fbdev->fb_info; int bpp; - memset(fbi, 0, sizeof(struct fb_info)); fbi->fbops = &au1200fb_fb_ops; bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); @@ -1626,11 +1625,13 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) static int au1200fb_drv_probe(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct fb_info *fbi = NULL; unsigned long page; int bpp, plane, ret; - if (!dev) - return -EINVAL; + /* shut gcc up */ + ret = 0; + fbdev = NULL; for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); @@ -1639,8 +1640,15 @@ static int au1200fb_drv_probe(struct platform_device *dev) if (win->w[plane].yres == 0) win->w[plane].yres = panel->Yres; - fbdev = &_au1200fb_devices[plane]; - memset(fbdev, 0, sizeof(struct au1200fb_device)); + fbi = framebuffer_alloc(sizeof(struct au1200fb_device), + &dev->dev); + if (!fbi) + goto failed; + + _au1200fb_infos[plane] = fbi; + fbdev = fbi->par; + fbdev->fb_info = fbi; + fbdev->plane = plane; /* Allocate the framebuffer to the maximum screen size */ @@ -1673,21 +1681,20 @@ static int au1200fb_drv_probe(struct platform_device *dev) goto failed; /* Register new framebuffer */ - if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { + ret = register_framebuffer(fbi); + if (ret < 0) { print_err("cannot register new framebuffer"); goto failed; } - au1200fb_fb_set_par(&fbdev->fb_info); + au1200fb_fb_set_par(fbi); #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) if (plane == 0) - if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { + if (fb_prepare_logo(fbi, FB_ROTATE_UR)) { /* Start display and show logo on boot */ - fb_set_cmap(&fbdev->fb_info.cmap, - &fbdev->fb_info); - - fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR); + fb_set_cmap(&fbi->cmap, fbi); + fb_show_logo(fbi, FB_ROTATE_UR); } #endif } @@ -1705,12 +1712,13 @@ static int au1200fb_drv_probe(struct platform_device *dev) failed: /* NOTE: This only does the current plane/window that failed; others are still active */ if (fbdev->fb_mem) - dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), + dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); + if (fbi) { + if (fbi->cmap.len != 0) + fb_dealloc_cmap(&fbi->cmap); + kfree(fbi->pseudo_palette); + } if (plane == 0) free_irq(AU1200_LCD_INT, (void*)dev); return ret; @@ -1719,6 +1727,7 @@ failed: static int au1200fb_drv_remove(struct platform_device *dev) { struct au1200fb_device *fbdev; + struct fb_info *fbi; int plane; if (!dev) @@ -1727,20 +1736,22 @@ static int au1200fb_drv_remove(struct platform_device *dev) /* Turn off the panel */ au1200_setpanel(NULL); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) - { - fbdev = &_au1200fb_devices[plane]; + for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { + fbi = _au1200fb_infos[plane]; + fbdev = fbi->par; /* Clean up all probe data */ - unregister_framebuffer(&fbdev->fb_info); + unregister_framebuffer(fbi); if (fbdev->fb_mem) dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len), fbdev->fb_mem, fbdev->fb_phys); - if (fbdev->fb_info.cmap.len != 0) - fb_dealloc_cmap(&fbdev->fb_info.cmap); - if (fbdev->fb_info.pseudo_palette) - kfree(fbdev->fb_info.pseudo_palette); + if (fbi->cmap.len != 0) + fb_dealloc_cmap(&fbi->cmap); + kfree(fbi->pseudo_palette); + + framebuffer_release(fbi); + _au1200fb_infos[plane] = NULL; } free_irq(AU1200_LCD_INT, (void *)dev); @@ -1749,7 +1760,8 @@ static int au1200fb_drv_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int au1200fb_drv_suspend(struct platform_device *dev, u32 state) +static int au1200fb_drv_suspend(struct platform_device *dev, + pm_message_t state) { /* TODO */ return 0; -- cgit v1.2.3 From 98707fcc044c2e6120448041bf738d1b134cfaa4 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 10 Jun 2011 15:23:02 +0000 Subject: au1200fb: fixup PM Remove last traces of the unused custom Alchemy PM code, implement suspend/resume callbacks. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/video/au1200fb.c | 154 ++++++++++++----------------------------------- 1 file changed, 39 insertions(+), 115 deletions(-) diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 442d005e452d..480ecb1b9d0b 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -46,10 +46,6 @@ #include #include "au1200fb.h" -#ifdef CONFIG_PM -#include -#endif - #ifndef CONFIG_FB_AU1200_DEVS #define CONFIG_FB_AU1200_DEVS 4 #endif @@ -205,12 +201,6 @@ struct window_settings { extern int board_au1200fb_panel_init (void); extern int board_au1200fb_panel_shutdown (void); -#ifdef CONFIG_PM -int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data); -au1xxx_power_dev_t *LCD_pm_dev; -#endif - /* * Default window configurations */ @@ -652,25 +642,6 @@ static struct panel_settings known_lcd_panels[] = /********************************************************************/ -#ifdef CONFIG_PM -static int set_brightness(unsigned int brightness) -{ - unsigned int hi1, divider; - - /* limit brightness pwm duty to >= 30/1600 */ - if (brightness < 30) { - brightness = 30; - } - divider = (lcd->pwmdiv & 0x3FFFF) + 1; - hi1 = (lcd->pwmhi >> 16) + 1; - hi1 = (((brightness & 0xFF) + 1) * divider >> 8); - lcd->pwmhi &= 0xFFFF; - lcd->pwmhi |= (hi1 << 16); - - return brightness; -} -#endif /* CONFIG_PM */ - static int winbpp (unsigned int winctrl1) { int bits = 0; @@ -1248,10 +1219,6 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) unsigned long start=0, off; struct au1200fb_device *fbdev = info->par; -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif - if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { return -EINVAL; } @@ -1461,10 +1428,6 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd, int plane; int val; -#ifdef CONFIG_PM - au1xxx_pm_access(LCD_pm_dev); -#endif - plane = fbinfo2index(info); print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); @@ -1622,7 +1585,7 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) /* AU1200 LCD controller device driver */ -static int au1200fb_drv_probe(struct platform_device *dev) +static int __devinit au1200fb_drv_probe(struct platform_device *dev) { struct au1200fb_device *fbdev; struct fb_info *fbi = NULL; @@ -1633,6 +1596,9 @@ static int au1200fb_drv_probe(struct platform_device *dev) ret = 0; fbdev = NULL; + /* Kickstart the panel */ + au1200_setpanel(panel); + for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) @@ -1724,15 +1690,12 @@ failed: return ret; } -static int au1200fb_drv_remove(struct platform_device *dev) +static int __devexit au1200fb_drv_remove(struct platform_device *dev) { struct au1200fb_device *fbdev; struct fb_info *fbi; int plane; - if (!dev) - return -ENODEV; - /* Turn off the panel */ au1200_setpanel(NULL); @@ -1760,31 +1723,53 @@ static int au1200fb_drv_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int au1200fb_drv_suspend(struct platform_device *dev, - pm_message_t state) +static int au1200fb_drv_suspend(struct device *dev) { - /* TODO */ + au1200_setpanel(NULL); + + lcd->outmask = 0; + au_sync(); + return 0; } -static int au1200fb_drv_resume(struct platform_device *dev) +static int au1200fb_drv_resume(struct device *dev) { - /* TODO */ + struct fb_info *fbi; + int i; + + /* Kickstart the panel */ + au1200_setpanel(panel); + + for (i = 0; i < CONFIG_FB_AU1200_DEVS; i++) { + fbi = _au1200fb_infos[i]; + au1200fb_fb_set_par(fbi); + } + return 0; } + +static const struct dev_pm_ops au1200fb_pmops = { + .suspend = au1200fb_drv_suspend, + .resume = au1200fb_drv_resume, + .freeze = au1200fb_drv_suspend, + .thaw = au1200fb_drv_resume, +}; + +#define AU1200FB_PMOPS (&au1200fb_pmops) + +#else +#define AU1200FB_PMOPS NULL #endif /* CONFIG_PM */ static struct platform_driver au1200fb_driver = { .driver = { - .name = "au1200-lcd", - .owner = THIS_MODULE, + .name = "au1200-lcd", + .owner = THIS_MODULE, + .pm = AU1200FB_PMOPS, }, .probe = au1200fb_drv_probe, - .remove = au1200fb_drv_remove, -#ifdef CONFIG_PM - .suspend = au1200fb_drv_suspend, - .resume = au1200fb_drv_resume, -#endif + .remove = __devexit_p(au1200fb_drv_remove), }; /*-------------------------------------------------------------------------*/ @@ -1847,56 +1832,6 @@ static void au1200fb_setup(void) } } -#ifdef CONFIG_PM -static int au1200fb_pm_callback(au1xxx_power_dev_t *dev, - au1xxx_request_t request, void *data) { - int retval = -1; - unsigned int d = 0; - unsigned int brightness = 0; - - if (request == AU1XXX_PM_SLEEP) { - board_au1200fb_panel_shutdown(); - } - else if (request == AU1XXX_PM_WAKEUP) { - if(dev->prev_state == SLEEP_STATE) - { - int plane; - au1200_setpanel(panel); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { - struct au1200fb_device *fbdev; - fbdev = &_au1200fb_devices[plane]; - au1200fb_fb_set_par(&fbdev->fb_info); - } - } - - d = *((unsigned int*)data); - if(d <=10) brightness = 26; - else if(d<=20) brightness = 51; - else if(d<=30) brightness = 77; - else if(d<=40) brightness = 102; - else if(d<=50) brightness = 128; - else if(d<=60) brightness = 153; - else if(d<=70) brightness = 179; - else if(d<=80) brightness = 204; - else if(d<=90) brightness = 230; - else brightness = 255; - set_brightness(brightness); - } else if (request == AU1XXX_PM_GETSTATUS) { - return dev->cur_state; - } else if (request == AU1XXX_PM_ACCESS) { - if (dev->cur_state != SLEEP_STATE) - return retval; - else { - au1200_setpanel(panel); - } - } else if (request == AU1XXX_PM_IDLE) { - } else if (request == AU1XXX_PM_CLEANUP) { - } - - return retval; -} -#endif - static int __init au1200fb_init(void) { print_info("" DRIVER_DESC ""); @@ -1911,17 +1846,6 @@ static int __init au1200fb_init(void) printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); - /* Kickstart the panel, the framebuffers/windows come soon enough */ - au1200_setpanel(panel); - - #ifdef CONFIG_PM - LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL); - if ( LCD_pm_dev == NULL) - printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n"); - else - printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n"); - #endif - return platform_driver_register(&au1200fb_driver); } -- cgit v1.2.3 From 8be90b07ac2a07b4f1eb685caa97e88b9f85ef27 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 10 Jun 2011 15:23:03 +0000 Subject: au1200fb: make number of windows configurable at load time. Make the number of framebuffer windows and the window configuration selectable at the kernel commandline instead of hardcoding it in the kernel config. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/video/au1200fb.c | 53 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 480ecb1b9d0b..4b58f7ba5728 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -46,10 +46,6 @@ #include #include "au1200fb.h" -#ifndef CONFIG_FB_AU1200_DEVS -#define CONFIG_FB_AU1200_DEVS 4 -#endif - #define DRIVER_NAME "au1200fb" #define DRIVER_DESC "LCD controller driver for AU1200 processors" @@ -154,7 +150,6 @@ struct au1200fb_device { dma_addr_t fb_phys; }; -static struct fb_info *_au1200fb_infos[CONFIG_FB_AU1200_DEVS]; /********************************************************************/ /* LCD controller restrictions */ @@ -167,10 +162,18 @@ static struct fb_info *_au1200fb_infos[CONFIG_FB_AU1200_DEVS]; /* Default number of visible screen buffer to allocate */ #define AU1200FB_NBR_VIDEO_BUFFERS 1 +/* Default maximum number of fb devices to create */ +#define MAX_DEVICE_COUNT 4 + +/* Default window configuration entry to use (see windows[]) */ +#define DEFAULT_WINDOW_INDEX 2 + /********************************************************************/ +static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT]; static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; -static int window_index = 2; /* default is zero */ +static int device_count = MAX_DEVICE_COUNT; +static int window_index = DEFAULT_WINDOW_INDEX; /* default is zero */ static int panel_index = 2; /* default is zero */ static struct window_settings *win; static struct panel_settings *panel; @@ -683,7 +686,7 @@ static int fbinfo2index (struct fb_info *fb_info) { int i; - for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { + for (i = 0; i < device_count; ++i) { if (fb_info == _au1200fb_infos[i]) return i; } @@ -1599,7 +1602,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) /* Kickstart the panel */ au1200_setpanel(panel); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { + for (plane = 0; plane < device_count; ++plane) { bpp = winbpp(win->w[plane].mode_winctrl1); if (win->w[plane].xres == 0) win->w[plane].xres = panel->Xres; @@ -1699,7 +1702,7 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev) /* Turn off the panel */ au1200_setpanel(NULL); - for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { + for (plane = 0; plane < device_count; ++plane) { fbi = _au1200fb_infos[plane]; fbdev = fbi->par; @@ -1741,7 +1744,7 @@ static int au1200fb_drv_resume(struct device *dev) /* Kickstart the panel */ au1200_setpanel(panel); - for (i = 0; i < CONFIG_FB_AU1200_DEVS; i++) { + for (i = 0; i < device_count; i++) { fbi = _au1200fb_infos[i]; au1200fb_fb_set_par(fbi); } @@ -1776,10 +1779,10 @@ static struct platform_driver au1200fb_driver = { /* Kernel driver */ -static void au1200fb_setup(void) +static int au1200fb_setup(void) { - char* options = NULL; - char* this_opt; + char *options = NULL; + char *this_opt, *endptr; int num_panels = ARRAY_SIZE(known_lcd_panels); int panel_idx = -1; @@ -1824,12 +1827,33 @@ static void au1200fb_setup(void) nohwcursor = 1; } + else if (strncmp(this_opt, "devices:", 8) == 0) { + this_opt += 8; + device_count = simple_strtol(this_opt, + &endptr, 0); + if ((device_count < 0) || + (device_count > MAX_DEVICE_COUNT)) + device_count = MAX_DEVICE_COUNT; + } + + else if (strncmp(this_opt, "wincfg:", 7) == 0) { + this_opt += 7; + window_index = simple_strtol(this_opt, + &endptr, 0); + if ((window_index < 0) || + (window_index >= ARRAY_SIZE(windows))) + window_index = DEFAULT_WINDOW_INDEX; + } + + else if (strncmp(this_opt, "off", 3) == 0) + return 1; /* Unsupported option */ else { print_warn("Unsupported option \"%s\"", this_opt); } } } + return 0; } static int __init au1200fb_init(void) @@ -1837,7 +1861,8 @@ static int __init au1200fb_init(void) print_info("" DRIVER_DESC ""); /* Setup driver with options */ - au1200fb_setup(); + if (au1200fb_setup()) + return -ENODEV; /* Point to the panel selected */ panel = &known_lcd_panels[panel_index]; -- cgit v1.2.3 From 4ee58461510221a53080afd02752838f93cc57fc Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Fri, 10 Jun 2011 15:23:04 +0000 Subject: au1200fb: switch to FB_SYS helpers Since all video memory is in system ram, use FB_SYS helpers. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 7 ++++--- drivers/video/au1200fb.c | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 549b960667c8..5e19de97242a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1756,9 +1756,10 @@ config FB_AU1100 config FB_AU1200 bool "Au1200 LCD Driver" depends on (FB = y) && MIPS && SOC_AU1200 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS help This is the framebuffer driver for the AMD Au1200 SOC. It can drive various panels and CRTs by passing in kernel cmd line option diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index 4b58f7ba5728..b1b16d98c919 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1502,9 +1502,11 @@ static struct fb_ops au1200fb_fb_ops = { .fb_set_par = au1200fb_fb_set_par, .fb_setcolreg = au1200fb_fb_setcolreg, .fb_blank = au1200fb_fb_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_read = fb_sys_read, + .fb_write = fb_sys_write, .fb_sync = NULL, .fb_ioctl = au1200fb_ioctl, .fb_mmap = au1200fb_fb_mmap, -- cgit v1.2.3 From 1630d85a831273868651d46d74f069e0cdf9b698 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sun, 12 Jun 2011 17:15:29 +0000 Subject: au1200fb: fix hardcoded IRQ Use the IRQ provided by platform resource information. Required for Au1300 support. Signed-off-by: Manuel Lauss Signed-off-by: Paul Mundt --- drivers/video/au1200fb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c index b1b16d98c919..ed5dcdb29cf7 100644 --- a/drivers/video/au1200fb.c +++ b/drivers/video/au1200fb.c @@ -1595,7 +1595,7 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) struct au1200fb_device *fbdev; struct fb_info *fbi = NULL; unsigned long page; - int bpp, plane, ret; + int bpp, plane, ret, irq; /* shut gcc up */ ret = 0; @@ -1671,10 +1671,12 @@ static int __devinit au1200fb_drv_probe(struct platform_device *dev) } /* Now hook interrupt too */ - if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, - IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) { + irq = platform_get_irq(dev, 0); + ret = request_irq(irq, au1200fb_handle_irq, + IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev); + if (ret) { print_err("fail to request interrupt line %d (err: %d)", - AU1200_LCD_INT, ret); + irq, ret); goto failed; } @@ -1722,7 +1724,7 @@ static int __devexit au1200fb_drv_remove(struct platform_device *dev) _au1200fb_infos[plane] = NULL; } - free_irq(AU1200_LCD_INT, (void *)dev); + free_irq(platform_get_irq(dev, 0), (void *)dev); return 0; } -- cgit v1.2.3 From 181b74ef794e198df36fbc8c962126a11a01d395 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 15 Jun 2011 16:57:21 +0200 Subject: video: don't use flush_scheduled_work() in fb_defio flush_scheduled_work() in on the way out. fb_deferred_io_cleanup() can simply sync-cancel info->deferred_work instead of cancel + flush_scheduled_work(). Drop flush_scheduled_work() usage. Signed-off-by: Tejun Heo Cc: Jaya Kumar Signed-off-by: Paul Mundt --- drivers/video/fb_defio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 804000183c5e..a79c0dedfbd4 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -216,8 +216,7 @@ void fb_deferred_io_cleanup(struct fb_info *info) int i; BUG_ON(!fbdefio); - cancel_delayed_work(&info->deferred_work); - flush_scheduled_work(); + cancel_delayed_work_sync(&info->deferred_work); /* clear out the mapping that we setup */ for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { -- cgit v1.2.3 From 75e1b6a84f7e2186e843da94751b6d175caf9209 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 23 Jun 2011 22:35:19 +0000 Subject: video: Fix speficied typo Signed-off-by: Joe Perches Signed-off-by: Paul Mundt --- drivers/video/controlfb.c | 2 +- drivers/video/platinumfb.c | 2 +- drivers/video/pm2fb.c | 2 +- drivers/video/pm3fb.c | 2 +- drivers/video/s3fb.c | 2 +- drivers/video/skeletonfb.c | 2 +- drivers/video/valkyriefb.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index c225dcce89e7..f6944019cb66 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -550,7 +550,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro /* - * Parse user speficied options (`video=controlfb:') + * Parse user specified options (`video=controlfb:') */ static void __init control_setup(char *options) { diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c index ef532d9d3c99..a0d0c3d625b9 100644 --- a/drivers/video/platinumfb.c +++ b/drivers/video/platinumfb.c @@ -490,7 +490,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var, /* - * Parse user speficied options (`video=platinumfb:') + * Parse user specified options (`video=platinumfb:') */ static int __init platinumfb_setup(char *options) { diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index f4f8ce802d02..dc7bfa91e57a 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1773,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table); #ifndef MODULE /** - * Parse user speficied options. + * Parse user specified options. * * This is, comma-separated options following `video=pm2fb:'. */ diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 8221b5b42da9..6632ee5ecb7e 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -1525,7 +1525,7 @@ static int __init pm3fb_setup(char *options) { char *this_opt; - /* Parse user speficied options (`video=pm3fb:') */ + /* Parse user specified options (`video=pm3fb:') */ if (!options || !*options) return 0; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 0f9af1aa5077..946a949f4c7d 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -1505,7 +1505,7 @@ static struct pci_driver s3fb_pci_driver = { .resume = s3_pci_resume, }; -/* Parse user speficied options */ +/* Parse user specified options */ #ifndef MODULE static int __init s3fb_setup(char *options) diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c index 89158bc71da2..30f7a815a62b 100644 --- a/drivers/video/skeletonfb.c +++ b/drivers/video/skeletonfb.c @@ -989,7 +989,7 @@ static struct platform_device *xxxfb_device; */ int __init xxxfb_setup(char *options) { - /* Parse user speficied options (`video=xxxfb:') */ + /* Parse user specified options (`video=xxxfb:') */ } #endif /* MODULE */ diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c index 6b52bf65f0b5..3f5a041601da 100644 --- a/drivers/video/valkyriefb.c +++ b/drivers/video/valkyriefb.c @@ -555,7 +555,7 @@ static int __init valkyrie_init_info(struct fb_info *info, /* - * Parse user speficied options (`video=valkyriefb:') + * Parse user specified options (`video=valkyriefb:') */ int __init valkyriefb_setup(char *options) { -- cgit v1.2.3 From dd37739f47ea278a57d66b2afe20243f0a6294a0 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 23 Jun 2011 22:35:17 +0000 Subject: Remove unneeded version.h includes from drivers/video/ It was pointed out by 'make versioncheck' that some includes of linux/version.h are not needed in drivers/video/. This patch removes them. Signed-off-by: Jesper Juhl Acked-by: Mike Frysinger Signed-off-by: Paul Mundt --- drivers/video/backlight/adp8860_bl.c | 1 - drivers/video/backlight/adp8870_bl.c | 1 - drivers/video/pxa3xx-gcu.c | 2 -- drivers/video/xilinxfb.c | 1 - 4 files changed, 5 deletions(-) diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index d2a96a421ffd..24a6dfd21b35 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index 05a8832bb3eb..383c4c364b5f 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 0283c7021090..d8de5577d3cf 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c @@ -31,8 +31,6 @@ */ #include -#include - #include #include #include diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index 77dea015ff69..fcb6cd90f64d 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From aeae1e92daec5a38b40ad12598b97501b675a381 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Sun, 3 Jul 2011 21:41:33 -0400 Subject: tools/power turbostat: less verbose debugging dump only the counters which are active Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 6d8ef4a3a9b5..dd2d1a2bdae9 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -162,19 +162,21 @@ void print_header(void) void dump_cnt(struct counters *cnt) { - fprintf(stderr, "package: %d ", cnt->pkg); - fprintf(stderr, "core:: %d ", cnt->core); - fprintf(stderr, "CPU: %d ", cnt->cpu); - fprintf(stderr, "TSC: %016llX\n", cnt->tsc); - fprintf(stderr, "c3: %016llX\n", cnt->c3); - fprintf(stderr, "c6: %016llX\n", cnt->c6); - fprintf(stderr, "c7: %016llX\n", cnt->c7); - fprintf(stderr, "aperf: %016llX\n", cnt->aperf); - fprintf(stderr, "pc2: %016llX\n", cnt->pc2); - fprintf(stderr, "pc3: %016llX\n", cnt->pc3); - fprintf(stderr, "pc6: %016llX\n", cnt->pc6); - fprintf(stderr, "pc7: %016llX\n", cnt->pc7); - fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); + if (!cnt) + return; + if (cnt->pkg) fprintf(stderr, "package: %d ", cnt->pkg); + if (cnt->core) fprintf(stderr, "core:: %d ", cnt->core); + if (cnt->cpu) fprintf(stderr, "CPU: %d ", cnt->cpu); + if (cnt->tsc) fprintf(stderr, "TSC: %016llX\n", cnt->tsc); + if (cnt->c3) fprintf(stderr, "c3: %016llX\n", cnt->c3); + if (cnt->c6) fprintf(stderr, "c6: %016llX\n", cnt->c6); + if (cnt->c7) fprintf(stderr, "c7: %016llX\n", cnt->c7); + if (cnt->aperf) fprintf(stderr, "aperf: %016llX\n", cnt->aperf); + if (cnt->pc2) fprintf(stderr, "pc2: %016llX\n", cnt->pc2); + if (cnt->pc3) fprintf(stderr, "pc3: %016llX\n", cnt->pc3); + if (cnt->pc6) fprintf(stderr, "pc6: %016llX\n", cnt->pc6); + if (cnt->pc7) fprintf(stderr, "pc7: %016llX\n", cnt->pc7); + if (cnt->extra_msr) fprintf(stderr, "msr0x%x: %016llX\n", extra_msr_offset, cnt->extra_msr); } void dump_list(struct counters *cnt) -- cgit v1.2.3 From 945903c7a477784e796168ef87b5022241cb52b5 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 4 Jul 2011 16:11:45 +0200 Subject: drivers/video/msm/mdp.c: adjust error handling code Use the error handling code at the end of the function, rather than returning directly. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @r@ identifier x; @@ kfree(x) @@ identifier r.x; expression E1!=0,E2,E3,E4; statement S; @@ ( if (<+...x...+>) S | if (...) { ... when != kfree(x) when != if (...) { ... kfree(x); ... } when != x = E3 * return E1; } ... when != x = E2 if (...) { ... when != x = E4 kfree(x); ... return ...; } ) // Signed-off-by: Julia Lawall Signed-off-by: Paul Mundt --- drivers/video/msm/mdp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c index c3636d55a3c5..7e94ee3d2521 100644 --- a/drivers/video/msm/mdp.c +++ b/drivers/video/msm/mdp.c @@ -422,7 +422,8 @@ int mdp_probe(struct platform_device *pdev) clk = clk_get(&pdev->dev, "mdp_clk"); if (IS_ERR(clk)) { printk(KERN_INFO "mdp: failed to get mdp clk"); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto error_get_clk; } ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); @@ -496,6 +497,7 @@ int mdp_probe(struct platform_device *pdev) error_device_register: free_irq(mdp->irq, mdp); error_request_irq: +error_get_clk: iounmap(mdp->base); error_get_irq: error_ioremap: -- cgit v1.2.3 From c91a793f66d5b06292aa431ae3a36c8aca991fa3 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 5 Jul 2011 17:04:11 -0700 Subject: drivers/video/udlfb bind framebuffer to interface. Udlfb has been binding the framebuffer device to its parent, which isn't correct and causes confusion with operations like udev remove. Coming plug and play multiseat support is dependent on this fix. Signed-off-by: Kay Sievers Signed-off-by: Bernie Thompson Signed-off-by: Paul Mundt --- drivers/video/udlfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index 816a4fda04f5..c6584c9f235a 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -1549,7 +1549,7 @@ static int dlfb_usb_probe(struct usb_interface *interface, /* We don't register a new USB class. Our client interface is fbdev */ /* allocates framebuffer driver structure, not framebuffer memory */ - info = framebuffer_alloc(0, &usbdev->dev); + info = framebuffer_alloc(0, &interface->dev); if (!info) { retval = -ENOMEM; pr_err("framebuffer_alloc failed\n"); -- cgit v1.2.3 From af48d1c6c85752053ddfed5cfb3933d6336d645c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 7 Jul 2011 12:20:37 +0200 Subject: video: s3c2410: remove unused variable Fixes: drivers/video/s3c2410fb.c: In function 's3c2410fb_cpufreq_transition': drivers/video/s3c2410fb.c:770:24: warning: unused variable 'freqs' Signed-off-by: Wolfram Sang Cc: Paul Mundt Signed-off-by: Paul Mundt --- drivers/video/s3c2410fb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index 0aa13761de6e..798144a4eedd 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -767,7 +767,6 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) static int s3c2410fb_cpufreq_transition(struct notifier_block *nb, unsigned long val, void *data) { - struct cpufreq_freqs *freqs = data; struct s3c2410fb_info *info; struct fb_info *fbinfo; long delta_f; -- cgit v1.2.3 From c84c14224bbca6ec60d5851fcc87be0e34df2f44 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 8 Jul 2011 11:04:38 +0200 Subject: carminefb: Fix module parameters permissions The third parameter of module_param is supposed to be an octal value. The missing leading "0" causes the following: $ ls -l /sys/module/carminefb/parameters/ total 0 -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_displays -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode_str After fixing the perm parameter, we get the expected: $ ls -l /sys/module/carminefb/parameters/ total 0 -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_displays -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode_str Signed-off-by: Jean Delvare Cc: Paul Mundt Cc: Sebastian Siewior Cc: stable@kernel.org Signed-off-by: Paul Mundt --- drivers/video/carminefb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index caaa27d4a46a..cb09aa1fa138 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -32,11 +32,11 @@ #define CARMINEFB_DEFAULT_VIDEO_MODE 1 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; -module_param(fb_mode, uint, 444); +module_param(fb_mode, uint, 0444); MODULE_PARM_DESC(fb_mode, "Initial video mode as integer."); static char *fb_mode_str; -module_param(fb_mode_str, charp, 444); +module_param(fb_mode_str, charp, 0444); MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); /* @@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); * 0b010 Display 1 */ static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1; -module_param(fb_displays, int, 444); +module_param(fb_displays, int, 0444); MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used"); struct carmine_hw { -- cgit v1.2.3 From b63d10130e68aa6480cc1b2483d7c5ce57a05481 Mon Sep 17 00:00:00 2001 From: Bernie Thompson Date: Sun, 10 Jul 2011 00:30:00 -0700 Subject: drivers/video/udlfb match class, subclass, and protocol Match udlfb only against vendor-specific class (e.g. only DisplayLink graphics, not composite standard audio class interfaces). This enables compatibility with composite graphics+audio devices (e.g. HDMI). Match udlfb only against compatible subclass 0 and protocol 0 chips. DisplayLink's USB 3.0 generation chips increment these values to signal that they have a incompatible protocol, preventing udlfb from erroneously matching to hardware it does not support. Tested to confirm proper behavior on both USB 2.0 and USB 3.0 generation devices. Reported-by: Andrew Kephart Signed-off-by: Bernie Thompson Signed-off-by: Paul Mundt --- drivers/video/udlfb.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c index c6584c9f235a..4e133754ba2b 100644 --- a/drivers/video/udlfb.c +++ b/drivers/video/udlfb.c @@ -49,13 +49,22 @@ static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR; /* - * There are many DisplayLink-based products, all with unique PIDs. We are able - * to support all volume ones (circa 2009) with a single driver, so we match - * globally on VID. TODO: Probe() needs to detect when we might be running - * "future" chips, and bail on those, so a compatible driver can match. + * There are many DisplayLink-based graphics products, all with unique PIDs. + * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff) + * We also require a match on SubClass (0x00) and Protocol (0x00), + * which is compatible with all known USB 2.0 era graphics chips and firmware, + * but allows DisplayLink to increment those for any future incompatible chips */ static struct usb_device_id id_table[] = { - {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, + {.idVendor = 0x17e9, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0x00, + .bInterfaceProtocol = 0x00, + .match_flags = USB_DEVICE_ID_MATCH_VENDOR | + USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL, + }, {}, }; MODULE_DEVICE_TABLE(usb, id_table); -- cgit v1.2.3 From a4b8f97a8fdeb94492738c36fddbd2cf822ed138 Mon Sep 17 00:00:00 2001 From: Kristoffer Glembo Date: Tue, 5 Jul 2011 09:29:19 +0200 Subject: video: Add Aeroflex Gaisler GRVGA framebuffer device driver This patch adds support for the GRVGA framebuffer IP core from Aeroflex Gaisler. The device is used in LEON SPARCV8 based System on Chips. Documentation can be found here: www.gaisler.com/products/grlib/grip.pdf. Signed-off-by: Kristoffer Glembo Signed-off-by: Paul Mundt --- drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/grvga.c | 579 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 589 insertions(+) create mode 100644 drivers/video/grvga.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 5e19de97242a..e087fc2207e7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -259,6 +259,15 @@ config FB_TILEBLITTING comment "Frame buffer hardware drivers" depends on FB +config FB_GRVGA + tristate "Aeroflex Gaisler framebuffer support" + depends on FB && SPARC + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler. + config FB_CIRRUS tristate "Cirrus Logic support" depends on FB && (ZORRO || PCI) diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 8b83129e209c..43079108bb16 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o +obj-$(CONFIG_FB_GRVGA) += grvga.o obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c new file mode 100644 index 000000000000..f37e02538203 --- /dev/null +++ b/drivers/video/grvga.c @@ -0,0 +1,579 @@ +/* + * Driver for Aeroflex Gaisler SVGACTRL framebuffer device. + * + * 2011 (c) Aeroflex Gaisler AB + * + * Full documentation of the core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: Kristoffer Glembo + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct grvga_regs { + u32 status; /* 0x00 */ + u32 video_length; /* 0x04 */ + u32 front_porch; /* 0x08 */ + u32 sync_length; /* 0x0C */ + u32 line_length; /* 0x10 */ + u32 fb_pos; /* 0x14 */ + u32 clk_vector[4]; /* 0x18 */ + u32 clut; /* 0x20 */ +}; + +struct grvga_par { + struct grvga_regs *regs; + u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */ + int clk_sel; + int fb_alloced; /* = 1 if framebuffer is allocated in main memory */ +}; + + +static const struct fb_videomode grvga_modedb[] = { + { + /* 640x480 @ 60 Hz */ + NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 60 Hz */ + NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, + 0, FB_VMODE_NONINTERLACED + }, { + /* 800x600 @ 72 Hz */ + NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, + 0, FB_VMODE_NONINTERLACED + }, { + /* 1024x768 @ 60 Hz */ + NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED + } + }; + +static struct fb_fix_screeninfo grvga_fix __initdata = { + .id = "AG SVGACTRL", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_PSEUDOCOLOR, + .xpanstep = 0, + .ypanstep = 1, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +static int grvga_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct grvga_par *par = info->par; + int i; + + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; + if (var->bits_per_pixel <= 8) + var->bits_per_pixel = 8; + else if (var->bits_per_pixel <= 16) + var->bits_per_pixel = 16; + else if (var->bits_per_pixel <= 24) + var->bits_per_pixel = 24; + else if (var->bits_per_pixel <= 32) + var->bits_per_pixel = 32; + else + return -EINVAL; + + var->xres_virtual = var->xres; + var->yres_virtual = 2*var->yres; + + if (info->fix.smem_len) { + if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len) + return -ENOMEM; + } + + /* Which clocks that are available can be read out in these registers */ + for (i = 0; i <= 3 ; i++) { + if (var->pixclock == par->regs->clk_vector[i]) + break; + } + if (i <= 3) + par->clk_sel = i; + else + return -EINVAL; + + switch (info->var.bits_per_pixel) { + case 8: + var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */ + var->green = (struct fb_bitfield) {0, 8, 0}; + var->blue = (struct fb_bitfield) {0, 8, 0}; + var->transp = (struct fb_bitfield) {0, 0, 0}; + break; + case 16: + var->red = (struct fb_bitfield) {11, 5, 0}; + var->green = (struct fb_bitfield) {5, 6, 0}; + var->blue = (struct fb_bitfield) {0, 5, 0}; + var->transp = (struct fb_bitfield) {0, 0, 0}; + break; + case 24: + case 32: + var->red = (struct fb_bitfield) {16, 8, 0}; + var->green = (struct fb_bitfield) {8, 8, 0}; + var->blue = (struct fb_bitfield) {0, 8, 0}; + var->transp = (struct fb_bitfield) {24, 8, 0}; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int grvga_set_par(struct fb_info *info) +{ + + u32 func = 0; + struct grvga_par *par = info->par; + + __raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1), + &par->regs->video_length); + + __raw_writel((info->var.lower_margin << 16) | (info->var.right_margin), + &par->regs->front_porch); + + __raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len), + &par->regs->sync_length); + + __raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) | + (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1), + &par->regs->line_length); + + switch (info->var.bits_per_pixel) { + case 8: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + func = 1; + break; + case 16: + info->fix.visual = FB_VISUAL_TRUECOLOR; + func = 2; + break; + case 24: + case 32: + info->fix.visual = FB_VISUAL_TRUECOLOR; + func = 3; + break; + default: + return -EINVAL; + } + + __raw_writel((par->clk_sel << 6) | (func << 4) | 1, + &par->regs->status); + + info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8; + return 0; +} + +static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) +{ + struct grvga_par *par; + par = info->par; + + if (regno >= 256) /* Size of CLUT */ + return -EINVAL; + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + + +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + +#undef CNVT_TOHW + + /* In PSEUDOCOLOR we use the hardware CLUT */ + if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) + __raw_writel((regno << 24) | (red << 16) | (green << 8) | blue, + &par->regs->clut); + + /* Truecolor uses the pseudo palette */ + else if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + if (regno >= 16) + return -EINVAL; + + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + ((u32 *) (info->pseudo_palette))[regno] = v; + } + return 0; +} + +static int grvga_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct grvga_par *par = info->par; + struct fb_fix_screeninfo *fix = &info->fix; + u32 base_addr; + + if (var->xoffset != 0) + return -EINVAL; + + base_addr = fix->smem_start + (var->yoffset * fix->line_length); + base_addr &= ~3UL; + + /* Set framebuffer base address */ + __raw_writel(base_addr, + &par->regs->fb_pos); + + return 0; +} + +static struct fb_ops grvga_ops = { + .owner = THIS_MODULE, + .fb_check_var = grvga_check_var, + .fb_set_par = grvga_set_par, + .fb_setcolreg = grvga_setcolreg, + .fb_pan_display = grvga_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit +}; + +static int __init grvga_parse_custom(char *options, + struct fb_var_screeninfo *screendata) +{ + char *this_opt; + int count = 0; + if (!options || !*options) + return -1; + + while ((this_opt = strsep(&options, " ")) != NULL) { + if (!*this_opt) + continue; + + switch (count) { + case 0: + screendata->pixclock = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 1: + screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 2: + screendata->right_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 3: + screendata->hsync_len = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 4: + screendata->left_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 5: + screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 6: + screendata->lower_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 7: + screendata->vsync_len = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 8: + screendata->upper_margin = simple_strtoul(this_opt, NULL, 0); + count++; + break; + case 9: + screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0); + count++; + break; + default: + return -1; + } + } + screendata->activate = FB_ACTIVATE_NOW; + screendata->vmode = FB_VMODE_NONINTERLACED; + return 0; +} + +static int __devinit grvga_probe(struct platform_device *dev) +{ + struct fb_info *info; + int retval = -ENOMEM; + unsigned long virtual_start; + unsigned long grvga_fix_addr = 0; + unsigned long physical_start = 0; + unsigned long grvga_mem_size = 0; + struct grvga_par *par = NULL; + char *options = NULL, *mode_opt = NULL; + + info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev); + if (!info) { + dev_err(&dev->dev, "framebuffer_alloc failed\n"); + return -ENOMEM; + } + + /* Expecting: "grvga: modestring, [addr:], [size:] + * + * If modestring is custom: we parse the string which then contains all videoparameters + * If address is left out, we allocate memory, + * if size is left out we only allocate enough to support the given mode. + */ + if (fb_get_options("grvga", &options)) { + retval = -ENODEV; + goto err; + } + + if (!options || !*options) + options = "640x480-8@60"; + + while (1) { + char *this_opt = strsep(&options, ","); + + if (!this_opt) + break; + + if (!strncmp(this_opt, "custom", 6)) { + if (grvga_parse_custom(this_opt, &info->var) < 0) { + dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt); + retval = -EINVAL; + goto err1; + } + } else if (!strncmp(this_opt, "addr", 4)) + grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16); + else if (!strncmp(this_opt, "size", 4)) + grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0); + else + mode_opt = this_opt; + } + + par = info->par; + info->fbops = &grvga_ops; + info->fix = grvga_fix; + info->pseudo_palette = par->color_palette; + info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN; + info->fix.smem_len = grvga_mem_size; + + if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) { + dev_err(&dev->dev, "registers already mapped\n"); + retval = -EBUSY; + goto err; + } + + par->regs = of_ioremap(&dev->resource[0], 0, + resource_size(&dev->resource[0]), + "grlib-svgactrl regs"); + + if (!par->regs) { + dev_err(&dev->dev, "failed to map registers\n"); + retval = -ENOMEM; + goto err1; + } + + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) { + dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n"); + retval = -ENOMEM; + goto err2; + } + + if (mode_opt) { + retval = fb_find_mode(&info->var, info, mode_opt, + grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8); + if (!retval || retval == 4) { + retval = -EINVAL; + goto err3; + } + } + + if (!grvga_mem_size) + grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8; + + if (grvga_fix_addr) { + /* Got framebuffer base address from argument list */ + + physical_start = grvga_fix_addr; + + if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) { + dev_err(&dev->dev, "failed to request memory region\n"); + retval = -ENOMEM; + goto err3; + } + + virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size); + + if (!virtual_start) { + dev_err(&dev->dev, "error mapping framebuffer memory\n"); + retval = -ENOMEM; + goto err4; + } + } else { /* Allocate frambuffer memory */ + + unsigned long page; + + virtual_start = (unsigned long) __get_free_pages(GFP_DMA, + get_order(grvga_mem_size)); + if (!virtual_start) { + dev_err(&dev->dev, + "unable to allocate framebuffer memory (%lu bytes)\n", + grvga_mem_size); + retval = -ENOMEM; + goto err3; + } + + physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE); + + /* Set page reserved so that mmap will work. This is necessary + * since we'll be remapping normal memory. + */ + for (page = virtual_start; + page < PAGE_ALIGN(virtual_start + grvga_mem_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + par->fb_alloced = 1; + } + + memset((unsigned long *) virtual_start, 0, grvga_mem_size); + + info->screen_base = (char __iomem *) virtual_start; + info->fix.smem_start = physical_start; + info->fix.smem_len = grvga_mem_size; + + dev_set_drvdata(&dev->dev, info); + + dev_info(&dev->dev, + "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n", + info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel, + grvga_mem_size >> 10, info->screen_base); + + retval = register_framebuffer(info); + if (retval < 0) { + dev_err(&dev->dev, "failed to register framebuffer\n"); + goto err4; + } + + __raw_writel(physical_start, &par->regs->fb_pos); + __raw_writel(__raw_readl(&par->regs->status) | 1, /* Enable framebuffer */ + &par->regs->status); + + return 0; + +err4: + dev_set_drvdata(&dev->dev, NULL); + if (grvga_fix_addr) { + release_mem_region(physical_start, grvga_mem_size); + iounmap((void *)virtual_start); + } else + kfree((void *)virtual_start); +err3: + fb_dealloc_cmap(&info->cmap); +err2: + of_iounmap(&dev->resource[0], par->regs, + resource_size(&dev->resource[0])); +err1: + release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0])); +err: + framebuffer_release(info); + + return retval; +} + +static int __devexit grvga_remove(struct platform_device *device) +{ + struct fb_info *info = dev_get_drvdata(&device->dev); + struct grvga_par *par = info->par; + + if (info) { + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); + + of_iounmap(&device->resource[0], par->regs, + resource_size(&device->resource[0])); + release_mem_region(device->resource[0].start, resource_size(&device->resource[0])); + + if (!par->fb_alloced) { + release_mem_region(info->fix.smem_start, info->fix.smem_len); + iounmap(info->screen_base); + } else + kfree((void *)info->screen_base); + + framebuffer_release(info); + dev_set_drvdata(&device->dev, NULL); + } + + return 0; +} + +static struct of_device_id svgactrl_of_match[] = { + { + .name = "GAISLER_SVGACTRL", + }, + { + .name = "01_063", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, svgactrl_of_match); + +static struct platform_driver grvga_driver = { + .driver = { + .name = "grlib-svgactrl", + .owner = THIS_MODULE, + .of_match_table = svgactrl_of_match, + }, + .probe = grvga_probe, + .remove = __devexit_p(grvga_remove), +}; + + +static int __init grvga_init(void) +{ + return platform_driver_register(&grvga_driver); +} + +static void __exit grvga_exit(void) +{ + platform_driver_unregister(&grvga_driver); +} + +module_init(grvga_init); +module_exit(grvga_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aeroflex Gaisler"); +MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver"); -- cgit v1.2.3 From c6daf05b6d7afca4c9e04a7361e284ef9e1d8dad Mon Sep 17 00:00:00 2001 From: "Manjunathappa, Prakash" Date: Tue, 5 Jul 2011 15:51:20 +0530 Subject: video: da8xx-fb: Interrupt configuration of revised LCDC IP An upcoming SoC of TI comes with an LCD controller which is an updated version of that found on TI's DA850 SoC. The da8xx-fb driver can support this LCD with some enhancements. This patch adds support for updated interrupt configuration on the new SoC. 1) Registers for setting and clearing interrupts are different. 2) Raw and masked status registers are different. The updates have been tested on an emulation platform for new features and the patch has been tested on DA850 platform to make sure nothing existing breaks. Signed-off-by: Manjunathappa, Prakash Signed-off-by: Paul Mundt --- drivers/video/da8xx-fb.c | 151 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 142 insertions(+), 9 deletions(-) diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 8d4e4ebd9977..217c05f74541 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -35,6 +35,9 @@ #define DRIVER_NAME "da8xx_lcdc" +#define LCD_VERSION_1 1 +#define LCD_VERSION_2 2 + /* LCD Status Register */ #define LCD_END_OF_FRAME1 BIT(9) #define LCD_END_OF_FRAME0 BIT(8) @@ -49,7 +52,9 @@ #define LCD_DMA_BURST_4 0x2 #define LCD_DMA_BURST_8 0x3 #define LCD_DMA_BURST_16 0x4 -#define LCD_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_V1_END_OF_FRAME_INT_ENA BIT(2) +#define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8) +#define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9) #define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) /* LCD Control Register */ @@ -65,12 +70,18 @@ #define LCD_MONO_8BIT_MODE BIT(9) #define LCD_RASTER_ORDER BIT(8) #define LCD_TFT_MODE BIT(7) -#define LCD_UNDERFLOW_INT_ENA BIT(6) -#define LCD_PL_ENABLE BIT(4) +#define LCD_V1_UNDERFLOW_INT_ENA BIT(6) +#define LCD_V2_UNDERFLOW_INT_ENA BIT(5) +#define LCD_V1_PL_INT_ENA BIT(4) +#define LCD_V2_PL_INT_ENA BIT(6) #define LCD_MONOCHROME_MODE BIT(1) #define LCD_RASTER_ENABLE BIT(0) #define LCD_TFT_ALT_ENABLE BIT(23) #define LCD_STN_565_ENABLE BIT(24) +#define LCD_V2_DMA_CLK_EN BIT(2) +#define LCD_V2_LIDD_CLK_EN BIT(1) +#define LCD_V2_CORE_CLK_EN BIT(0) +#define LCD_V2_LPP_B10 26 /* LCD Raster Timing 2 Register */ #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) @@ -82,6 +93,7 @@ #define LCD_INVERT_FRAME_CLOCK BIT(20) /* LCD Block */ +#define LCD_PID_REG 0x0 #define LCD_CTRL_REG 0x4 #define LCD_STAT_REG 0x8 #define LCD_RASTER_CTRL_REG 0x28 @@ -94,6 +106,17 @@ #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 +/* Interrupt Registers available only in Version 2 */ +#define LCD_RAW_STAT_REG 0x58 +#define LCD_MASKED_STAT_REG 0x5c +#define LCD_INT_ENABLE_SET_REG 0x60 +#define LCD_INT_ENABLE_CLR_REG 0x64 +#define LCD_END_OF_INT_IND_REG 0x68 + +/* Clock registers available only on Version 2 */ +#define LCD_CLK_ENABLE_REG 0x6c +#define LCD_CLK_RESET_REG 0x70 + #define LCD_NUM_BUFFERS 2 #define WSI_TIMEOUT 50 @@ -105,6 +128,8 @@ static resource_size_t da8xx_fb_reg_base; static struct resource *lcdc_regs; +static unsigned int lcd_revision; +static irq_handler_t lcdc_irq_handler; static inline unsigned int lcdc_read(unsigned int addr) { @@ -240,6 +265,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) u32 end; u32 reg_ras; u32 reg_dma; + u32 reg_int; /* init reg to clear PLM (loading mode) fields */ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); @@ -252,7 +278,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) end = par->dma_end; reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); - reg_dma |= LCD_END_OF_FRAME_INT_ENA; + if (lcd_revision == LCD_VERSION_1) { + reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_END_OF_FRAME0_INT_ENA | + LCD_V2_END_OF_FRAME1_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); @@ -264,7 +297,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) end = start + par->palette_sz - 1; reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); - reg_ras |= LCD_PL_ENABLE; + + if (lcd_revision == LCD_VERSION_1) { + reg_ras |= LCD_V1_PL_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_PL_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); @@ -348,6 +388,7 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width, static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) { u32 reg; + u32 reg_int; reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | LCD_MONO_8BIT_MODE | @@ -375,7 +416,13 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) } /* enable additional interrupts here */ - reg |= LCD_UNDERFLOW_INT_ENA; + if (lcd_revision == LCD_VERSION_1) { + reg |= LCD_V1_UNDERFLOW_INT_ENA; + } else { + reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | + LCD_V2_UNDERFLOW_INT_ENA; + lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); + } lcdc_write(reg, LCD_RASTER_CTRL_REG); @@ -511,6 +558,9 @@ static void lcd_reset(struct da8xx_fb_par *par) /* DMA has to be disabled */ lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); + + if (lcd_revision == LCD_VERSION_2) + lcdc_write(0, LCD_INT_ENABLE_SET_REG); } static void lcd_calc_clk_divider(struct da8xx_fb_par *par) @@ -523,6 +573,11 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par) /* Configure the LCD clock divisor. */ lcdc_write(LCD_CLK_DIVISOR(div) | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); + + if (lcd_revision == LCD_VERSION_2) + lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | + LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); + } static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, @@ -583,7 +638,63 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, return 0; } -static irqreturn_t lcdc_irq_handler(int irq, void *arg) +/* IRQ handler for version 2 of LCDC */ +static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) +{ + struct da8xx_fb_par *par = arg; + u32 stat = lcdc_read(LCD_MASKED_STAT_REG); + u32 reg_int; + + if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { + lcd_disable_raster(); + lcdc_write(stat, LCD_MASKED_STAT_REG); + lcd_enable_raster(); + } else if (stat & LCD_PL_LOAD_DONE) { + /* + * Must disable raster before changing state of any control bit. + * And also must be disabled before clearing the PL loading + * interrupt via the following write to the status register. If + * this is done after then one gets multiple PL done interrupts. + */ + lcd_disable_raster(); + + lcdc_write(stat, LCD_MASKED_STAT_REG); + + /* Disable PL completion inerrupt */ + reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) | + (LCD_V2_PL_INT_ENA); + lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG); + + /* Setup and start data loading mode */ + lcd_blit(LOAD_DATA, par); + } else { + lcdc_write(stat, LCD_MASKED_STAT_REG); + + if (stat & LCD_END_OF_FRAME0) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + + if (stat & LCD_END_OF_FRAME1) { + lcdc_write(par->dma_start, + LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); + lcdc_write(par->dma_end, + LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); + par->vsync_flag = 1; + wake_up_interruptible(&par->vsync_wait); + } + } + + lcdc_write(0, LCD_END_OF_INT_IND_REG); + return IRQ_HANDLED; +} + +/* IRQ handler for version 1 LCDC */ +static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) { struct da8xx_fb_par *par = arg; u32 stat = lcdc_read(LCD_STAT_REG); @@ -606,7 +717,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg) /* Disable PL completion inerrupt */ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); - reg_ras &= ~LCD_PL_ENABLE; + reg_ras &= ~LCD_V1_PL_INT_ENA; lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); /* Setup and start data loading mode */ @@ -945,6 +1056,22 @@ static int __devinit fb_probe(struct platform_device *device) if (ret) goto err_clk_put; + /* Determine LCD IP Version */ + switch (lcdc_read(LCD_PID_REG)) { + case 0x4C100102: + lcd_revision = LCD_VERSION_1; + break; + case 0x4F200800: + lcd_revision = LCD_VERSION_2; + break; + default: + dev_warn(&device->dev, "Unknown PID Reg value 0x%x, " + "defaulting to LCD revision 1\n", + lcdc_read(LCD_PID_REG)); + lcd_revision = LCD_VERSION_1; + break; + } + for (i = 0, lcdc_info = known_lcd_panels; i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) { @@ -1085,7 +1212,13 @@ static int __devinit fb_probe(struct platform_device *device) } #endif - ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); + if (lcd_revision == LCD_VERSION_1) + lcdc_irq_handler = lcdc_irq_handler_rev01; + else + lcdc_irq_handler = lcdc_irq_handler_rev02; + + ret = request_irq(par->irq, lcdc_irq_handler, 0, + DRIVER_NAME, par); if (ret) goto irq_freq; return 0; -- cgit v1.2.3 From 7653aaab775d4c205a7dce52850c8e3d4f31d4ea Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Sat, 9 Jul 2011 15:38:14 -0500 Subject: drivers/video: use strings to specify the Freescale DIU monitor port Instead of using ill-defined numbers (0, 1, and 2) for the monitor port, allow the user to specify the port by name ("dvi", "lvds", or "dlvds"). This works on the kernel command line, the module command-line, and the sysfs "monitor" device. Note that changing the monitor port does not currently work on the P1022DS, because the code that talks to the PIXIS FPGA is broken. Signed-off-by: Timur Tabi Acked-by: Anatolij Gustschin Signed-off-by: Paul Mundt --- arch/powerpc/platforms/512x/mpc512x_shared.c | 22 ++++----- arch/powerpc/platforms/85xx/p1022_ds.c | 47 +++++++++--------- arch/powerpc/platforms/86xx/mpc8610_hpcd.c | 55 ++++++++++----------- arch/powerpc/sysdev/fsl_soc.h | 25 +++++++--- drivers/video/fsl-diu-fb.c | 74 +++++++++++++++++++++------- 5 files changed, 128 insertions(+), 95 deletions(-) diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c index e41ebbdb3e12..3dc62f907a1e 100644 --- a/arch/powerpc/platforms/512x/mpc512x_shared.c +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c @@ -66,8 +66,8 @@ struct fsl_diu_shared_fb { bool in_use; }; -unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel, - int monitor_port) +u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port, + unsigned int bits_per_pixel) { switch (bits_per_pixel) { case 32: @@ -80,11 +80,12 @@ unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel, return 0x00000400; } -void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base) +void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port, + char *gamma_table_base) { } -void mpc512x_set_monitor_port(int monitor_port) +void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port) { } @@ -182,14 +183,10 @@ void mpc512x_set_pixel_clock(unsigned int pixclock) iounmap(ccm); } -ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf) +enum fsl_diu_monitor_port +mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port) { - return sprintf(buf, "0 - 5121 LCD\n"); -} - -int mpc512x_set_sysfs_monitor_port(int val) -{ - return 0; + return FSL_DIU_PORT_DVI; } static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; @@ -332,8 +329,7 @@ void __init mpc512x_setup_diu(void) diu_ops.set_gamma_table = mpc512x_set_gamma_table; diu_ops.set_monitor_port = mpc512x_set_monitor_port; diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; - diu_ops.show_monitor_port = mpc512x_show_monitor_port; - diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port; + diu_ops.valid_monitor_port = mpc512x_valid_monitor_port; diu_ops.release_bootmem = mpc512x_release_bootmem; #endif } diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 7eb5c40c069f..a13d3cce413c 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -93,8 +93,8 @@ * The Area Descriptor is a 32-bit value that determine which bits in each * pixel are to be used for each color. */ -static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel, - int monitor_port) +static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port, + unsigned int bits_per_pixel) { switch (bits_per_pixel) { case 32: @@ -118,7 +118,8 @@ static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel, * On some boards, the gamma table for some ports may need to be modified. * This is not the case on the P1022DS, so we do nothing. */ -static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base) +static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, + char *gamma_table_base) { } @@ -126,7 +127,7 @@ static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base) * p1022ds_set_monitor_port: switch the output to a different monitor port * */ -static void p1022ds_set_monitor_port(int monitor_port) +static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) { struct device_node *pixis_node; u8 __iomem *brdcfg1; @@ -144,19 +145,21 @@ static void p1022ds_set_monitor_port(int monitor_port) } brdcfg1 += 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ - switch (monitor_port) { - case 0: /* DVI */ + switch (port) { + case FSL_DIU_PORT_DVI: + printk(KERN_INFO "%s:%u\n", __func__, __LINE__); /* Enable the DVI port, disable the DFP and the backlight */ clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, PX_BRDCFG1_DVIEN); break; - case 1: /* Single link LVDS */ + case FSL_DIU_PORT_LVDS: + printk(KERN_INFO "%s:%u\n", __func__, __LINE__); /* Enable the DFP port, disable the DVI and the backlight */ clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, PX_BRDCFG1_DFPEN); break; default: - pr_err("p1022ds: unsupported monitor port %i\n", monitor_port); + pr_err("p1022ds: unsupported monitor port %i\n", port); } } @@ -204,23 +207,18 @@ void p1022ds_set_pixel_clock(unsigned int pixclock) } /** - * p1022ds_show_monitor_port: show the current monitor - * - * This function returns a string indicating whether the current monitor is - * set to DVI or LVDS. - */ -ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf) -{ - return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n", - monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' '); -} - -/** - * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs + * p1022ds_valid_monitor_port: set the monitor port for sysfs */ -int p1022ds_set_sysfs_monitor_port(int val) +enum fsl_diu_monitor_port +p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) { - return val < 2 ? val : 0; + switch (port) { + case FSL_DIU_PORT_DVI: + case FSL_DIU_PORT_LVDS: + return port; + default: + return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ + } } #endif @@ -295,8 +293,7 @@ static void __init p1022_ds_setup_arch(void) diu_ops.set_gamma_table = p1022ds_set_gamma_table; diu_ops.set_monitor_port = p1022ds_set_monitor_port; diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; - diu_ops.show_monitor_port = p1022ds_show_monitor_port; - diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port; + diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; #endif #ifdef CONFIG_SMP diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index a896511690c2..0d80e9614f31 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c @@ -145,10 +145,10 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) -unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, - int monitor_port) +u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port, + unsigned int bits_per_pixel) { - static const unsigned long pixelformat[][3] = { + static const u32 pixelformat[][3] = { { MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), @@ -163,7 +163,8 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, unsigned int arch_monitor; /* The DVI port is mis-wired on revision 1 of this board. */ - arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; + arch_monitor = + ((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1; switch (bits_per_pixel) { case 32: @@ -178,10 +179,11 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, } } -void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) +void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port, + char *gamma_table_base) { int i; - if (monitor_port == 2) { /* dual link LVDS */ + if (port == FSL_DIU_PORT_DLVDS) { for (i = 0; i < 256*3; i++) gamma_table_base[i] = (gamma_table_base[i] << 2) | ((gamma_table_base[i] >> 6) & 0x03); @@ -192,17 +194,21 @@ void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) #define PX_BRDCFG0_DLINK (1 << 4) #define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK) -void mpc8610hpcd_set_monitor_port(int monitor_port) +void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port) { - static const u8 bdcfg[] = { - PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK, - PX_BRDCFG0_DLINK, - 0, - }; - - if (monitor_port < 3) + switch (port) { + case FSL_DIU_PORT_DVI: clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, - bdcfg[monitor_port]); + PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK); + break; + case FSL_DIU_PORT_LVDS: + clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, + PX_BRDCFG0_DLINK); + break; + case FSL_DIU_PORT_DLVDS: + clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK); + break; + } } void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) @@ -273,20 +279,10 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock) iounmap(clkdvdr); } -ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) -{ - return snprintf(buf, PAGE_SIZE, - "%c0 - DVI\n" - "%c1 - Single link LVDS\n" - "%c2 - Dual link LVDS\n", - monitor_port == 0 ? '*' : ' ', - monitor_port == 1 ? '*' : ' ', - monitor_port == 2 ? '*' : ' '); -} - -int mpc8610hpcd_set_sysfs_monitor_port(int val) +enum fsl_diu_monitor_port +mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port) { - return val < 3 ? val : 0; + return port; } #endif @@ -318,8 +314,7 @@ static void __init mpc86xx_hpcd_setup_arch(void) diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; - diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port; - diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; + diu_ops.valid_monitor_port = mpc8610hpcd_valid_monitor_port; #endif pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 53609489a62b..064bc7089134 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -22,15 +22,24 @@ struct device_node; extern void fsl_rstcr_restart(char *cmd); #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) + +/* The different ports that the DIU can be connected to */ +enum fsl_diu_monitor_port { + FSL_DIU_PORT_DVI, /* DVI */ + FSL_DIU_PORT_LVDS, /* Single-link LVDS */ + FSL_DIU_PORT_DLVDS /* Dual-link LVDS */ +}; + struct platform_diu_data_ops { - unsigned int (*get_pixel_format) (unsigned int bits_per_pixel, - int monitor_port); - void (*set_gamma_table) (int monitor_port, char *gamma_table_base); - void (*set_monitor_port) (int monitor_port); - void (*set_pixel_clock) (unsigned int pixclock); - ssize_t (*show_monitor_port) (int monitor_port, char *buf); - int (*set_sysfs_monitor_port) (int val); - void (*release_bootmem) (void); + u32 (*get_pixel_format)(enum fsl_diu_monitor_port port, + unsigned int bpp); + void (*set_gamma_table)(enum fsl_diu_monitor_port port, + char *gamma_table_base); + void (*set_monitor_port)(enum fsl_diu_monitor_port port); + void (*set_pixel_clock)(unsigned int pixclock); + enum fsl_diu_monitor_port (*valid_monitor_port) + (enum fsl_diu_monitor_port port); + void (*release_bootmem)(void); }; extern struct platform_diu_data_ops diu_ops; diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index 0acc7d65aeaa..0f1933b54596 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -31,8 +31,6 @@ #include #include -#include - #include #include #include "edid.h" @@ -183,7 +181,8 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = { static char *fb_mode = "1024x768-32@60"; static unsigned long default_bpp = 32; -static int monitor_port; +static enum fsl_diu_monitor_port monitor_port; +static char *monitor_string; #if defined(CONFIG_NOT_COHERENT_CACHE) static u8 *coherence_data; @@ -201,7 +200,7 @@ struct fsl_diu_data { void *dummy_aoi_virt; unsigned int irq; int fb_enabled; - int monitor_port; + enum fsl_diu_monitor_port monitor_port; }; struct mfb_info { @@ -281,6 +280,37 @@ static struct diu_hw dr = { static struct diu_pool pool; +/** + * fsl_diu_name_to_port - convert a port name to a monitor port enum + * + * Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns + * the enum fsl_diu_monitor_port that corresponds to that string. + * + * For compatibility with older versions, a number ("0", "1", or "2") is also + * supported. + * + * If the string is unknown, DVI is assumed. + * + * If the particular port is not supported by the platform, another port + * (platform-specific) is chosen instead. + */ +static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) +{ + enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI; + unsigned long val; + + if (s) { + if (!strict_strtoul(s, 10, &val) && (val <= 2)) + port = (enum fsl_diu_monitor_port) val; + else if (strncmp(s, "lvds", 4) == 0) + port = FSL_DIU_PORT_LVDS; + else if (strncmp(s, "dlvds", 5) == 0) + port = FSL_DIU_PORT_DLVDS; + } + + return diu_ops.valid_monitor_port(port); +} + /** * fsl_diu_alloc - allocate memory for the DIU * @size: number of bytes to allocate @@ -831,9 +861,8 @@ static int fsl_diu_set_par(struct fb_info *info) } } - ad->pix_fmt = - diu_ops.get_pixel_format(var->bits_per_pixel, - machine_data->monitor_port); + ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port, + var->bits_per_pixel); ad->addr = cpu_to_le32(info->fix.smem_start); ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | var->xres_virtual) | mfbi->g_alpha; @@ -1439,16 +1468,12 @@ static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, static ssize_t store_monitor(struct device *device, struct device_attribute *attr, const char *buf, size_t count) { - int old_monitor_port; - unsigned long val; + enum fsl_diu_monitor_port old_monitor_port; struct fsl_diu_data *machine_data = container_of(attr, struct fsl_diu_data, dev_attr); - if (strict_strtoul(buf, 10, &val)) - return 0; - old_monitor_port = machine_data->monitor_port; - machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); + machine_data->monitor_port = fsl_diu_name_to_port(buf); if (old_monitor_port != machine_data->monitor_port) { /* All AOIs need adjust pixel format @@ -1468,7 +1493,17 @@ static ssize_t show_monitor(struct device *device, { struct fsl_diu_data *machine_data = container_of(attr, struct fsl_diu_data, dev_attr); - return diu_ops.show_monitor_port(machine_data->monitor_port, buf); + + switch (machine_data->monitor_port) { + case FSL_DIU_PORT_DVI: + return sprintf(buf, "DVI\n"); + case FSL_DIU_PORT_LVDS: + return sprintf(buf, "Single-link LVDS\n"); + case FSL_DIU_PORT_DLVDS: + return sprintf(buf, "Dual-link LVDS\n"); + } + + return 0; } static int __devinit fsl_diu_probe(struct platform_device *ofdev) @@ -1692,8 +1727,7 @@ static int __init fsl_diu_setup(char *options) if (!*opt) continue; if (!strncmp(opt, "monitor=", 8)) { - if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) - monitor_port = val; + monitor_port = fsl_diu_name_to_port(opt + 8); } else if (!strncmp(opt, "bpp=", 4)) { if (!strict_strtoul(opt + 4, 10, &val)) default_bpp = val; @@ -1746,6 +1780,8 @@ static int __init fsl_diu_init(void) if (fb_get_options("fslfb", &option)) return -ENODEV; fsl_diu_setup(option); +#else + monitor_port = fsl_diu_name_to_port(monitor_string); #endif printk(KERN_INFO "Freescale DIU driver\n"); @@ -1812,7 +1848,7 @@ MODULE_PARM_DESC(mode, "Specify resolution as \"x[-][@]\" "); module_param_named(bpp, default_bpp, ulong, 0); MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); -module_param_named(monitor, monitor_port, int, 0); -MODULE_PARM_DESC(monitor, - "Specify the monitor port (0, 1 or 2) if supported by the platform"); +module_param_named(monitor, monitor_string, charp, 0); +MODULE_PARM_DESC(monitor, "Specify the monitor port " + "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform"); -- cgit v1.2.3 From 936a3f770b8de7042d793272f008ef1bb08522e9 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 6 Jun 2011 01:27:34 +0000 Subject: viafb: improve pitch handling This patch adds checks for minimum and maximum pitch size to prevent invalid settings which could otherwise crash the machine. Also the alignment is done in a slightly more readable way. Signed-off-by: Florian Tobias Schandinat Cc: stable@kernel.org --- drivers/video/via/via_modesetting.h | 5 +++++ drivers/video/via/viafbdev.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h index ae35cfdeb37c..013884543e91 100644 --- a/drivers/video/via/via_modesetting.h +++ b/drivers/video/via/via_modesetting.h @@ -28,6 +28,11 @@ #include + +#define VIA_PITCH_SIZE (1<<3) +#define VIA_PITCH_MAX 0x3FF8 + + void via_set_primary_address(u32 addr); void via_set_secondary_address(u32 addr); void via_set_primary_pitch(u32 pitch); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index aa87529d7d6a..bddae58ecd8a 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_info *info) info->fix.visual = bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7; + info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8, + VIA_PITCH_SIZE); } static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, @@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var, depth = 24; viafb_fill_var_color_info(var, depth); - line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7; - if (line * var->yres_virtual > ppar->memsize) + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8, + VIA_PITCH_SIZE); + if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize) return -EINVAL; /* Based on var passed in to calculate the refresh, -- cgit v1.2.3 From 699efdd2d34c535f415516e06d3d9f0bed131664 Mon Sep 17 00:00:00 2001 From: JeongHyeon Kim Date: Thu, 21 Jul 2011 16:19:19 +0900 Subject: ARM: EXYNOS4: Add support for ORIGEN board Insignal's ORIGEN board is based Samsung EXYNOS4210 SoC. Signed-off-by: JeongHyeon Kim Signed-off-by: Tushar Behera [kgene.kim@samsung.com: Fixed SoC name to EXYNOS4210] [kgene.kim@samsung.com: Selected MACH_ORIGEN in exynos4_defconfig] Signed-off-by: Kukjin Kim --- arch/arm/configs/exynos4_defconfig | 1 + arch/arm/mach-exynos4/Kconfig | 10 ++++ arch/arm/mach-exynos4/Makefile | 1 + arch/arm/mach-exynos4/mach-origen.c | 108 ++++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 arch/arm/mach-exynos4/mach-origen.c diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig index da53ff3b4d70..cd40bb56e568 100644 --- a/arch/arm/configs/exynos4_defconfig +++ b/arch/arm/configs/exynos4_defconfig @@ -11,6 +11,7 @@ CONFIG_MACH_SMDKV310=y CONFIG_MACH_ARMLEX4210=y CONFIG_MACH_UNIVERSAL_C210=y CONFIG_MACH_NURI=y +CONFIG_MACH_ORIGEN=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig index 1435fc31c4b2..3ab0f18c52a4 100644 --- a/arch/arm/mach-exynos4/Kconfig +++ b/arch/arm/mach-exynos4/Kconfig @@ -186,6 +186,16 @@ config MACH_NURI help Machine support for Samsung Mobile NURI Board. +config MACH_ORIGEN + bool "ORIGEN" + select CPU_EXYNOS4210 + select S3C_DEV_RTC + select S3C_DEV_WDT + select S3C_DEV_HSMMC2 + select EXYNOS4_SETUP_SDHCI + help + Machine support for ORIGEN based on Samsung EXYNOS4210 + endmenu comment "Configuration for HSMMC bus width" diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile index 60fe5ecf3599..4b22dc531219 100644 --- a/arch/arm/mach-exynos4/Makefile +++ b/arch/arm/mach-exynos4/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_MACH_SMDKV310) += mach-smdkv310.o obj-$(CONFIG_MACH_ARMLEX4210) += mach-armlex4210.o obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o obj-$(CONFIG_MACH_NURI) += mach-nuri.o +obj-$(CONFIG_MACH_ORIGEN) += mach-origen.o # device support diff --git a/arch/arm/mach-exynos4/mach-origen.c b/arch/arm/mach-exynos4/mach-origen.c new file mode 100644 index 000000000000..ed59f86001ac --- /dev/null +++ b/arch/arm/mach-exynos4/mach-origen.c @@ -0,0 +1,108 @@ +/* linux/arch/arm/mach-exynos4/mach-origen.c + * + * Copyright (c) 2011 Insignal Co., Ltd. + * http://www.insignal.co.kr/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/* Following are default values for UCON, ULCON and UFCON UART registers */ +#define ORIGEN_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \ + S3C2410_UCON_RXILEVEL | \ + S3C2410_UCON_TXIRQMODE | \ + S3C2410_UCON_RXIRQMODE | \ + S3C2410_UCON_RXFIFO_TOI | \ + S3C2443_UCON_RXERR_IRQEN) + +#define ORIGEN_ULCON_DEFAULT S3C2410_LCON_CS8 + +#define ORIGEN_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE | \ + S5PV210_UFCON_TXTRIG4 | \ + S5PV210_UFCON_RXTRIG4) + +static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = ORIGEN_UCON_DEFAULT, + .ulcon = ORIGEN_ULCON_DEFAULT, + .ufcon = ORIGEN_UFCON_DEFAULT, + }, +}; + +static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_GPIO, + .ext_cd_gpio = EXYNOS4_GPK2(2), + .ext_cd_gpio_invert = 1, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; + +static struct platform_device *origen_devices[] __initdata = { + &s3c_device_hsmmc2, + &s3c_device_rtc, + &s3c_device_wdt, +}; + +static void __init origen_map_io(void) +{ + s5p_init_io(NULL, 0, S5P_VA_CHIPID); + s3c24xx_init_clocks(24000000); + s3c24xx_init_uarts(origen_uartcfgs, ARRAY_SIZE(origen_uartcfgs)); +} + +static void __init origen_machine_init(void) +{ + s3c_sdhci2_set_platdata(&origen_hsmmc2_pdata); + platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); +} + +MACHINE_START(ORIGEN, "ORIGEN") + /* Maintainer: JeongHyeon Kim */ + .boot_params = S5P_PA_SDRAM + 0x100, + .init_irq = exynos4_init_irq, + .map_io = origen_map_io, + .init_machine = origen_machine_init, + .timer = &exynos4_timer, +MACHINE_END -- cgit v1.2.3 From 64a648c2204b0c750fe49828158751183d8b5f83 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 25 Jul 2011 11:15:15 +0100 Subject: ASoC: dapm - Add DAPM stream completion event. In preparation for Dynamic PCM (AKA DSP) support. This adds a callback function to be called at the completion of a DAPM stream event. This can be used by DSP components to perform calculations based on DAPM graphs after completion of stream events. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 ++ include/sound/soc.h | 6 ++++++ sound/soc/soc-core.c | 2 ++ sound/soc/soc-dapm.c | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e0583b7769cb..350b1b395cac 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -524,6 +524,8 @@ struct snd_soc_dapm_context { enum snd_soc_bias_level target_bias_level; struct list_head list; + int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); + #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_dapm; #endif diff --git a/include/sound/soc.h b/include/sound/soc.h index aa19f5a32ba8..64a9dd5a69d6 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -634,6 +634,9 @@ struct snd_soc_codec_driver { void (*seq_notifier)(struct snd_soc_dapm_context *, enum snd_soc_dapm_type, int); + /* codec stream completion event */ + int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); + /* probe ordering - for components with runtime dependencies */ int probe_order; int remove_order; @@ -669,6 +672,9 @@ struct snd_soc_platform_driver { /* platform stream ops */ struct snd_pcm_ops *ops; + /* platform stream completion event */ + int (*stream_event)(struct snd_soc_dapm_context *dapm, int event); + /* probe ordering - for components with runtime dependencies */ int probe_order; int remove_order; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 83ad8ca27490..9d3935bbbd0c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3141,6 +3141,7 @@ int snd_soc_register_platform(struct device *dev, platform->driver = platform_drv; platform->dapm.dev = dev; platform->dapm.platform = platform; + platform->dapm.stream_event = platform_drv->stream_event; mutex_lock(&client_mutex); list_add(&platform->list, &platform_list); @@ -3253,6 +3254,7 @@ int snd_soc_register_codec(struct device *dev, codec->dapm.dev = dev; codec->dapm.codec = codec; codec->dapm.seq_notifier = codec_drv->seq_notifier; + codec->dapm.stream_event = codec_drv->stream_event; codec->dev = dev; codec->driver = codec_drv; codec->num_dai = num_dai; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7e15914b3633..612a2a28979a 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2604,6 +2604,10 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, } dapm_power_widgets(dapm, event); + + /* do we need to notify any clients that DAPM stream is complete */ + if (dapm->stream_event) + dapm->stream_event(dapm, event); } /** -- cgit v1.2.3 From ee47b364860bb21580cc105e6bb6e0dd76b75ad2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Mon, 25 Jul 2011 11:15:50 +0100 Subject: ASoC: dapm - change stream event dbg to vdgb Stream event debug can be noisy on larger audio devices so improve the debug SNR by changing it to the verbose level. Signed-off-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 612a2a28979a..c26531132c66 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2584,7 +2584,7 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, { if (!w->sname || w->dapm != dapm) continue; - dev_dbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", + dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", w->name, w->sname, stream, event); if (strstr(w->sname, stream)) { switch(event) { -- cgit v1.2.3 From 786c89f7a24b4ed8b68dfb136347267875315c30 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 25 Jul 2011 18:40:06 -0300 Subject: ARM: mx50: Select IMX_HAVE_PLATFORM_FEC as done on other i.MX devices Currently it is only the MX50_RDP board that selects IMX_HAVE_PLATFORM_FEC in its board Kconfig. Do like the other i.MX processors, which select IMX_HAVE_PLATFORM_FEC based on the processor type. Signed-off-by: Fabio Estevam Signed-off-by: Sascha Hauer --- arch/arm/mach-mx5/Kconfig | 1 - arch/arm/plat-mxc/devices/Kconfig | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 799fbc40e53c..3b5aed2bb58f 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -52,7 +52,6 @@ config MACH_MX50_RDP select IMX_HAVE_PLATFORM_IMX_UART select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX select IMX_HAVE_PLATFORM_SPI_IMX - select IMX_HAVE_PLATFORM_FEC help Include support for MX50 reference design platform (RDP) board. This includes specific configurations for the board and its peripherals. diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig index bd294add932c..39b08957e8ad 100644 --- a/arch/arm/plat-mxc/devices/Kconfig +++ b/arch/arm/plat-mxc/devices/Kconfig @@ -1,6 +1,6 @@ config IMX_HAVE_PLATFORM_FEC bool - default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX51 || SOC_IMX53 + default y if ARCH_MX25 || SOC_IMX27 || SOC_IMX35 || SOC_IMX50 || SOC_IMX51 || SOC_IMX53 config IMX_HAVE_PLATFORM_FLEXCAN select HAVE_CAN_FLEXCAN if CAN -- cgit v1.2.3 From b3c70c9ea62a3ae6c63536e43fa28f965a56de91 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:44:45 +0200 Subject: ASoC: Alchemy AC97C/I2SC audio support This patch adds ASoC support for the AC97 and I2S controllers on the old Au1000/Au1500/Au1100 chips, AC97 Tested on a Db1500. I2S untested since none of the boards actually have an I2S codec wired up (just test pins). Signed-off-by: Manuel Lauss Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/au1x/Kconfig | 19 +++ sound/soc/au1x/Makefile | 8 + sound/soc/au1x/ac97c.c | 365 ++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/au1x/dma.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/au1x/i2sc.c | 347 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/au1x/psc.h | 19 +-- 6 files changed, 1126 insertions(+), 9 deletions(-) create mode 100644 sound/soc/au1x/ac97c.c create mode 100644 sound/soc/au1x/dma.c create mode 100644 sound/soc/au1x/i2sc.c diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index 4b67140fdec3..0460b428862c 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig @@ -18,6 +18,25 @@ config SND_SOC_AU1XPSC_AC97 select SND_AC97_CODEC select SND_SOC_AC97_BUS +## +## Au1000/1500/1100 DMA + AC97C/I2SC +## +config SND_SOC_AU1XAUDIO + tristate "SoC Audio for Au1000/Au1500/Au1100" + depends on MIPS_ALCHEMY + help + This is a driver set for the AC97 unit and the + old DMA controller as found on the Au1000/Au1500/Au1100 chips. + +config SND_SOC_AU1XAC97C + tristate + select AC97_BUS + select SND_AC97_CODEC + select SND_SOC_AC97_BUS + +config SND_SOC_AU1XI2SC + tristate + ## ## Boards diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile index 16873076e8c4..ff5531eee613 100644 --- a/sound/soc/au1x/Makefile +++ b/sound/soc/au1x/Makefile @@ -3,9 +3,17 @@ snd-soc-au1xpsc-dbdma-objs := dbdma2.o snd-soc-au1xpsc-i2s-objs := psc-i2s.o snd-soc-au1xpsc-ac97-objs := psc-ac97.o +# Au1000/1500/1100 Audio units +snd-soc-au1x-dma-objs := dma.o +snd-soc-au1x-ac97c-objs := ac97c.o +snd-soc-au1x-i2sc-objs := i2sc.o + obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o +obj-$(CONFIG_SND_SOC_AU1XAUDIO) += snd-soc-au1x-dma.o +obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o +obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o # Boards snd-soc-db1200-objs := db1200.o diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c new file mode 100644 index 000000000000..9c05f381d95e --- /dev/null +++ b/sound/soc/au1x/ac97c.c @@ -0,0 +1,365 @@ +/* + * Au1000/Au1500/Au1100 AC97C controller driver for ASoC + * + * (c) 2011 Manuel Lauss + * + * based on the old ALSA driver originally written by + * Charles Eidsness + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +/* register offsets and bits */ +#define AC97_CONFIG 0x00 +#define AC97_STATUS 0x04 +#define AC97_DATA 0x08 +#define AC97_CMDRESP 0x0c +#define AC97_ENABLE 0x10 + +#define CFG_RC(x) (((x) & 0x3ff) << 13) /* valid rx slots mask */ +#define CFG_XS(x) (((x) & 0x3ff) << 3) /* valid tx slots mask */ +#define CFG_SG (1 << 2) /* sync gate */ +#define CFG_SN (1 << 1) /* sync control */ +#define CFG_RS (1 << 0) /* acrst# control */ +#define STAT_XU (1 << 11) /* tx underflow */ +#define STAT_XO (1 << 10) /* tx overflow */ +#define STAT_RU (1 << 9) /* rx underflow */ +#define STAT_RO (1 << 8) /* rx overflow */ +#define STAT_RD (1 << 7) /* codec ready */ +#define STAT_CP (1 << 6) /* command pending */ +#define STAT_TE (1 << 4) /* tx fifo empty */ +#define STAT_TF (1 << 3) /* tx fifo full */ +#define STAT_RE (1 << 1) /* rx fifo empty */ +#define STAT_RF (1 << 0) /* rx fifo full */ +#define CMD_SET_DATA(x) (((x) & 0xffff) << 16) +#define CMD_GET_DATA(x) ((x) & 0xffff) +#define CMD_READ (1 << 7) +#define CMD_WRITE (0 << 7) +#define CMD_IDX(x) ((x) & 0x7f) +#define EN_D (1 << 1) /* DISable bit */ +#define EN_CE (1 << 0) /* clock enable bit */ + +/* how often to retry failed codec register reads/writes */ +#define AC97_RW_RETRIES 5 + +#define AC97_RATES \ + SNDRV_PCM_RATE_CONTINUOUS + +#define AC97_FMTS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE) + +/* instance data. There can be only one, MacLeod!!!!, fortunately there IS only + * once AC97C on early Alchemy chips. The newer ones aren't so lucky. + */ +static struct au1xpsc_audio_data *ac97c_workdata; +#define ac97_to_ctx(x) ac97c_workdata + +static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg) +{ + return __raw_readl(ctx->mmio + reg); +} + +static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v) +{ + __raw_writel(v, ctx->mmio + reg); + wmb(); +} + +static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97, + unsigned short r) +{ + struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); + unsigned int tmo, retry; + unsigned long data; + + data = ~0; + retry = AC97_RW_RETRIES; + do { + mutex_lock(&ctx->lock); + + tmo = 5; + while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + udelay(21); /* wait an ac97 frame time */ + if (!tmo) { + pr_debug("ac97rd timeout #1\n"); + goto next; + } + + WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ); + + /* stupid errata: data is only valid for 21us, so + * poll, Forrest, poll... + */ + tmo = 0x10000; + while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--) + asm volatile ("nop"); + data = RD(ctx, AC97_CMDRESP); + + if (!tmo) + pr_debug("ac97rd timeout #2\n"); + +next: + mutex_unlock(&ctx->lock); + } while (--retry && !tmo); + + pr_debug("AC97RD %04x %04lx %d\n", r, data, retry); + + return retry ? data & 0xffff : 0xffff; +} + +static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r, + unsigned short v) +{ + struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); + unsigned int tmo, retry; + + retry = AC97_RW_RETRIES; + do { + mutex_lock(&ctx->lock); + + for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--) + udelay(21); + if (!tmo) { + pr_debug("ac97wr timeout #1\n"); + goto next; + } + + WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v)); + + for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--) + udelay(21); + if (!tmo) + pr_debug("ac97wr timeout #2\n"); +next: + mutex_unlock(&ctx->lock); + } while (--retry && !tmo); + + pr_debug("AC97WR %04x %04x %d\n", r, v, retry); +} + +static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97) +{ + struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); + + WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN); + msleep(20); + WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG); + WR(ctx, AC97_CONFIG, ctx->cfg); +} + +static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97) +{ + struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97); + int i; + + WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS); + msleep(500); + WR(ctx, AC97_CONFIG, ctx->cfg); + + /* wait for codec ready */ + i = 50; + while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i) + msleep(20); + if (!i) + printk(KERN_ERR "ac97c: codec not ready after cold reset\n"); +} + +/* AC97 controller operations */ +struct snd_ac97_bus_ops soc_ac97_ops = { + .read = au1xac97c_ac97_read, + .write = au1xac97c_ac97_write, + .reset = au1xac97c_ac97_cold_reset, + .warm_reset = au1xac97c_ac97_warm_reset, +}; +EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */ + +static int alchemy_ac97c_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]); + return 0; +} + +static struct snd_soc_dai_ops alchemy_ac97c_ops = { + .startup = alchemy_ac97c_startup, +}; + +static int au1xac97c_dai_probe(struct snd_soc_dai *dai) +{ + return ac97c_workdata ? 0 : -ENODEV; +} + +static struct snd_soc_dai_driver au1xac97c_dai_driver = { + .name = "alchemy-ac97c", + .ac97_control = 1, + .probe = au1xac97c_dai_probe, + .playback = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AC97_RATES, + .formats = AC97_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &alchemy_ac97c_ops, +}; + +static int __devinit au1xac97c_drvprobe(struct platform_device *pdev) +{ + int ret; + struct resource *r; + struct au1xpsc_audio_data *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_init(&ctx->lock); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out0; + } + + ret = -EBUSY; + if (!request_mem_region(r->start, resource_size(r), pdev->name)) + goto out0; + + ctx->mmio = ioremap_nocache(r->start, resource_size(r)); + if (!ctx->mmio) + goto out1; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) + goto out1; + ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) + goto out1; + ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; + + /* switch it on */ + WR(ctx, AC97_ENABLE, EN_D | EN_CE); + WR(ctx, AC97_ENABLE, EN_CE); + + ctx->cfg = CFG_RC(3) | CFG_XS(3); + WR(ctx, AC97_CONFIG, ctx->cfg); + + platform_set_drvdata(pdev, ctx); + + ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver); + if (ret) + goto out1; + + ac97c_workdata = ctx; + return 0; + + + snd_soc_unregister_dai(&pdev->dev); +out1: + release_mem_region(r->start, resource_size(r)); +out0: + kfree(ctx); + return ret; +} + +static int __devexit au1xac97c_drvremove(struct platform_device *pdev) +{ + struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + snd_soc_unregister_dai(&pdev->dev); + + WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ + + iounmap(ctx->mmio); + release_mem_region(r->start, resource_size(r)); + kfree(ctx); + + ac97c_workdata = NULL; /* MDEV */ + + return 0; +} + +#ifdef CONFIG_PM +static int au1xac97c_drvsuspend(struct device *dev) +{ + struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); + + WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */ + + return 0; +} + +static int au1xac97c_drvresume(struct device *dev) +{ + struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); + + WR(ctx, AC97_ENABLE, EN_D | EN_CE); + WR(ctx, AC97_ENABLE, EN_CE); + WR(ctx, AC97_CONFIG, ctx->cfg); + + return 0; +} + +static const struct dev_pm_ops au1xpscac97_pmops = { + .suspend = au1xac97c_drvsuspend, + .resume = au1xac97c_drvresume, +}; + +#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops) + +#else + +#define AU1XPSCAC97_PMOPS NULL + +#endif + +static struct platform_driver au1xac97c_driver = { + .driver = { + .name = "alchemy-ac97c", + .owner = THIS_MODULE, + .pm = AU1XPSCAC97_PMOPS, + }, + .probe = au1xac97c_drvprobe, + .remove = __devexit_p(au1xac97c_drvremove), +}; + +static int __init au1xac97c_load(void) +{ + ac97c_workdata = NULL; + return platform_driver_register(&au1xac97c_driver); +} + +static void __exit au1xac97c_unload(void) +{ + platform_driver_unregister(&au1xac97c_driver); +} + +module_init(au1xac97c_load); +module_exit(au1xac97c_unload); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver"); +MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c new file mode 100644 index 000000000000..7aa5b7606777 --- /dev/null +++ b/sound/soc/au1x/dma.c @@ -0,0 +1,377 @@ +/* + * Au1000/Au1500/Au1100 Audio DMA support. + * + * (c) 2011 Manuel Lauss + * + * copied almost verbatim from the old ALSA driver, written by + * Charles Eidsness + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +#define ALCHEMY_PCM_FMTS \ + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \ + SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \ + 0) + +struct pcm_period { + u32 start; + u32 relative_end; /* relative to start of buffer */ + struct pcm_period *next; +}; + +struct audio_stream { + struct snd_pcm_substream *substream; + int dma; + struct pcm_period *buffer; + unsigned int period_size; + unsigned int periods; +}; + +struct alchemy_pcm_ctx { + struct audio_stream stream[2]; /* playback & capture */ +}; + +static void au1000_release_dma_link(struct audio_stream *stream) +{ + struct pcm_period *pointer; + struct pcm_period *pointer_next; + + stream->period_size = 0; + stream->periods = 0; + pointer = stream->buffer; + if (!pointer) + return; + do { + pointer_next = pointer->next; + kfree(pointer); + pointer = pointer_next; + } while (pointer != stream->buffer); + stream->buffer = NULL; +} + +static int au1000_setup_dma_link(struct audio_stream *stream, + unsigned int period_bytes, + unsigned int periods) +{ + struct snd_pcm_substream *substream = stream->substream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct pcm_period *pointer; + unsigned long dma_start; + int i; + + dma_start = virt_to_phys(runtime->dma_area); + + if (stream->period_size == period_bytes && + stream->periods == periods) + return 0; /* not changed */ + + au1000_release_dma_link(stream); + + stream->period_size = period_bytes; + stream->periods = periods; + + stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL); + if (!stream->buffer) + return -ENOMEM; + pointer = stream->buffer; + for (i = 0; i < periods; i++) { + pointer->start = (u32)(dma_start + (i * period_bytes)); + pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1); + if (i < periods - 1) { + pointer->next = kmalloc(sizeof(struct pcm_period), + GFP_KERNEL); + if (!pointer->next) { + au1000_release_dma_link(stream); + return -ENOMEM; + } + pointer = pointer->next; + } + } + pointer->next = stream->buffer; + return 0; +} + +static void au1000_dma_stop(struct audio_stream *stream) +{ + if (stream->buffer) + disable_dma(stream->dma); +} + +static void au1000_dma_start(struct audio_stream *stream) +{ + if (!stream->buffer) + return; + + init_dma(stream->dma); + if (get_dma_active_buffer(stream->dma) == 0) { + clear_dma_done0(stream->dma); + set_dma_addr0(stream->dma, stream->buffer->start); + set_dma_count0(stream->dma, stream->period_size >> 1); + set_dma_addr1(stream->dma, stream->buffer->next->start); + set_dma_count1(stream->dma, stream->period_size >> 1); + } else { + clear_dma_done1(stream->dma); + set_dma_addr1(stream->dma, stream->buffer->start); + set_dma_count1(stream->dma, stream->period_size >> 1); + set_dma_addr0(stream->dma, stream->buffer->next->start); + set_dma_count0(stream->dma, stream->period_size >> 1); + } + enable_dma_buffers(stream->dma); + start_dma(stream->dma); +} + +static irqreturn_t au1000_dma_interrupt(int irq, void *ptr) +{ + struct audio_stream *stream = (struct audio_stream *)ptr; + struct snd_pcm_substream *substream = stream->substream; + + switch (get_dma_buffer_done(stream->dma)) { + case DMA_D0: + stream->buffer = stream->buffer->next; + clear_dma_done0(stream->dma); + set_dma_addr0(stream->dma, stream->buffer->next->start); + set_dma_count0(stream->dma, stream->period_size >> 1); + enable_dma_buffer0(stream->dma); + break; + case DMA_D1: + stream->buffer = stream->buffer->next; + clear_dma_done1(stream->dma); + set_dma_addr1(stream->dma, stream->buffer->next->start); + set_dma_count1(stream->dma, stream->period_size >> 1); + enable_dma_buffer1(stream->dma); + break; + case (DMA_D0 | DMA_D1): + pr_debug("DMA %d missed interrupt.\n", stream->dma); + au1000_dma_stop(stream); + au1000_dma_start(stream); + break; + case (~DMA_D0 & ~DMA_D1): + pr_debug("DMA %d empty irq.\n", stream->dma); + } + snd_pcm_period_elapsed(substream); + return IRQ_HANDLED; +} + +static const struct snd_pcm_hardware alchemy_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH, + .formats = ALCHEMY_PCM_FMTS, + .rates = SNDRV_PCM_RATE_8000_192000, + .rate_min = SNDRV_PCM_RATE_8000, + .rate_max = SNDRV_PCM_RATE_192000, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 1024, + .period_bytes_max = 16 * 1024 - 1, + .periods_min = 4, + .periods_max = 255, + .buffer_bytes_max = 128 * 1024, + .fifo_size = 16, +}; + +static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss) +{ + struct snd_soc_pcm_runtime *rtd = ss->private_data; + return snd_soc_platform_get_drvdata(rtd->platform); +} + +static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss) +{ + struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss); + return &(ctx->stream[ss->stream]); +} + +static int alchemy_pcm_open(struct snd_pcm_substream *substream) +{ + struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int *dmaids, s = substream->stream; + char *name; + + dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dmaids) + return -ENODEV; /* whoa, has ordering changed? */ + + /* DMA setup */ + name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx"; + ctx->stream[s].dma = request_au1000_dma(dmaids[s], name, + au1000_dma_interrupt, IRQF_DISABLED, + &ctx->stream[s]); + set_dma_mode(ctx->stream[s].dma, + get_dma_mode(ctx->stream[s].dma) & ~DMA_NC); + + ctx->stream[s].substream = substream; + ctx->stream[s].buffer = NULL; + snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware); + + return 0; +} + +static int alchemy_pcm_close(struct snd_pcm_substream *substream) +{ + struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream); + int stype = substream->stream; + + ctx->stream[stype].substream = NULL; + free_au1000_dma(ctx->stream[stype].dma); + + return 0; +} + +static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct audio_stream *stream = ss_to_as(substream); + int err; + + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; + err = au1000_setup_dma_link(stream, + params_period_bytes(hw_params), + params_periods(hw_params)); + if (err) + snd_pcm_lib_free_pages(substream); + + return err; +} + +static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct audio_stream *stream = ss_to_as(substream); + au1000_release_dma_link(stream); + return snd_pcm_lib_free_pages(substream); +} + +static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct audio_stream *stream = ss_to_as(substream); + int err = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + au1000_dma_start(stream); + break; + case SNDRV_PCM_TRIGGER_STOP: + au1000_dma_stop(stream); + break; + default: + err = -EINVAL; + break; + } + return err; +} + +static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss) +{ + struct audio_stream *stream = ss_to_as(ss); + long location; + + location = get_dma_residue(stream->dma); + location = stream->buffer->relative_end - location; + if (location == -1) + location = 0; + return bytes_to_frames(ss->runtime, location); +} + +static struct snd_pcm_ops alchemy_pcm_ops = { + .open = alchemy_pcm_open, + .close = alchemy_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = alchemy_pcm_hw_params, + .hw_free = alchemy_pcm_hw_free, + .trigger = alchemy_pcm_trigger, + .pointer = alchemy_pcm_pointer, +}; + +static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_pcm *pcm = rtd->pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1); + + return 0; +} + +struct snd_soc_platform_driver alchemy_pcm_soc_platform = { + .ops = &alchemy_pcm_ops, + .pcm_new = alchemy_pcm_new, + .pcm_free = alchemy_pcm_free_dma_buffers, +}; + +static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev) +{ + struct alchemy_pcm_ctx *ctx; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + platform_set_drvdata(pdev, ctx); + + ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform); + if (ret) + kfree(ctx); + + return ret; +} + +static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev) +{ + struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev); + + snd_soc_unregister_platform(&pdev->dev); + kfree(ctx); + + return 0; +} + +static struct platform_driver alchemy_pcmdma_driver = { + .driver = { + .name = "alchemy-pcm-dma", + .owner = THIS_MODULE, + }, + .probe = alchemy_pcm_drvprobe, + .remove = __devexit_p(alchemy_pcm_drvremove), +}; + +static int __init alchemy_pcmdma_load(void) +{ + return platform_driver_register(&alchemy_pcmdma_driver); +} + +static void __exit alchemy_pcmdma_unload(void) +{ + platform_driver_unregister(&alchemy_pcmdma_driver); +} + +module_init(alchemy_pcmdma_load); +module_exit(alchemy_pcmdma_unload); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver"); +MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c new file mode 100644 index 000000000000..b4172fdd2c48 --- /dev/null +++ b/sound/soc/au1x/i2sc.c @@ -0,0 +1,347 @@ +/* + * Au1000/Au1500/Au1100 I2S controller driver for ASoC + * + * (c) 2011 Manuel Lauss + * + * Note: clock supplied to the I2S controller must be 256x samplerate. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +#define I2S_RXTX 0x00 +#define I2S_CFG 0x04 +#define I2S_ENABLE 0x08 + +#define CFG_XU (1 << 25) /* tx underflow */ +#define CFG_XO (1 << 24) +#define CFG_RU (1 << 23) +#define CFG_RO (1 << 22) +#define CFG_TR (1 << 21) +#define CFG_TE (1 << 20) +#define CFG_TF (1 << 19) +#define CFG_RR (1 << 18) +#define CFG_RF (1 << 17) +#define CFG_ICK (1 << 12) /* clock invert */ +#define CFG_PD (1 << 11) /* set to make I2SDIO INPUT */ +#define CFG_LB (1 << 10) /* loopback */ +#define CFG_IC (1 << 9) /* word select invert */ +#define CFG_FM_I2S (0 << 7) /* I2S format */ +#define CFG_FM_LJ (1 << 7) /* left-justified */ +#define CFG_FM_RJ (2 << 7) /* right-justified */ +#define CFG_FM_MASK (3 << 7) +#define CFG_TN (1 << 6) /* tx fifo en */ +#define CFG_RN (1 << 5) /* rx fifo en */ +#define CFG_SZ_8 (0x08) +#define CFG_SZ_16 (0x10) +#define CFG_SZ_18 (0x12) +#define CFG_SZ_20 (0x14) +#define CFG_SZ_24 (0x18) +#define CFG_SZ_MASK (0x1f) +#define EN_D (1 << 1) /* DISable */ +#define EN_CE (1 << 0) /* clock enable */ + +/* only limited by clock generator and board design */ +#define AU1XI2SC_RATES \ + SNDRV_PCM_RATE_CONTINUOUS + +#define AU1XI2SC_FMTS \ + (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \ + SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_U18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ + SNDRV_PCM_FMTBIT_S20_3BE | SNDRV_PCM_FMTBIT_U20_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \ + 0) + +static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg) +{ + return __raw_readl(ctx->mmio + reg); +} + +static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v) +{ + __raw_writel(v, ctx->mmio + reg); + wmb(); +} + +static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long c; + int ret; + + ret = -EINVAL; + c = ctx->cfg; + + c &= ~CFG_FM_MASK; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + c |= CFG_FM_I2S; + break; + case SND_SOC_DAIFMT_MSB: + c |= CFG_FM_RJ; + break; + case SND_SOC_DAIFMT_LSB: + c |= CFG_FM_LJ; + break; + default: + goto out; + } + + c &= ~(CFG_IC | CFG_ICK); /* IB-IF */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + c |= CFG_IC | CFG_ICK; + break; + case SND_SOC_DAIFMT_NB_IF: + c |= CFG_IC; + break; + case SND_SOC_DAIFMT_IB_NF: + c |= CFG_ICK; + break; + case SND_SOC_DAIFMT_IB_IF: + break; + default: + goto out; + } + + /* I2S controller only supports master */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */ + break; + default: + goto out; + } + + ret = 0; + ctx->cfg = c; +out: + return ret; +} + +static int au1xi2s_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai); + int stype = SUBSTREAM_TYPE(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + /* power up */ + WR(ctx, I2S_ENABLE, EN_D | EN_CE); + WR(ctx, I2S_ENABLE, EN_CE); + ctx->cfg |= (stype == PCM_TX) ? CFG_TN : CFG_RN; + WR(ctx, I2S_CFG, ctx->cfg); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + ctx->cfg &= ~((stype == PCM_TX) ? CFG_TN : CFG_RN); + WR(ctx, I2S_CFG, ctx->cfg); + WR(ctx, I2S_ENABLE, EN_D); /* power off */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static unsigned long msbits_to_reg(int msbits) +{ + switch (msbits) { + case 8: + return CFG_SZ_8; + case 16: + return CFG_SZ_16; + case 18: + return CFG_SZ_18; + case 20: + return CFG_SZ_20; + case 24: + return CFG_SZ_24; + } + return 0; +} + +static int au1xi2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai); + unsigned long v; + + v = msbits_to_reg(params->msbits); + if (!v) + return -EINVAL; + + ctx->cfg &= ~CFG_SZ_MASK; + ctx->cfg |= v; + return 0; +} + +static int au1xi2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]); + return 0; +} + +static const struct snd_soc_dai_ops au1xi2s_dai_ops = { + .startup = au1xi2s_startup, + .trigger = au1xi2s_trigger, + .hw_params = au1xi2s_hw_params, + .set_fmt = au1xi2s_set_fmt, +}; + +static struct snd_soc_dai_driver au1xi2s_dai_driver = { + .symmetric_rates = 1, + .playback = { + .rates = AU1XI2SC_RATES, + .formats = AU1XI2SC_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .rates = AU1XI2SC_RATES, + .formats = AU1XI2SC_FMTS, + .channels_min = 2, + .channels_max = 2, + }, + .ops = &au1xi2s_dai_ops, +}; + +static int __devinit au1xi2s_drvprobe(struct platform_device *pdev) +{ + int ret; + struct resource *r; + struct au1xpsc_audio_data *ctx; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + ret = -ENODEV; + goto out0; + } + + ret = -EBUSY; + if (!request_mem_region(r->start, resource_size(r), pdev->name)) + goto out0; + + ctx->mmio = ioremap_nocache(r->start, resource_size(r)); + if (!ctx->mmio) + goto out1; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) + goto out1; + ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) + goto out1; + ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; + + platform_set_drvdata(pdev, ctx); + + ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver); + if (ret) + goto out1; + + return 0; + + snd_soc_unregister_dai(&pdev->dev); +out1: + release_mem_region(r->start, resource_size(r)); +out0: + kfree(ctx); + return ret; +} + +static int __devexit au1xi2s_drvremove(struct platform_device *pdev) +{ + struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev); + struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + snd_soc_unregister_dai(&pdev->dev); + + WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */ + + iounmap(ctx->mmio); + release_mem_region(r->start, resource_size(r)); + kfree(ctx); + + return 0; +} + +#ifdef CONFIG_PM +static int au1xi2s_drvsuspend(struct device *dev) +{ + struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); + + WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */ + + return 0; +} + +static int au1xi2s_drvresume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops au1xi2sc_pmops = { + .suspend = au1xi2s_drvsuspend, + .resume = au1xi2s_drvresume, +}; + +#define AU1XI2SC_PMOPS (&au1xi2sc_pmops) + +#else + +#define AU1XI2SC_PMOPS NULL + +#endif + +static struct platform_driver au1xi2s_driver = { + .driver = { + .name = "alchemy-i2sc", + .owner = THIS_MODULE, + .pm = AU1XI2SC_PMOPS, + }, + .probe = au1xi2s_drvprobe, + .remove = __devexit_p(au1xi2s_drvremove), +}; + +static int __init au1xi2s_load(void) +{ + return platform_driver_register(&au1xi2s_driver); +} + +static void __exit au1xi2s_unload(void) +{ + platform_driver_unregister(&au1xi2s_driver); +} + +module_init(au1xi2s_load); +module_exit(au1xi2s_unload); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Au1000/1500/1100 I2S ASoC driver"); +MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index b30eadd422a7..c59b9e544e72 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -1,7 +1,7 @@ /* - * Au12x0/Au1550 PSC ALSA ASoC audio support. + * Alchemy ALSA ASoC audio support. * - * (c) 2007-2008 MSC Vertriebsges.m.b.H., + * (c) 2007-2011 MSC Vertriebsges.m.b.H., * Manuel Lauss * * This program is free software; you can redistribute it and/or modify @@ -13,7 +13,13 @@ #ifndef _AU1X_PCM_H #define _AU1X_PCM_H -/* DBDMA helpers */ +#define PCM_TX 0 +#define PCM_RX 1 + +#define SUBSTREAM_TYPE(substream) \ + ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) + +/* PSC/DBDMA helpers */ extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev); extern void au1xpsc_pcm_destroy(struct platform_device *dmapd); @@ -27,15 +33,10 @@ struct au1xpsc_audio_data { unsigned long pm[2]; struct mutex lock; + int dmaids[2]; struct platform_device *dmapd; }; -#define PCM_TX 0 -#define PCM_RX 1 - -#define SUBSTREAM_TYPE(substream) \ - ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) - /* easy access macros */ #define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET) #define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET) -- cgit v1.2.3 From e882dc9c8e10db52dd509fbd67240ce0cc09c201 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:15:59 +0300 Subject: Xen: fix whitespaces,tabs coding style issue in drivers/xen/balloon.c This is a patch to the balloon.c file that fixed up whitespaces, tabs errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/balloon.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index f54290baa3db..61c0ee7aa7dd 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -84,8 +84,8 @@ static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)]; #define inc_totalhigh_pages() (totalhigh_pages++) #define dec_totalhigh_pages() (totalhigh_pages--) #else -#define inc_totalhigh_pages() do {} while(0) -#define dec_totalhigh_pages() do {} while(0) +#define inc_totalhigh_pages() do {} while (0) +#define dec_totalhigh_pages() do {} while (0) #endif /* List of ballooned pages, threaded through the mem_map array. */ @@ -145,8 +145,7 @@ static struct page *balloon_retrieve(bool prefer_highmem) if (PageHighMem(page)) { balloon_stats.balloon_high--; inc_totalhigh_pages(); - } - else + } else balloon_stats.balloon_low--; totalram_pages++; @@ -299,7 +298,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) (unsigned long)__va(pfn << PAGE_SHIFT), __pte_ma(0), 0); BUG_ON(ret); - } + } } @@ -376,10 +375,10 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); * @pages: pages returned * @return 0 on success, error otherwise */ -int alloc_xenballooned_pages(int nr_pages, struct page** pages) +int alloc_xenballooned_pages(int nr_pages, struct page **pages) { int pgno = 0; - struct page* page; + struct page *page; mutex_lock(&balloon_mutex); while (pgno < nr_pages) { page = balloon_retrieve(true); @@ -409,7 +408,7 @@ EXPORT_SYMBOL(alloc_xenballooned_pages); * @nr_pages: Number of pages * @pages: pages to return */ -void free_xenballooned_pages(int nr_pages, struct page** pages) +void free_xenballooned_pages(int nr_pages, struct page **pages) { int i; -- cgit v1.2.3 From 088c05a845da821fba9e5434bbcc6329368de34e Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:13 +0300 Subject: Xen: fix whitespaces,tabs coding style issue in drivers/xen/events.c This is a patch to the events.c file that fixed up whitespaces, tabs and braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/events.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index da70f5c32eb9..8876ffd08771 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -85,8 +85,7 @@ enum xen_irq_type { * IPI - IPI vector * EVTCHN - */ -struct irq_info -{ +struct irq_info { struct list_head list; enum xen_irq_type type; /* type */ unsigned irq; @@ -282,9 +281,9 @@ static inline unsigned long active_evtchns(unsigned int cpu, struct shared_info *sh, unsigned int idx) { - return (sh->evtchn_pending[idx] & + return sh->evtchn_pending[idx] & per_cpu(cpu_evtchn_mask, cpu)[idx] & - ~sh->evtchn_mask[idx]); + ~sh->evtchn_mask[idx]; } static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu) @@ -1152,7 +1151,7 @@ static void __xen_evtchn_do_upcall(void) int cpu = get_cpu(); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); - unsigned count; + unsigned count; do { unsigned long pending_words; -- cgit v1.2.3 From 7b0ac956d91b91a1e05e4e0b454d65710fc73cd8 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:26 +0300 Subject: Xen: fix braces coding style issue in gntdev.c and grant-table.c This is a patch to the gntdev.c and grant-table.c files that fixed up braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/gntdev.c | 3 +-- drivers/xen/grant-table.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index f914b26cf0c2..772a5b8bbf2e 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -188,9 +188,8 @@ static void gntdev_put_map(struct grant_map *map) atomic_sub(map->count, &pages_mapped); - if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { + if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) notify_remote_via_evtchn(map->notify.event); - } if (map->pages) { if (!use_ptemod) diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index fd725cde6ad1..3a3dceb7063a 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -193,7 +193,7 @@ int gnttab_query_foreign_access(grant_ref_t ref) nflags = shared[ref].flags; - return (nflags & (GTF_reading|GTF_writing)); + return nflags & (GTF_reading|GTF_writing); } EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); -- cgit v1.2.3 From 4b0109830842fa645c7f7460dc713cedfe4473f6 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:16:38 +0300 Subject: Xen: fix whitespaces,tabs coding style issue in drivers/xen/pci.c This is a patch to the pci.c file that fixed up whitespaces, tabs warnings found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/pci.c b/drivers/xen/pci.c index cef4bafc07dc..c4448ee5595f 100644 --- a/drivers/xen/pci.c +++ b/drivers/xen/pci.c @@ -36,7 +36,7 @@ static int xen_add_device(struct device *dev) struct physdev_manage_pci_ext manage_pci_ext = { .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, - .is_virtfn = 1, + .is_virtfn = 1, .physfn.bus = pci_dev->physfn->bus->number, .physfn.devfn = pci_dev->physfn->devfn, }; @@ -56,7 +56,7 @@ static int xen_add_device(struct device *dev) &manage_pci_ext); } else { struct physdev_manage_pci manage_pci = { - .bus = pci_dev->bus->number, + .bus = pci_dev->bus->number, .devfn = pci_dev->devfn, }; -- cgit v1.2.3 From 822a259aa17e977892bf9dbb546522c477f7b7cb Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:17:01 +0300 Subject: Xen: fix braces coding style issue in xenbus_probe.h This is a patch to the xenbus_probe.h file that fixed up braces errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h index b814935378c7..9b1de4e34c64 100644 --- a/drivers/xen/xenbus/xenbus_probe.h +++ b/drivers/xen/xenbus/xenbus_probe.h @@ -36,8 +36,7 @@ #define XEN_BUS_ID_SIZE 20 -struct xen_bus_type -{ +struct xen_bus_type { char *root; unsigned int levels; int (*get_bus_id)(char bus_id[XEN_BUS_ID_SIZE], const char *nodename); -- cgit v1.2.3 From 6913200a566b6d2866d46d7b947a2326c4e11f55 Mon Sep 17 00:00:00 2001 From: Ruslan Pisarev Date: Tue, 26 Jul 2011 14:17:23 +0300 Subject: Xen: fix braces and tabs coding style issue in xenbus_probe.c This is a patch to the xenbus_probe.c file that fixed up braces and tabs errors found by the checkpatch.pl tools. Signed-off-by: Ruslan Pisarev Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xenbus/xenbus_probe.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index bd2f90c9ac8b..d4c7a9ffbcb9 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -309,8 +309,7 @@ void xenbus_unregister_driver(struct xenbus_driver *drv) } EXPORT_SYMBOL_GPL(xenbus_unregister_driver); -struct xb_find_info -{ +struct xb_find_info { struct xenbus_device *dev; const char *nodename; }; @@ -639,7 +638,7 @@ int xenbus_dev_cancel(struct device *dev) EXPORT_SYMBOL_GPL(xenbus_dev_cancel); /* A flag to determine if xenstored is 'ready' (i.e. has started) */ -int xenstored_ready = 0; +int xenstored_ready; int register_xenstore_notifier(struct notifier_block *nb) @@ -762,7 +761,7 @@ static int __init xenbus_init(void) return 0; - out_error: +out_error: if (page != 0) free_page(page); -- cgit v1.2.3 From b2ce305dda483e59a78d5aa6e4211034c0cea38d Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:44:46 +0200 Subject: ASoC: Add a DB1x00 AC97 machine driver Add a machine driver suitable for the AC97 part on the DB1000/DB1500/DB1100 boards. Run-tested on DB1500. Signed-off-by: Manuel Lauss Acked-by: Ralf Baechle Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/mips/alchemy/devboards/db1x00/platform.c | 48 +++++++++++++++++ sound/soc/au1x/Kconfig | 9 ++++ sound/soc/au1x/Makefile | 2 + sound/soc/au1x/db1000.c | 75 +++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) create mode 100644 sound/soc/au1x/db1000.c diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c index 978d5ab3d678..7057d28f7301 100644 --- a/arch/mips/alchemy/devboards/db1x00/platform.c +++ b/arch/mips/alchemy/devboards/db1x00/platform.c @@ -19,8 +19,11 @@ */ #include +#include #include +#include +#include #include #include #include "../platform.h" @@ -85,6 +88,45 @@ #endif #endif +static struct resource alchemy_ac97c_res[] = { + [0] = { + .start = AU1000_AC97_PHYS_ADDR, + .end = AU1000_AC97_PHYS_ADDR + 0xfff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = DMA_ID_AC97C_TX, + .end = DMA_ID_AC97C_TX, + .flags = IORESOURCE_DMA, + }, + [2] = { + .start = DMA_ID_AC97C_RX, + .end = DMA_ID_AC97C_RX, + .flags = IORESOURCE_DMA, + }, +}; + +static struct platform_device alchemy_ac97c_dev = { + .name = "alchemy-ac97c", + .id = -1, + .resource = alchemy_ac97c_res, + .num_resources = ARRAY_SIZE(alchemy_ac97c_res), +}; + +static struct platform_device alchemy_ac97c_dma_dev = { + .name = "alchemy-pcm-dma", + .id = 0, +}; + +static struct platform_device db1x00_codec_dev = { + .name = "ac97-codec", + .id = -1, +}; + +static struct platform_device db1x00_audio_dev = { + .name = "db1000-audio", +}; + static int __init db1xxx_dev_init(void) { #ifdef DB1XXX_HAS_PCMCIA @@ -113,6 +155,12 @@ static int __init db1xxx_dev_init(void) 1); #endif db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED); + + platform_device_register(&db1x00_codec_dev); + platform_device_register(&alchemy_ac97c_dma_dev); + platform_device_register(&alchemy_ac97c_dev); + platform_device_register(&db1x00_audio_dev); + return 0; } device_initcall(db1xxx_dev_init); diff --git a/sound/soc/au1x/Kconfig b/sound/soc/au1x/Kconfig index 0460b428862c..6d592546e8fc 100644 --- a/sound/soc/au1x/Kconfig +++ b/sound/soc/au1x/Kconfig @@ -41,6 +41,15 @@ config SND_SOC_AU1XI2SC ## ## Boards ## +config SND_SOC_DB1000 + tristate "DB1000 Audio support" + depends on SND_SOC_AU1XAUDIO + select SND_SOC_AU1XAC97C + select SND_SOC_AC97_CODEC + help + Select this option to enable AC97 audio on the early DB1x00 series + of boards (DB1000/DB1500/DB1100). + config SND_SOC_DB1200 tristate "DB1200 AC97+I2S audio support" depends on SND_SOC_AU1XPSC diff --git a/sound/soc/au1x/Makefile b/sound/soc/au1x/Makefile index ff5531eee613..920710514ea0 100644 --- a/sound/soc/au1x/Makefile +++ b/sound/soc/au1x/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o # Boards +snd-soc-db1000-objs := db1000.o snd-soc-db1200-objs := db1200.o +obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o diff --git a/sound/soc/au1x/db1000.c b/sound/soc/au1x/db1000.c new file mode 100644 index 000000000000..127477a5e0c7 --- /dev/null +++ b/sound/soc/au1x/db1000.c @@ -0,0 +1,75 @@ +/* + * DB1000/DB1500/DB1100 ASoC audio fabric support code. + * + * (c) 2011 Manuel Lauss + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psc.h" + +static struct snd_soc_dai_link db1000_ac97_dai = { + .name = "AC97", + .stream_name = "AC97 HiFi", + .codec_dai_name = "ac97-hifi", + .cpu_dai_name = "alchemy-ac97c", + .platform_name = "alchemy-pcm-dma.0", + .codec_name = "ac97-codec", +}; + +static struct snd_soc_card db1000_ac97 = { + .name = "DB1000_AC97", + .dai_link = &db1000_ac97_dai, + .num_links = 1, +}; + +static int __devinit db1000_audio_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &db1000_ac97; + card->dev = &pdev->dev; + return snd_soc_register_card(card); +} + +static int __devexit db1000_audio_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + snd_soc_unregister_card(card); + return 0; +} + +static struct platform_driver db1000_audio_driver = { + .driver = { + .name = "db1000-audio", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .probe = db1000_audio_probe, + .remove = __devexit_p(db1000_audio_remove), +}; + +static int __init db1000_audio_load(void) +{ + return platform_driver_register(&db1000_audio_driver); +} + +static void __exit db1000_audio_unload(void) +{ + platform_driver_unregister(&db1000_audio_driver); +} + +module_init(db1000_audio_load); +module_exit(db1000_audio_unload); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio"); +MODULE_AUTHOR("Manuel Lauss"); -- cgit v1.2.3 From 7137c6bcb7ff5d0e6f63f8a4175d5b77dc79abc0 Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:44:47 +0200 Subject: ALSA: deprecate MIPS AU1X00 AC97 driver Now that an ASoC variant is available, tell users that this driver is now living on borrowed time... Signed-off-by: Manuel Lauss Acked-by: Ralf Baechle Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/mips/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig index a9823fad85c2..77dd0a13aecc 100644 --- a/sound/mips/Kconfig +++ b/sound/mips/Kconfig @@ -23,12 +23,15 @@ config SND_SGI_HAL2 config SND_AU1X00 - tristate "Au1x00 AC97 Port Driver" + tristate "Au1x00 AC97 Port Driver (DEPRECATED)" depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500 select SND_PCM select SND_AC97_CODEC help ALSA Sound driver for the Au1x00's AC97 port. + Newer drivers for ASoC are available, please do not use + this driver as it will be removed in the future. + endif # SND_MIPS -- cgit v1.2.3 From 5b0912be7a8ff1dbfe56358c5f933d65445bb8af Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:45:02 +0200 Subject: ASoC: au1x: remove automatic DMA device registration from PSC drivers The PSC audio drivers (psc-ac97/psc-i2s) register the DMA platform_device on their own. This is frowned upon, from now on board code must register a simple pcm dma platform device for each PSC with sound duties. Signed-off-by: Manuel Lauss Acked-by: Ralf Baechle Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/mips/alchemy/devboards/db1200/platform.c | 6 ++ sound/soc/au1x/dbdma2.c | 83 ++++----------------------- sound/soc/au1x/psc-ac97.c | 34 +++++++---- sound/soc/au1x/psc-i2s.c | 32 +++++++---- sound/soc/au1x/psc.h | 5 -- 5 files changed, 64 insertions(+), 96 deletions(-) diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c index fbb55935b99e..cfb71aed4cb9 100644 --- a/arch/mips/alchemy/devboards/db1200/platform.c +++ b/arch/mips/alchemy/devboards/db1200/platform.c @@ -434,12 +434,18 @@ static struct platform_device db1200_stac_dev = { .id = 1, /* on PSC1 */ }; +static struct platform_device db1200_audiodma_dev = { + .name = "au1xpsc-pcm", + .id = 1, /* PSC ID */ +}; + static struct platform_device *db1200_devs[] __initdata = { NULL, /* PSC0, selected by S6.8 */ &db1200_ide_dev, &db1200_eth_dev, &db1200_rtc_dev, &db1200_nand_dev, + &db1200_audiodma_dev, &db1200_audio_dev, &db1200_stac_dev, }; diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 20bb53a837b1..fd5378f7dece 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -293,6 +293,16 @@ au1xpsc_pcm_pointer(struct snd_pcm_substream *substream) static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) { + struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int stype = SUBSTREAM_TYPE(substream), *dmaids; + + dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + if (!dmaids) + return -ENODEV; /* whoa, has ordering changed? */ + + pcd->ddma_id = dmaids[stype]; + snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware); return 0; } @@ -340,36 +350,18 @@ struct snd_soc_platform_driver au1xpsc_soc_platform = { static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev) { struct au1xpsc_audio_dmadata *dmadata; - struct resource *r; int ret; dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL); if (!dmadata) return -ENOMEM; - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) { - ret = -ENODEV; - goto out1; - } - dmadata[PCM_TX].ddma_id = r->start; - - /* RX DMA */ - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!r) { - ret = -ENODEV; - goto out1; - } - dmadata[PCM_RX].ddma_id = r->start; - platform_set_drvdata(pdev, dmadata); ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); - if (!ret) - return ret; + if (ret) + kfree(dmadata); -out1: - kfree(dmadata); return ret; } @@ -405,57 +397,6 @@ static void __exit au1xpsc_audio_dbdma_unload(void) module_init(au1xpsc_audio_dbdma_load); module_exit(au1xpsc_audio_dbdma_unload); - -struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev) -{ - struct resource *res, *r; - struct platform_device *pd; - int id[2]; - int ret; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) - return NULL; - id[0] = r->start; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!r) - return NULL; - id[1] = r->start; - - res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); - if (!res) - return NULL; - - res[0].start = res[0].end = id[0]; - res[1].start = res[1].end = id[1]; - res[0].flags = res[1].flags = IORESOURCE_DMA; - - pd = platform_device_alloc("au1xpsc-pcm", pdev->id); - if (!pd) - goto out; - - pd->resource = res; - pd->num_resources = 2; - - ret = platform_device_add(pd); - if (!ret) - return pd; - - platform_device_put(pd); -out: - kfree(res); - return NULL; -} -EXPORT_SYMBOL_GPL(au1xpsc_pcm_add); - -void au1xpsc_pcm_destroy(struct platform_device *dmapd) -{ - if (dmapd) - platform_device_unregister(dmapd); -} -EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy); - MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver"); MODULE_AUTHOR("Manuel Lauss"); diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index d0db66f24a00..44296abfc38f 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -324,12 +324,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, return ret; } +static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]); + return 0; +} + static int au1xpsc_ac97_probe(struct snd_soc_dai *dai) { return au1xpsc_ac97_workdata ? 0 : -ENODEV; } static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { + .startup = au1xpsc_ac97_startup, .trigger = au1xpsc_ac97_trigger, .hw_params = au1xpsc_ac97_hw_params, }; @@ -379,6 +388,16 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) if (!wd->mmio) goto out1; + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) + goto out2; + wd->dmaids[PCM_TX] = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) + goto out2; + wd->dmaids[PCM_RX] = r->start; + /* configuration: max dma trigger threshold, enable ac97 */ wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | PSC_AC97CFG_DE_ENABLE; @@ -401,15 +420,13 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); if (ret) - goto out1; + goto out2; - wd->dmapd = au1xpsc_pcm_add(pdev); - if (wd->dmapd) { - au1xpsc_ac97_workdata = wd; - return 0; - } + au1xpsc_ac97_workdata = wd; + return 0; - snd_soc_unregister_dai(&pdev->dev); +out2: + iounmap(wd->mmio); out1: release_mem_region(r->start, resource_size(r)); out0: @@ -422,9 +439,6 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev) struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (wd->dmapd) - au1xpsc_pcm_destroy(wd->dmapd); - snd_soc_unregister_dai(&pdev->dev); /* disable PSC completely */ diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index fca091276320..1b7ab5d422e0 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -257,7 +257,16 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } +static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); + snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]); + return 0; +} + static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = { + .startup = au1xpsc_i2s_startup, .trigger = au1xpsc_i2s_trigger, .hw_params = au1xpsc_i2s_hw_params, .set_fmt = au1xpsc_i2s_set_fmt, @@ -304,6 +313,16 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) if (!wd->mmio) goto out1; + r = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!r) + goto out2; + wd->dmaids[PCM_TX] = r->start; + + r = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!r) + goto out2; + wd->dmaids[PCM_RX] = r->start; + /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) */ @@ -330,15 +349,11 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, wd); ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv); - if (ret) - goto out1; - - /* finally add the DMA device for this PSC */ - wd->dmapd = au1xpsc_pcm_add(pdev); - if (wd->dmapd) + if (!ret) return 0; - snd_soc_unregister_dai(&pdev->dev); +out2: + iounmap(wd->mmio); out1: release_mem_region(r->start, resource_size(r)); out0: @@ -351,9 +366,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev) struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev); struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (wd->dmapd) - au1xpsc_pcm_destroy(wd->dmapd); - snd_soc_unregister_dai(&pdev->dev); au_writel(0, I2S_CFG(wd)); diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index c59b9e544e72..1b21c4ffae12 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -19,10 +19,6 @@ #define SUBSTREAM_TYPE(substream) \ ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) -/* PSC/DBDMA helpers */ -extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev); -extern void au1xpsc_pcm_destroy(struct platform_device *dmapd); - struct au1xpsc_audio_data { void __iomem *mmio; @@ -34,7 +30,6 @@ struct au1xpsc_audio_data { unsigned long pm[2]; struct mutex lock; int dmaids[2]; - struct platform_device *dmapd; }; /* easy access macros */ -- cgit v1.2.3 From adbc7a5a61ee9225e0b80d3f5719e05a88db2b4c Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:45:03 +0200 Subject: ASoC: au1x: update db1200 machine to the new way of things The use of the "soc-audio" platform device is no longer en vogue, update the code to the newer, simpler way of doing things. Signed-off-by: Manuel Lauss Acked-by: Ralf Baechle Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- arch/mips/alchemy/devboards/db1200/platform.c | 10 +++++ sound/soc/au1x/db1200.c | 64 ++++++++++++++++++--------- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/arch/mips/alchemy/devboards/db1200/platform.c b/arch/mips/alchemy/devboards/db1200/platform.c index cfb71aed4cb9..dda090bf74e6 100644 --- a/arch/mips/alchemy/devboards/db1200/platform.c +++ b/arch/mips/alchemy/devboards/db1200/platform.c @@ -422,6 +422,7 @@ static struct resource au1200_psc1_res[] = { }, }; +/* AC97 or I2S device */ static struct platform_device db1200_audio_dev = { /* name assigned later based on switch setting */ .id = 1, /* PSC ID */ @@ -429,6 +430,12 @@ static struct platform_device db1200_audio_dev = { .resource = au1200_psc1_res, }; +/* DB1200 ASoC card device */ +static struct platform_device db1200_sound_dev = { + /* name assigned later based on switch setting */ + .id = 1, /* PSC ID */ +}; + static struct platform_device db1200_stac_dev = { .name = "ac97-codec", .id = 1, /* on PSC1 */ @@ -448,6 +455,7 @@ static struct platform_device *db1200_devs[] __initdata = { &db1200_audiodma_dev, &db1200_audio_dev, &db1200_stac_dev, + &db1200_sound_dev, }; static int __init db1200_dev_init(void) @@ -507,10 +515,12 @@ static int __init db1200_dev_init(void) if (sw == BCSR_SWITCHES_DIP_8) { bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC1MUX); db1200_audio_dev.name = "au1xpsc_i2s"; + db1200_sound_dev.name = "db1200-i2s"; printk(KERN_INFO " S6.7 ON : PSC1 mode I2S\n"); } else { bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC1MUX, 0); db1200_audio_dev.name = "au1xpsc_ac97"; + db1200_sound_dev.name = "db1200-ac97"; printk(KERN_INFO " S6.7 OFF: PSC1 mode AC97\n"); } diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c index 1d3e258c9ea8..289312c14b99 100644 --- a/sound/soc/au1x/db1200.c +++ b/sound/soc/au1x/db1200.c @@ -1,7 +1,7 @@ /* * DB1200 ASoC audio fabric support code. * - * (c) 2008-9 Manuel Lauss + * (c) 2008-2011 Manuel Lauss * */ @@ -21,6 +21,17 @@ #include "../codecs/wm8731.h" #include "psc.h" +static struct platform_device_id db1200_pids[] = { + { + .name = "db1200-ac97", + .driver_data = 0, + }, { + .name = "db1200-i2s", + .driver_data = 1, + }, + {}, +}; + /*------------------------- AC97 PART ---------------------------*/ static struct snd_soc_dai_link db1200_ac97_dai = { @@ -89,36 +100,47 @@ static struct snd_soc_card db1200_i2s_machine = { /*------------------------- COMMON PART ---------------------------*/ -static struct platform_device *db1200_asoc_dev; +static struct snd_soc_card *db1200_cards[] __devinitdata = { + &db1200_ac97_machine, + &db1200_i2s_machine, +}; -static int __init db1200_audio_load(void) +static int __devinit db1200_audio_probe(struct platform_device *pdev) { - int ret; + const struct platform_device_id *pid = platform_get_device_id(pdev); + struct snd_soc_card *card; - ret = -ENOMEM; - db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */ - if (!db1200_asoc_dev) - goto out; + card = db1200_cards[pid->driver_data]; + card->dev = &pdev->dev; + return snd_soc_register_card(card); +} - /* DB1200 board setup set PSC1MUX to preferred audio device */ - if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX) - platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine); - else - platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine); +static int __devexit db1200_audio_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + snd_soc_unregister_card(card); + return 0; +} - ret = platform_device_add(db1200_asoc_dev); +static struct platform_driver db1200_audio_driver = { + .driver = { + .name = "db1200-ac97", + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + }, + .id_table = db1200_pids, + .probe = db1200_audio_probe, + .remove = __devexit_p(db1200_audio_remove), +}; - if (ret) { - platform_device_put(db1200_asoc_dev); - db1200_asoc_dev = NULL; - } -out: - return ret; +static int __init db1200_audio_load(void) +{ + return platform_driver_register(&db1200_audio_driver); } static void __exit db1200_audio_unload(void) { - platform_device_unregister(db1200_asoc_dev); + platform_driver_unregister(&db1200_audio_driver); } module_init(db1200_audio_load); -- cgit v1.2.3 From 25942fdc824a709c48190356ed058ef7be19fb6a Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Mon, 25 Jul 2011 13:45:04 +0200 Subject: ASoC: au1x: use substream stream info directly PCM_TX/RX are the same as SNDRV_PCM_STREAM_PLAYBACK/CAPTURE. Use them directly. Signed-off-by: Manuel Lauss Acked-by: Ralf Baechle Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 10 +++++----- sound/soc/au1x/psc-ac97.c | 18 +++++++++--------- sound/soc/au1x/psc-i2s.c | 14 +++++++------- sound/soc/au1x/psc.h | 6 ------ 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index fd5378f7dece..d7d04e26eee5 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -169,7 +169,7 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd, au1x_pcm_dbdma_free(pcd); - if (stype == PCM_RX) + if (stype == SNDRV_PCM_STREAM_CAPTURE) pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id, DSCR_CMD0_ALWAYS, au1x_pcm_dmarx_cb, (void *)pcd); @@ -198,7 +198,7 @@ static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream struct snd_soc_pcm_runtime *rtd = ss->private_data; struct au1xpsc_audio_dmadata *pcd = snd_soc_platform_get_drvdata(rtd->platform); - return &pcd[SUBSTREAM_TYPE(ss)]; + return &pcd[ss->stream]; } static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, @@ -212,7 +212,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto out; - stype = SUBSTREAM_TYPE(substream); + stype = substream->stream; pcd = to_dmadata(substream); DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " @@ -255,7 +255,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream) au1xxx_dbdma_reset(pcd->ddma_chan); - if (SUBSTREAM_TYPE(substream) == PCM_RX) { + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { au1x_pcm_queue_rx(pcd); au1x_pcm_queue_rx(pcd); } else { @@ -295,7 +295,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream) { struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream); struct snd_soc_pcm_runtime *rtd = substream->private_data; - int stype = SUBSTREAM_TYPE(substream), *dmaids; + int stype = substream->stream, *dmaids; dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (!dmaids) diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 44296abfc38f..172eefd38b2d 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -41,14 +41,14 @@ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE) #define AC97PCR_START(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS) #define AC97PCR_STOP(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP) #define AC97PCR_CLRFIFO(stype) \ - ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) #define AC97STAT_BUSY(stype) \ - ((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) /* instance data. There can be only one, MacLeod!!!! */ static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; @@ -215,7 +215,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, { struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); unsigned long r, ro, stat; - int chans, t, stype = SUBSTREAM_TYPE(substream); + int chans, t, stype = substream->stream; chans = params_channels(params); @@ -235,7 +235,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, r |= PSC_AC97CFG_SET_LEN(params->msbits); /* channels: enable slots for front L/R channel */ - if (stype == PCM_TX) { + if (stype == SNDRV_PCM_STREAM_PLAYBACK) { r &= ~PSC_AC97CFG_TXSLOT_MASK; r |= PSC_AC97CFG_TXSLOT_ENA(3); r |= PSC_AC97CFG_TXSLOT_ENA(4); @@ -294,7 +294,7 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); - int ret, stype = SUBSTREAM_TYPE(substream); + int ret, stype = substream->stream; ret = 0; @@ -391,12 +391,12 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!r) goto out2; - wd->dmaids[PCM_TX] = r->start; + wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; r = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!r) goto out2; - wd->dmaids[PCM_RX] = r->start; + wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; /* configuration: max dma trigger threshold, enable ac97 */ wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index 1b7ab5d422e0..7c5ae920544f 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -42,13 +42,13 @@ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) #define I2SSTAT_BUSY(stype) \ - ((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB) #define I2SPCR_START(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TS : PSC_I2SPCR_RS) #define I2SPCR_STOP(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TP : PSC_I2SPCR_RP) #define I2SPCR_CLRFIFO(stype) \ - ((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) + ((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TC : PSC_I2SPCR_RC) static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, @@ -240,7 +240,7 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai); - int ret, stype = SUBSTREAM_TYPE(substream); + int ret, stype = substream->stream; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -316,12 +316,12 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!r) goto out2; - wd->dmaids[PCM_TX] = r->start; + wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; r = platform_get_resource(pdev, IORESOURCE_DMA, 1); if (!r) goto out2; - wd->dmaids[PCM_RX] = r->start; + wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; /* preserve PSC clock source set up by platform (dev.platform_data * is already occupied by soc layer) diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index 1b21c4ffae12..b16b2e02e0c9 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h @@ -13,12 +13,6 @@ #ifndef _AU1X_PCM_H #define _AU1X_PCM_H -#define PCM_TX 0 -#define PCM_RX 1 - -#define SUBSTREAM_TYPE(substream) \ - ((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX) - struct au1xpsc_audio_data { void __iomem *mmio; -- cgit v1.2.3 From ed6e1d04c106f69882c055a72a63111ed9dadc01 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Jul 2011 12:36:55 +0800 Subject: ASoC: mxs: add mxs-pcm driver Signed-off-by: Dong Aisheng Acked-by: Liam Girdwood Tested-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-pcm.c | 359 ++++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/mxs/mxs-pcm.h | 43 ++++++ 2 files changed, 402 insertions(+) create mode 100644 sound/soc/mxs/mxs-pcm.c create mode 100644 sound/soc/mxs/mxs-pcm.h diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c new file mode 100644 index 000000000000..dea5aa4aa647 --- /dev/null +++ b/sound/soc/mxs/mxs-pcm.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Based on sound/soc/imx/imx-pcm-dma-mx2.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "mxs-pcm.h" + +static struct snd_pcm_hardware snd_mxs_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_INTERLEAVED, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 2, + .period_bytes_min = 32, + .period_bytes_max = 8192, + .periods_min = 1, + .periods_max = 52, + .buffer_bytes_max = 64 * 1024, + .fifo_size = 32, + +}; + +static void audio_dma_irq(void *data) +{ + struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + + iprtd->offset += iprtd->period_bytes; + iprtd->offset %= iprtd->period_bytes * iprtd->periods; + snd_pcm_period_elapsed(substream); +} + +static bool filter(struct dma_chan *chan, void *param) +{ + struct mxs_pcm_runtime_data *iprtd = param; + struct mxs_pcm_dma_params *dma_params = iprtd->dma_params; + + if (!mxs_dma_is_apbx(chan)) + return false; + + if (chan->chan_id != dma_params->chan_num) + return false; + + chan->private = &iprtd->dma_data; + + return true; +} + +static int mxs_dma_alloc(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + dma_cap_mask_t mask; + + iprtd->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + iprtd->dma_data.chan_irq = iprtd->dma_params->chan_irq; + iprtd->dma_chan = dma_request_channel(mask, filter, iprtd); + if (!iprtd->dma_chan) + return -EINVAL; + + return 0; +} + +static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + unsigned long dma_addr; + struct dma_chan *chan; + int ret; + + ret = mxs_dma_alloc(substream, params); + if (ret) + return ret; + chan = iprtd->dma_chan; + + iprtd->size = params_buffer_bytes(params); + iprtd->periods = params_periods(params); + iprtd->period_bytes = params_period_bytes(params); + iprtd->offset = 0; + iprtd->period_time = HZ / (params_rate(params) / + params_period_size(params)); + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + + dma_addr = runtime->dma_addr; + + iprtd->buf = substream->dma_buffer.area; + + iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr, + iprtd->period_bytes * iprtd->periods, + iprtd->period_bytes, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!iprtd->desc) { + dev_err(&chan->dev->device, "cannot prepare slave dma\n"); + return -EINVAL; + } + + iprtd->desc->callback = audio_dma_irq; + iprtd->desc->callback_param = substream; + + return 0; +} + +static int snd_mxs_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + + if (iprtd->dma_chan) { + dma_release_channel(iprtd->dma_chan); + iprtd->dma_chan = NULL; + } + + return 0; +} + +static int snd_mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dmaengine_submit(iprtd->desc); + + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dmaengine_terminate_all(iprtd->dma_chan); + + break; + default: + return -EINVAL; + } + + return 0; +} + +static snd_pcm_uframes_t snd_mxs_pcm_pointer( + struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + + return bytes_to_frames(substream->runtime, iprtd->offset); +} + +static int snd_mxs_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd; + int ret; + + iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); + if (iprtd == NULL) + return -ENOMEM; + runtime->private_data = iprtd; + + ret = snd_pcm_hw_constraint_integer(substream->runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + kfree(iprtd); + return ret; + } + + snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); + + return 0; +} + +static int snd_mxs_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct mxs_pcm_runtime_data *iprtd = runtime->private_data; + + kfree(iprtd); + + return 0; +} + +static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return dma_mmap_writecombine(substream->pcm->card->dev, vma, + runtime->dma_area, + runtime->dma_addr, + runtime->dma_bytes); +} + +static struct snd_pcm_ops mxs_pcm_ops = { + .open = snd_mxs_open, + .close = snd_mxs_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_mxs_pcm_hw_params, + .hw_free = snd_mxs_pcm_hw_free, + .trigger = snd_mxs_pcm_trigger, + .pointer = snd_mxs_pcm_pointer, + .mmap = snd_mxs_pcm_mmap, +}; + +static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = snd_mxs_hardware.buffer_bytes_max; + + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + buf->area = dma_alloc_writecombine(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + + return 0; +} + +static u64 mxs_pcm_dmamask = DMA_BIT_MASK(32); +static int mxs_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_card *card = rtd->card->snd_card; + struct snd_pcm *pcm = rtd->pcm; + int ret = 0; + + if (!card->dev->dma_mask) + card->dev->dma_mask = &mxs_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + ret = mxs_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + ret = mxs_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + +out: + return ret; +} + +static void mxs_pcm_free(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_writecombine(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static struct snd_soc_platform_driver mxs_soc_platform = { + .ops = &mxs_pcm_ops, + .pcm_new = mxs_pcm_new, + .pcm_free = mxs_pcm_free, +}; + +static int __devinit mxs_soc_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform); +} + +static int __devexit mxs_soc_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_platform(&pdev->dev); + + return 0; +} + +static struct platform_driver mxs_pcm_driver = { + .driver = { + .name = "mxs-pcm-audio", + .owner = THIS_MODULE, + }, + .probe = mxs_soc_platform_probe, + .remove = __devexit_p(mxs_soc_platform_remove), +}; + +static int __init snd_mxs_pcm_init(void) +{ + return platform_driver_register(&mxs_pcm_driver); +} +module_init(snd_mxs_pcm_init); + +static void __exit snd_mxs_pcm_exit(void) +{ + platform_driver_unregister(&mxs_pcm_driver); +} +module_exit(snd_mxs_pcm_exit); diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h new file mode 100644 index 000000000000..f55ac4f7a76a --- /dev/null +++ b/sound/soc/mxs/mxs-pcm.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _MXS_PCM_H +#define _MXS_PCM_H + +#include + +struct mxs_pcm_dma_params { + int chan_irq; + int chan_num; +}; + +struct mxs_pcm_runtime_data { + int period_bytes; + int periods; + int dma; + unsigned long offset; + unsigned long size; + void *buf; + int period_time; + struct dma_async_tx_descriptor *desc; + struct dma_chan *dma_chan; + struct mxs_dma_data dma_data; + struct mxs_pcm_dma_params *dma_params; +}; + +#endif -- cgit v1.2.3 From 2a24f2ce89b6157192c10616492be8a981b0cce8 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Jul 2011 12:36:56 +0800 Subject: ASoC: mxs: add mxs-saif driver Signed-off-by: Dong Aisheng Acked-by: Liam Girdwood Tested-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 677 +++++++++++++++++++++++++++++++++++++++++++++++ sound/soc/mxs/mxs-saif.h | 130 +++++++++ 2 files changed, 807 insertions(+) create mode 100644 sound/soc/mxs/mxs-saif.c create mode 100644 sound/soc/mxs/mxs-saif.h diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c new file mode 100644 index 000000000000..0b3adaec9f4c --- /dev/null +++ b/sound/soc/mxs/mxs-saif.c @@ -0,0 +1,677 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mxs-saif.h" + +static struct mxs_saif *mxs_saif[2]; + +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + + switch (clk_id) { + case MXS_SAIF_MCLK: + saif->mclk = freq; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Set SAIF clock and MCLK + */ +static int mxs_saif_set_clk(struct mxs_saif *saif, + unsigned int mclk, + unsigned int rate) +{ + u32 scr; + int ret; + + scr = __raw_readl(saif->base + SAIF_CTRL); + scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE; + scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; + + /* + * Set SAIF clock + * + * The SAIF clock should be either 384*fs or 512*fs. + * If MCLK is used, the SAIF clk ratio need to match mclk ratio. + * For 32x mclk, set saif clk as 512*fs. + * For 48x mclk, set saif clk as 384*fs. + * + * If MCLK is not used, we just set saif clk to 512*fs. + */ + if (saif->mclk_in_use) { + if (mclk % 32 == 0) { + scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; + ret = clk_set_rate(saif->clk, 512 * rate); + } else if (mclk % 48 == 0) { + scr |= BM_SAIF_CTRL_BITCLK_BASE_RATE; + ret = clk_set_rate(saif->clk, 384 * rate); + } else { + /* SAIF MCLK should be either 32x or 48x */ + return -EINVAL; + } + } else { + ret = clk_set_rate(saif->clk, 512 * rate); + scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; + } + + if (ret) + return ret; + + if (!saif->mclk_in_use) { + __raw_writel(scr, saif->base + SAIF_CTRL); + return 0; + } + + /* + * Program the over-sample rate for MCLK output + * + * The available MCLK range is 32x, 48x... 512x. The rate + * could be from 8kHz to 192kH. + */ + switch (mclk / rate) { + case 32: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(4); + break; + case 64: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3); + break; + case 128: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2); + break; + case 256: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1); + break; + case 512: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0); + break; + case 48: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(3); + break; + case 96: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(2); + break; + case 192: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(1); + break; + case 384: + scr |= BF_SAIF_CTRL_BITCLK_MULT_RATE(0); + break; + default: + return -EINVAL; + } + + __raw_writel(scr, saif->base + SAIF_CTRL); + + return 0; +} + +/* + * Put and disable MCLK. + */ +int mxs_saif_put_mclk(unsigned int saif_id) +{ + struct mxs_saif *saif = mxs_saif[saif_id]; + u32 stat; + + if (!saif) + return -EINVAL; + + stat = __raw_readl(saif->base + SAIF_STAT); + if (stat & BM_SAIF_STAT_BUSY) { + dev_err(saif->dev, "error: busy\n"); + return -EBUSY; + } + + clk_disable(saif->clk); + + /* disable MCLK output */ + __raw_writel(BM_SAIF_CTRL_CLKGATE, + saif->base + SAIF_CTRL + MXS_SET_ADDR); + __raw_writel(BM_SAIF_CTRL_RUN, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + + saif->mclk_in_use = 0; + return 0; +} + +/* + * Get MCLK and set clock rate, then enable it + * + * This interface is used for codecs who are using MCLK provided + * by saif. + */ +int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk, + unsigned int rate) +{ + struct mxs_saif *saif = mxs_saif[saif_id]; + u32 stat; + int ret; + + if (!saif) + return -EINVAL; + + stat = __raw_readl(saif->base + SAIF_STAT); + if (stat & BM_SAIF_STAT_BUSY) { + dev_err(saif->dev, "error: busy\n"); + return -EBUSY; + } + + /* Clear Reset */ + __raw_writel(BM_SAIF_CTRL_SFTRST, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + + saif->mclk_in_use = 1; + ret = mxs_saif_set_clk(saif, mclk, rate); + if (ret) + return ret; + + ret = clk_enable(saif->clk); + if (ret) + return ret; + + /* enable MCLK output */ + __raw_writel(BM_SAIF_CTRL_CLKGATE, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + __raw_writel(BM_SAIF_CTRL_RUN, + saif->base + SAIF_CTRL + MXS_SET_ADDR); + + return 0; +} + +/* + * SAIF DAI format configuration. + * Should only be called when port is inactive. + */ +static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + u32 scr, stat; + u32 scr0; + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + + stat = __raw_readl(saif->base + SAIF_STAT); + if (stat & BM_SAIF_STAT_BUSY) { + dev_err(cpu_dai->dev, "error: busy\n"); + return -EBUSY; + } + + scr0 = __raw_readl(saif->base + SAIF_CTRL); + scr0 = scr0 & ~BM_SAIF_CTRL_BITCLK_EDGE & ~BM_SAIF_CTRL_LRCLK_POLARITY \ + & ~BM_SAIF_CTRL_JUSTIFY & ~BM_SAIF_CTRL_DELAY; + scr = 0; + + /* DAI mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* data frame low 1clk before data */ + scr |= BM_SAIF_CTRL_DELAY; + scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; + break; + case SND_SOC_DAIFMT_LEFT_J: + /* data frame high with data */ + scr &= ~BM_SAIF_CTRL_DELAY; + scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; + scr &= ~BM_SAIF_CTRL_JUSTIFY; + break; + default: + return -EINVAL; + } + + /* DAI clock inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + scr |= BM_SAIF_CTRL_BITCLK_EDGE; + scr |= BM_SAIF_CTRL_LRCLK_POLARITY; + break; + case SND_SOC_DAIFMT_IB_NF: + scr |= BM_SAIF_CTRL_BITCLK_EDGE; + scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; + break; + case SND_SOC_DAIFMT_NB_IF: + scr &= ~BM_SAIF_CTRL_BITCLK_EDGE; + scr |= BM_SAIF_CTRL_LRCLK_POLARITY; + break; + case SND_SOC_DAIFMT_NB_NF: + scr &= ~BM_SAIF_CTRL_BITCLK_EDGE; + scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; + break; + } + + /* + * Note: We simply just support master mode since SAIF TX can only + * work as master. + */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + scr &= ~BM_SAIF_CTRL_SLAVE_MODE; + __raw_writel(scr | scr0, saif->base + SAIF_CTRL); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int mxs_saif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param); + + /* clear error status to 0 for each re-open */ + saif->fifo_underrun = 0; + saif->fifo_overrun = 0; + + /* Clear Reset for normal operations */ + __raw_writel(BM_SAIF_CTRL_SFTRST, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + + return 0; +} + +/* + * Should only be called when port is inactive. + * although can be called multiple times by upper layers. + */ +static int mxs_saif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + u32 scr, stat; + int ret; + + /* mclk should already be set */ + if (!saif->mclk && saif->mclk_in_use) { + dev_err(cpu_dai->dev, "set mclk first\n"); + return -EINVAL; + } + + stat = __raw_readl(saif->base + SAIF_STAT); + if (stat & BM_SAIF_STAT_BUSY) { + dev_err(cpu_dai->dev, "error: busy\n"); + return -EBUSY; + } + + /* + * Set saif clk based on sample rate. + * If mclk is used, we also set mclk, if not, saif->mclk is + * default 0, means not used. + */ + ret = mxs_saif_set_clk(saif, saif->mclk, params_rate(params)); + if (ret) { + dev_err(cpu_dai->dev, "unable to get proper clk\n"); + return ret; + } + + scr = __raw_readl(saif->base + SAIF_CTRL); + + scr &= ~BM_SAIF_CTRL_WORD_LENGTH; + scr &= ~BM_SAIF_CTRL_BITCLK_48XFS_ENABLE; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + scr |= BF_SAIF_CTRL_WORD_LENGTH(0); + break; + case SNDRV_PCM_FORMAT_S20_3LE: + scr |= BF_SAIF_CTRL_WORD_LENGTH(4); + scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE; + break; + case SNDRV_PCM_FORMAT_S24_LE: + scr |= BF_SAIF_CTRL_WORD_LENGTH(8); + scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE; + break; + default: + return -EINVAL; + } + + /* Tx/Rx config */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* enable TX mode */ + scr &= ~BM_SAIF_CTRL_READ_MODE; + } else { + /* enable RX mode */ + scr |= BM_SAIF_CTRL_READ_MODE; + } + + __raw_writel(scr, saif->base + SAIF_CTRL); + return 0; +} + +static int mxs_saif_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + + /* clear clock gate */ + __raw_writel(BM_SAIF_CTRL_CLKGATE, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + + /* enable FIFO error irqs */ + __raw_writel(BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN, + saif->base + SAIF_CTRL + MXS_SET_ADDR); + + return 0; +} + +static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *cpu_dai) +{ + struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dev_dbg(cpu_dai->dev, "start\n"); + + clk_enable(saif->clk); + if (!saif->mclk_in_use) + __raw_writel(BM_SAIF_CTRL_RUN, + saif->base + SAIF_CTRL + MXS_SET_ADDR); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* + * write a data to saif data register to trigger + * the transfer + */ + __raw_writel(0, saif->base + SAIF_DATA); + } else { + /* + * read a data from saif data register to trigger + * the receive + */ + __raw_readl(saif->base + SAIF_DATA); + } + + dev_dbg(cpu_dai->dev, "CTRL 0x%x STAT 0x%x\n", + __raw_readl(saif->base + SAIF_CTRL), + __raw_readl(saif->base + SAIF_STAT)); + + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dev_dbg(cpu_dai->dev, "stop\n"); + + clk_disable(saif->clk); + if (!saif->mclk_in_use) + __raw_writel(BM_SAIF_CTRL_RUN, + saif->base + SAIF_CTRL + MXS_CLR_ADDR); + + break; + default: + return -EINVAL; + } + + return 0; +} + +#define MXS_SAIF_RATES SNDRV_PCM_RATE_8000_192000 +#define MXS_SAIF_FORMATS \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops mxs_saif_dai_ops = { + .startup = mxs_saif_startup, + .trigger = mxs_saif_trigger, + .prepare = mxs_saif_prepare, + .hw_params = mxs_saif_hw_params, + .set_sysclk = mxs_saif_set_dai_sysclk, + .set_fmt = mxs_saif_set_dai_fmt, +}; + +static int mxs_saif_dai_probe(struct snd_soc_dai *dai) +{ + struct mxs_saif *saif = dev_get_drvdata(dai->dev); + + snd_soc_dai_set_drvdata(dai, saif); + + return 0; +} + +static struct snd_soc_dai_driver mxs_saif_dai = { + .name = "mxs-saif", + .probe = mxs_saif_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = MXS_SAIF_RATES, + .formats = MXS_SAIF_FORMATS, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = MXS_SAIF_RATES, + .formats = MXS_SAIF_FORMATS, + }, + .ops = &mxs_saif_dai_ops, +}; + +static irqreturn_t mxs_saif_irq(int irq, void *dev_id) +{ + struct mxs_saif *saif = dev_id; + unsigned int stat; + + stat = __raw_readl(saif->base + SAIF_STAT); + if (!(stat & (BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ | + BM_SAIF_STAT_FIFO_OVERFLOW_IRQ))) + return IRQ_NONE; + + if (stat & BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ) { + dev_dbg(saif->dev, "underrun!!! %d\n", ++saif->fifo_underrun); + __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ, + saif->base + SAIF_STAT + MXS_CLR_ADDR); + } + + if (stat & BM_SAIF_STAT_FIFO_OVERFLOW_IRQ) { + dev_dbg(saif->dev, "overrun!!! %d\n", ++saif->fifo_overrun); + __raw_writel(BM_SAIF_STAT_FIFO_OVERFLOW_IRQ, + saif->base + SAIF_STAT + MXS_CLR_ADDR); + } + + dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n", + __raw_readl(saif->base + SAIF_CTRL), + __raw_readl(saif->base + SAIF_STAT)); + + return IRQ_HANDLED; +} + +static int mxs_saif_probe(struct platform_device *pdev) +{ + struct resource *res; + struct mxs_saif *saif; + int ret = 0; + + saif = kzalloc(sizeof(*saif), GFP_KERNEL); + if (!saif) + return -ENOMEM; + + if (pdev->id >= ARRAY_SIZE(mxs_saif)) + return -EINVAL; + mxs_saif[pdev->id] = saif; + + saif->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(saif->clk)) { + ret = PTR_ERR(saif->clk); + dev_err(&pdev->dev, "Cannot get the clock: %d\n", + ret); + goto failed_clk; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + dev_err(&pdev->dev, "failed to get io resource: %d\n", + ret); + goto failed_get_resource; + } + + if (!request_mem_region(res->start, resource_size(res), "mxs-saif")) { + dev_err(&pdev->dev, "request_mem_region failed\n"); + ret = -EBUSY; + goto failed_get_resource; + } + + saif->base = ioremap(res->start, resource_size(res)); + if (!saif->base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENODEV; + goto failed_ioremap; + } + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + ret = -ENODEV; + dev_err(&pdev->dev, "failed to get dma resource: %d\n", + ret); + goto failed_ioremap; + } + saif->dma_param.chan_num = res->start; + + saif->irq = platform_get_irq(pdev, 0); + if (saif->irq < 0) { + ret = saif->irq; + dev_err(&pdev->dev, "failed to get irq resource: %d\n", + ret); + goto failed_get_irq1; + } + + saif->dev = &pdev->dev; + ret = request_irq(saif->irq, mxs_saif_irq, 0, "mxs-saif", saif); + if (ret) { + dev_err(&pdev->dev, "failed to request irq\n"); + goto failed_get_irq1; + } + + saif->dma_param.chan_irq = platform_get_irq(pdev, 1); + if (saif->dma_param.chan_irq < 0) { + ret = saif->dma_param.chan_irq; + dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", + ret); + goto failed_get_irq2; + } + + platform_set_drvdata(pdev, saif); + + ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai); + if (ret) { + dev_err(&pdev->dev, "register DAI failed\n"); + goto failed_register; + } + + saif->soc_platform_pdev = platform_device_alloc( + "mxs-pcm-audio", pdev->id); + if (!saif->soc_platform_pdev) { + ret = -ENOMEM; + goto failed_pdev_alloc; + } + + platform_set_drvdata(saif->soc_platform_pdev, saif); + ret = platform_device_add(saif->soc_platform_pdev); + if (ret) { + dev_err(&pdev->dev, "failed to add soc platform device\n"); + goto failed_pdev_add; + } + + return 0; + +failed_pdev_add: + platform_device_put(saif->soc_platform_pdev); +failed_pdev_alloc: + snd_soc_unregister_dai(&pdev->dev); +failed_register: +failed_get_irq2: + free_irq(saif->irq, saif); +failed_get_irq1: + iounmap(saif->base); +failed_ioremap: + release_mem_region(res->start, resource_size(res)); +failed_get_resource: + clk_put(saif->clk); +failed_clk: + kfree(saif); + + return ret; +} + +static int __devexit mxs_saif_remove(struct platform_device *pdev) +{ + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct mxs_saif *saif = platform_get_drvdata(pdev); + + platform_device_unregister(saif->soc_platform_pdev); + + snd_soc_unregister_dai(&pdev->dev); + + iounmap(saif->base); + release_mem_region(res->start, resource_size(res)); + free_irq(saif->irq, saif); + + clk_put(saif->clk); + kfree(saif); + + return 0; +} + +static struct platform_driver mxs_saif_driver = { + .probe = mxs_saif_probe, + .remove = __devexit_p(mxs_saif_remove), + + .driver = { + .name = "mxs-saif", + .owner = THIS_MODULE, + }, +}; + +static int __init mxs_saif_init(void) +{ + return platform_driver_register(&mxs_saif_driver); +} + +static void __exit mxs_saif_exit(void) +{ + platform_driver_unregister(&mxs_saif_driver); +} + +module_init(mxs_saif_init); +module_exit(mxs_saif_exit); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXS ASoC SAIF driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h new file mode 100644 index 000000000000..0e2ff8cdbfee --- /dev/null +++ b/sound/soc/mxs/mxs-saif.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +#ifndef _MXS_SAIF_H +#define _MXS_SAIF_H + +#define SAIF_CTRL 0x0 +#define SAIF_STAT 0x10 +#define SAIF_DATA 0x20 +#define SAIF_VERSION 0X30 + +/* SAIF_CTRL */ +#define BM_SAIF_CTRL_SFTRST 0x80000000 +#define BM_SAIF_CTRL_CLKGATE 0x40000000 +#define BP_SAIF_CTRL_BITCLK_MULT_RATE 27 +#define BM_SAIF_CTRL_BITCLK_MULT_RATE 0x38000000 +#define BF_SAIF_CTRL_BITCLK_MULT_RATE(v) \ + (((v) << 27) & BM_SAIF_CTRL_BITCLK_MULT_RATE) +#define BM_SAIF_CTRL_BITCLK_BASE_RATE 0x04000000 +#define BM_SAIF_CTRL_FIFO_ERROR_IRQ_EN 0x02000000 +#define BM_SAIF_CTRL_FIFO_SERVICE_IRQ_EN 0x01000000 +#define BP_SAIF_CTRL_RSRVD2 21 +#define BM_SAIF_CTRL_RSRVD2 0x00E00000 + +#define BP_SAIF_CTRL_DMAWAIT_COUNT 16 +#define BM_SAIF_CTRL_DMAWAIT_COUNT 0x001F0000 +#define BF_SAIF_CTRL_DMAWAIT_COUNT(v) \ + (((v) << 16) & BM_SAIF_CTRL_DMAWAIT_COUNT) +#define BP_SAIF_CTRL_CHANNEL_NUM_SELECT 14 +#define BM_SAIF_CTRL_CHANNEL_NUM_SELECT 0x0000C000 +#define BF_SAIF_CTRL_CHANNEL_NUM_SELECT(v) \ + (((v) << 14) & BM_SAIF_CTRL_CHANNEL_NUM_SELECT) +#define BM_SAIF_CTRL_LRCLK_PULSE 0x00002000 +#define BM_SAIF_CTRL_BIT_ORDER 0x00001000 +#define BM_SAIF_CTRL_DELAY 0x00000800 +#define BM_SAIF_CTRL_JUSTIFY 0x00000400 +#define BM_SAIF_CTRL_LRCLK_POLARITY 0x00000200 +#define BM_SAIF_CTRL_BITCLK_EDGE 0x00000100 +#define BP_SAIF_CTRL_WORD_LENGTH 4 +#define BM_SAIF_CTRL_WORD_LENGTH 0x000000F0 +#define BF_SAIF_CTRL_WORD_LENGTH(v) \ + (((v) << 4) & BM_SAIF_CTRL_WORD_LENGTH) +#define BM_SAIF_CTRL_BITCLK_48XFS_ENABLE 0x00000008 +#define BM_SAIF_CTRL_SLAVE_MODE 0x00000004 +#define BM_SAIF_CTRL_READ_MODE 0x00000002 +#define BM_SAIF_CTRL_RUN 0x00000001 + +/* SAIF_STAT */ +#define BM_SAIF_STAT_PRESENT 0x80000000 +#define BP_SAIF_STAT_RSRVD2 17 +#define BM_SAIF_STAT_RSRVD2 0x7FFE0000 +#define BF_SAIF_STAT_RSRVD2(v) \ + (((v) << 17) & BM_SAIF_STAT_RSRVD2) +#define BM_SAIF_STAT_DMA_PREQ 0x00010000 +#define BP_SAIF_STAT_RSRVD1 7 +#define BM_SAIF_STAT_RSRVD1 0x0000FF80 +#define BF_SAIF_STAT_RSRVD1(v) \ + (((v) << 7) & BM_SAIF_STAT_RSRVD1) + +#define BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ 0x00000040 +#define BM_SAIF_STAT_FIFO_OVERFLOW_IRQ 0x00000020 +#define BM_SAIF_STAT_FIFO_SERVICE_IRQ 0x00000010 +#define BP_SAIF_STAT_RSRVD0 1 +#define BM_SAIF_STAT_RSRVD0 0x0000000E +#define BF_SAIF_STAT_RSRVD0(v) \ + (((v) << 1) & BM_SAIF_STAT_RSRVD0) +#define BM_SAIF_STAT_BUSY 0x00000001 + +/* SAFI_DATA */ +#define BP_SAIF_DATA_PCM_RIGHT 16 +#define BM_SAIF_DATA_PCM_RIGHT 0xFFFF0000 +#define BF_SAIF_DATA_PCM_RIGHT(v) \ + (((v) << 16) & BM_SAIF_DATA_PCM_RIGHT) +#define BP_SAIF_DATA_PCM_LEFT 0 +#define BM_SAIF_DATA_PCM_LEFT 0x0000FFFF +#define BF_SAIF_DATA_PCM_LEFT(v) \ + (((v) << 0) & BM_SAIF_DATA_PCM_LEFT) + +/* SAIF_VERSION */ +#define BP_SAIF_VERSION_MAJOR 24 +#define BM_SAIF_VERSION_MAJOR 0xFF000000 +#define BF_SAIF_VERSION_MAJOR(v) \ + (((v) << 24) & BM_SAIF_VERSION_MAJOR) +#define BP_SAIF_VERSION_MINOR 16 +#define BM_SAIF_VERSION_MINOR 0x00FF0000 +#define BF_SAIF_VERSION_MINOR(v) \ + (((v) << 16) & BM_SAIF_VERSION_MINOR) +#define BP_SAIF_VERSION_STEP 0 +#define BM_SAIF_VERSION_STEP 0x0000FFFF +#define BF_SAIF_VERSION_STEP(v) \ + (((v) << 0) & BM_SAIF_VERSION_STEP) + +#define MXS_SAIF_MCLK 0 + +#include "mxs-pcm.h" + +struct mxs_saif { + struct device *dev; + struct clk *clk; + unsigned int mclk; + unsigned int mclk_in_use; + void __iomem *base; + int irq; + struct mxs_pcm_dma_params dma_param; + + struct platform_device *soc_platform_pdev; + u32 fifo_underrun; + u32 fifo_overrun; +}; + +extern int mxs_saif_put_mclk(unsigned int saif_id); +extern int mxs_saif_get_mclk(unsigned int saif_id, unsigned int mclk, + unsigned int rate); +#endif -- cgit v1.2.3 From fcb5e47eff29a10e9cbc55a7660746695e303671 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Jul 2011 12:36:57 +0800 Subject: ASoC: mxs: add mxs-sgtl5000 machine driver The driver only supports playback firstly. For recording, as we have to use two saif instances to implement full duplex (playback & recording) due to hardware limitation, we need to figure out a good design to fit in ASoC. Signed-off-by: Dong Aisheng Acked-by: Liam Girdwood Tested-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-sgtl5000.c | 165 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 sound/soc/mxs/mxs-sgtl5000.c diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c new file mode 100644 index 000000000000..a0d89c93df0f --- /dev/null +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -0,0 +1,165 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/sgtl5000.h" +#include "mxs-saif.h" + +static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int rate = params_rate(params); + u32 dai_format, mclk; + int ret; + + /* sgtl5000 does not support 512*rate when in 96000 fs */ + switch (rate) { + case 96000: + mclk = 256 * rate; + break; + default: + mclk = 512 * rate; + break; + } + + /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ + if (mclk < 8000000 || mclk > 27000000) + return -EINVAL; + + /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ + ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); + if (ret) + return ret; + + /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */ + ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0); + if (ret) + return ret; + + /* set codec to slave mode */ + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, dai_format); + if (ret) + return ret; + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); + if (ret) + return ret; + + return 0; +} + +static struct snd_soc_ops mxs_sgtl5000_hifi_ops = { + .hw_params = mxs_sgtl5000_hw_params, +}; + +static struct snd_soc_dai_link mxs_sgtl5000_dai[] = { + { + .name = "HiFi", + .stream_name = "HiFi Playback", + .codec_dai_name = "sgtl5000", + .codec_name = "sgtl5000.0-000a", + .cpu_dai_name = "mxs-saif.0", + .platform_name = "mxs-pcm-audio.0", + .ops = &mxs_sgtl5000_hifi_ops, + }, +}; + +static struct snd_soc_card mxs_sgtl5000 = { + .name = "mxs_sgtl5000", + .dai_link = mxs_sgtl5000_dai, + .num_links = ARRAY_SIZE(mxs_sgtl5000_dai), +}; + +static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &mxs_sgtl5000; + int ret; + + /* + * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w). + * The Sgtl5000 sysclk is derived from saif0 mclk and it's range + * should be >= 8MHz and <= 27M. + */ + ret = mxs_saif_get_mclk(0, 44100 * 256, 44100); + if (ret) + return ret; + + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + return ret; + } + + return 0; +} + +static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + + mxs_saif_put_mclk(0); + + snd_soc_unregister_card(card); + + return 0; +} + +static struct platform_driver mxs_sgtl5000_audio_driver = { + .driver = { + .name = "mxs-sgtl5000", + .owner = THIS_MODULE, + }, + .probe = mxs_sgtl5000_probe, + .remove = __devexit_p(mxs_sgtl5000_remove), +}; + +static int __init mxs_sgtl5000_init(void) +{ + return platform_driver_register(&mxs_sgtl5000_audio_driver); +} +module_init(mxs_sgtl5000_init); + +static void __exit mxs_sgtl5000_exit(void) +{ + platform_driver_unregister(&mxs_sgtl5000_audio_driver); +} +module_exit(mxs_sgtl5000_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXS ALSA SoC Machine driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 009ad054b71b77264157c70c58654543acc0c566 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Jul 2011 12:36:58 +0800 Subject: ASoC: mxs: add asoc configuration files Signed-off-by: Dong Aisheng Acked-by: Liam Girdwood Tested-by: Wolfram Sang Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/mxs/Kconfig | 20 ++++++++++++++++++++ sound/soc/mxs/Makefile | 10 ++++++++++ 4 files changed, 32 insertions(+) create mode 100644 sound/soc/mxs/Kconfig create mode 100644 sound/soc/mxs/Makefile diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 8224db5f0434..47d07ce4e867 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -51,6 +51,7 @@ source "sound/soc/nuc900/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/kirkwood/Kconfig" source "sound/soc/mid-x86/Kconfig" +source "sound/soc/mxs/Kconfig" source "sound/soc/pxa/Kconfig" source "sound/soc/samsung/Kconfig" source "sound/soc/s6000/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 4f913876f332..9ea8ac827adc 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += imx/ obj-$(CONFIG_SND_SOC) += jz4740/ obj-$(CONFIG_SND_SOC) += mid-x86/ +obj-$(CONFIG_SND_SOC) += mxs/ obj-$(CONFIG_SND_SOC) += nuc900/ obj-$(CONFIG_SND_SOC) += omap/ obj-$(CONFIG_SND_SOC) += kirkwood/ diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig new file mode 100644 index 000000000000..e4ba8d5f25fa --- /dev/null +++ b/sound/soc/mxs/Kconfig @@ -0,0 +1,20 @@ +menuconfig SND_MXS_SOC + tristate "SoC Audio for Freescale MXS CPUs" + depends on ARCH_MXS + select SND_PCM + help + Say Y or M if you want to add support for codecs attached to + the MXS SAIF interface. + + +if SND_MXS_SOC + +config SND_SOC_MXS_SGTL5000 + tristate "SoC Audio support for i.MX boards with sgtl5000" + depends on I2C + select SND_SOC_SGTL5000 + help + Say Y if you want to add support for SoC audio on an MXS board with + a sgtl5000 codec. + +endif # SND_MXS_SOC diff --git a/sound/soc/mxs/Makefile b/sound/soc/mxs/Makefile new file mode 100644 index 000000000000..565b5b51e8b7 --- /dev/null +++ b/sound/soc/mxs/Makefile @@ -0,0 +1,10 @@ +# MXS Platform Support +snd-soc-mxs-objs := mxs-saif.o +snd-soc-mxs-pcm-objs := mxs-pcm.o + +obj-$(CONFIG_SND_MXS_SOC) += snd-soc-mxs.o snd-soc-mxs-pcm.o + +# i.MX Machine Support +snd-soc-mxs-sgtl5000-objs := mxs-sgtl5000.o + +obj-$(CONFIG_SND_SOC_MXS_SGTL5000) += snd-soc-mxs-sgtl5000.o -- cgit v1.2.3 From a7f96e4dc6bb5f45d0612782419e6a63032a2ac0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 26 Jul 2011 21:00:13 +0100 Subject: ASoC: Add device tree binding for WM8731 Tested with the famous "hey, look! this compiles" test plan. Signed-off-by: Mark Brown Acked-by: Liam Girdwood Acked by: Grant Likely --- Documentation/devicetree/bindings/sound/wm8731.txt | 18 ++++++++++++++++++ sound/soc/codecs/wm8731.c | 10 ++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/wm8731.txt diff --git a/Documentation/devicetree/bindings/sound/wm8731.txt b/Documentation/devicetree/bindings/sound/wm8731.txt new file mode 100644 index 000000000000..15f70048469b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8731.txt @@ -0,0 +1,18 @@ +WM8731 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + + - compatible : "wlf,wm8731" + + - reg : the I2C address of the device for I2C, the chip select + number for SPI. + +Example: + +codec: wm8731@1a { + compatible = "wlf,wm8731"; + reg = <0x1a>; +}; diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 76b4361e9b80..f76b6fc6766a 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -607,6 +608,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { .num_dapm_routes = ARRAY_SIZE(wm8731_intercon), }; +static const struct of_device_id wm8731_of_match[] = { + { .compatible = "wlf,wm8731", }, + { } +}; + +MODULE_DEVICE_TABLE(of, wm8731_of_match); + #if defined(CONFIG_SPI_MASTER) static int __devinit wm8731_spi_probe(struct spi_device *spi) { @@ -638,6 +646,7 @@ static struct spi_driver wm8731_spi_driver = { .driver = { .name = "wm8731", .owner = THIS_MODULE, + .of_match_table = wm8731_of_match, }, .probe = wm8731_spi_probe, .remove = __devexit_p(wm8731_spi_remove), @@ -682,6 +691,7 @@ static struct i2c_driver wm8731_i2c_driver = { .driver = { .name = "wm8731", .owner = THIS_MODULE, + .of_match_table = wm8731_of_match, }, .probe = wm8731_i2c_probe, .remove = __devexit_p(wm8731_i2c_remove), -- cgit v1.2.3 From 58e494247a9f09f0ae8d9867fcfb672a9bcdd6ae Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Fri, 22 Jul 2011 00:28:51 +0800 Subject: ASoC: sgtl5000: add device tree probe support It adds device tree probe support for sgtl5000 driver. Signed-off-by: Shawn Guo Acked-by: Grant Likely Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt | 11 +++++++++++ sound/soc/codecs/sgtl5000.c | 8 ++++++++ 2 files changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt diff --git a/Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt b/Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt new file mode 100644 index 000000000000..2c3cd413f042 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/soc/codecs/fsl-sgtl5000.txt @@ -0,0 +1,11 @@ +* Freescale SGTL5000 Stereo Codec + +Required properties: +- compatible : "fsl,sgtl5000". + +Example: + +codec: sgtl5000@0a { + compatible = "fsl,sgtl5000"; + reg = <0x0a>; +}; diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 76258f2a2ffb..cf6eea8b458e 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1494,10 +1495,17 @@ static const struct i2c_device_id sgtl5000_id[] = { MODULE_DEVICE_TABLE(i2c, sgtl5000_id); +static const struct of_device_id sgtl5000_dt_ids[] = { + { .compatible = "fsl,sgtl5000", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, sgtl5000_dt_ids); + static struct i2c_driver sgtl5000_i2c_driver = { .driver = { .name = "sgtl5000", .owner = THIS_MODULE, + .of_match_table = sgtl5000_dt_ids, }, .probe = sgtl5000_i2c_probe, .remove = __devexit_p(sgtl5000_i2c_remove), -- cgit v1.2.3 From 6b71c52e7f848e2c9f804e175215e5965ea90d32 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 28 Jul 2011 15:23:03 +0200 Subject: xen: use static initializers in xen-balloon.c There is no need to use dynamic initializaion, it just confuses the reader. Switch to static initializers like its used in other files. Signed-off-by: Olaf Hering [v2: Rebased on v3.0] Signed-off-by: Konrad Rzeszutek Wilk --- drivers/xen/xen-balloon.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/xen/xen-balloon.c b/drivers/xen/xen-balloon.c index 5c9dc43c1e94..9cc2259c9992 100644 --- a/drivers/xen/xen-balloon.c +++ b/drivers/xen/xen-balloon.c @@ -50,11 +50,6 @@ static struct sys_device balloon_sysdev; static int register_balloon(struct sys_device *sysdev); -static struct xenbus_watch target_watch = -{ - .node = "memory/target" -}; - /* React to a change in the target key */ static void watch_target(struct xenbus_watch *watch, const char **vec, unsigned int len) @@ -73,6 +68,11 @@ static void watch_target(struct xenbus_watch *watch, */ balloon_set_new_target(new_target >> (PAGE_SHIFT - 10)); } +static struct xenbus_watch target_watch = { + .node = "memory/target", + .callback = watch_target, +}; + static int balloon_init_watcher(struct notifier_block *notifier, unsigned long event, @@ -87,7 +87,9 @@ static int balloon_init_watcher(struct notifier_block *notifier, return NOTIFY_DONE; } -static struct notifier_block xenstore_notifier; +static struct notifier_block xenstore_notifier = { + .notifier_call = balloon_init_watcher, +}; static int __init balloon_init(void) { @@ -100,9 +102,6 @@ static int __init balloon_init(void) register_xen_selfballooning(&balloon_sysdev); - target_watch.callback = watch_target; - xenstore_notifier.notifier_call = balloon_init_watcher; - register_xenstore_notifier(&xenstore_notifier); return 0; -- cgit v1.2.3 From f9ada374f07fa8c09c15262ffd26371beacb1e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:18:44 -0300 Subject: [media] gspca-stv06xx: Simplify register writes by avoiding special data structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx.h | 6 ++++- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h | 31 +++++++++++----------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index e0f63c51f40d..d270a5981afe 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -37,6 +37,8 @@ #define STV_ISOC_ENDPOINT_ADDR 0x81 +#define STV_R 0x0509 + #define STV_REG23 0x0423 /* Control registers of the STV0600 ASIC */ @@ -61,7 +63,9 @@ /* Refers to the CIF 352x288 and QCIF 176x144 */ /* 1: 288 lines, 2: 144 lines */ -#define STV_Y_CTRL 0x15c3 +#define STV_Y_CTRL 0x15c3 + +#define STV_RESET 0x1620 /* 0xa: 352 columns, 0x6: 176 columns */ #define STV_X_CTRL 0x1680 diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index 7fe3587f5f71..c7615c218c31 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -216,22 +216,23 @@ struct stv_init { u8 len; }; -static const u8 x1500[] = { /* 0x1500 - 0x150f */ - 0x0b, 0xa7, 0xb7, 0x00, 0x00 -}; - -static const u8 x1536[] = { /* 0x1536 - 0x153b */ - 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 -}; - static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ - {NULL, 0x1620, 0x80}, - {NULL, 0x1620, 0x00}, - {NULL, 0x1443, 0x00}, - {NULL, 0x1423, 0x04}, - {x1500, 0x1500, ARRAY_SIZE(x1500)}, - {x1536, 0x1536, ARRAY_SIZE(x1536)}, + {NULL, STV_RESET, 0x80}, + {NULL, STV_RESET, 0x00}, + {NULL, STV_SCAN_RATE, 0x00}, + {NULL, STV_I2C_FLUSH, 0x04}, + {NULL, STV_REG00, 0x0b}, + {NULL, STV_REG01, 0xa7}, + {NULL, STV_REG02, 0xb7}, + {NULL, STV_REG03, 0x00}, + {NULL, STV_REG04, 0x00}, + {NULL, 0x1536, 0x02}, + {NULL, 0x1537, 0x00}, + {NULL, 0x1538, 0x60}, + {NULL, 0x1539, 0x01}, + {NULL, 0x153a, 0x20}, + {NULL, 0x153b, 0x01}, }; static const u8 vv6410_sensor_init[][2] = { @@ -240,7 +241,7 @@ static const u8 vv6410_sensor_init[][2] = { {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, /* Use shuffled read-out mode */ {VV6410_SETUP1, BIT(6)}, - /* All modes to 1 */ + /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */ {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, {VV6410_PINMAPPING, 0x00}, /* Pre-clock generator divide off */ -- cgit v1.2.3 From 46fecfaf786a35ce6dc024a70ae1e768ee44e803 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:19:58 -0300 Subject: [media] gspca-stv06xx: Simplify stv_init struct and vv6410 bridge init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | 13 +------- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h | 35 +++++++++++----------- 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index f8398434c328..51b66590c7fa 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -138,18 +138,7 @@ static int vv6410_init(struct sd *sd) s32 *sensor_settings = sd->sensor_priv; for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { - /* if NULL then len contains single value */ - if (stv_bridge_init[i].data == NULL) { - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start, - stv_bridge_init[i].len); - } else { - int j; - for (j = 0; j < stv_bridge_init[i].len; j++) - err = stv06xx_write_bridge(sd, - stv_bridge_init[i].start + j, - stv_bridge_init[i].data[j]); - } + stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); } if (err < 0) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index c7615c218c31..f75c3364a376 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -211,28 +211,27 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = { /* If NULL, only single value to write, stored in len */ struct stv_init { - const u8 *data; - u16 start; - u8 len; + u16 addr; + u8 data; }; static const struct stv_init stv_bridge_init[] = { /* This reg is written twice. Some kind of reset? */ - {NULL, STV_RESET, 0x80}, - {NULL, STV_RESET, 0x00}, - {NULL, STV_SCAN_RATE, 0x00}, - {NULL, STV_I2C_FLUSH, 0x04}, - {NULL, STV_REG00, 0x0b}, - {NULL, STV_REG01, 0xa7}, - {NULL, STV_REG02, 0xb7}, - {NULL, STV_REG03, 0x00}, - {NULL, STV_REG04, 0x00}, - {NULL, 0x1536, 0x02}, - {NULL, 0x1537, 0x00}, - {NULL, 0x1538, 0x60}, - {NULL, 0x1539, 0x01}, - {NULL, 0x153a, 0x20}, - {NULL, 0x153b, 0x01}, + {STV_RESET, 0x80}, + {STV_RESET, 0x00}, + {STV_SCAN_RATE, 0x00}, + {STV_I2C_FLUSH, 0x04}, + {STV_REG00, 0x0b}, + {STV_REG01, 0xa7}, + {STV_REG02, 0xb7}, + {STV_REG03, 0x00}, + {STV_REG04, 0x00}, + {0x1536, 0x02}, + {0x1537, 0x00}, + {0x1538, 0x60}, + {0x1539, 0x01}, + {0x153a, 0x20}, + {0x153b, 0x01}, }; static const u8 vv6410_sensor_init[][2] = { -- cgit v1.2.3 From a0917ca4d776db110b129d148fffe3dba97ea9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:20:38 -0300 Subject: [media] gspca-stv06xx: Fix sensor init indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional changes on this patch. Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index f75c3364a376..a25b8873f2e6 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -236,24 +236,24 @@ static const struct stv_init stv_bridge_init[] = { static const u8 vv6410_sensor_init[][2] = { /* Setup registers */ - {VV6410_SETUP0, VV6410_SOFT_RESET}, - {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, + {VV6410_SETUP0, VV6410_SOFT_RESET}, + {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, /* Use shuffled read-out mode */ - {VV6410_SETUP1, BIT(6)}, + {VV6410_SETUP1, BIT(6)}, /* All modes to 1, FST, Fast QCK, Free running QCK, Free running LST, FST will qualify visible pixels */ - {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, - {VV6410_PINMAPPING, 0x00}, + {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, + {VV6410_PINMAPPING, 0x00}, /* Pre-clock generator divide off */ - {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, + {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, - {VV6410_CLKDIV, VV6410_CLK_DIV_2}, + {VV6410_CLKDIV, VV6410_CLK_DIV_2}, /* System registers */ /* Enable voltage doubler */ - {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, - {VV6410_AT0, 0x00}, + {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + {VV6410_AT0, 0x00}, /* Power up audio, differential */ - {VV6410_AT1, BIT(4)|BIT(0)}, + {VV6410_AT1, BIT(4) | BIT(0)}, }; #endif -- cgit v1.2.3 From d6c5441f6204219fce7aefbe3e5ffead3815ef99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:21:14 -0300 Subject: [media] gspca-stv06xx: Remove writes to read-only registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index 51b66590c7fa..308add8bc98f 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -172,15 +172,6 @@ static int vv6410_start(struct sd *sd) struct cam *cam = &sd->gspca_dev.cam; u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; - if (priv & VV6410_CROP_TO_QVGA) { - PDEBUG(D_CONF, "Cropping to QVGA"); - stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); - } else { - stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); - stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); - } - if (priv & VV6410_SUBSAMPLE) { PDEBUG(D_CONF, "Enabling subsampling"); stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); -- cgit v1.2.3 From eaceba650dea4af61f6f3a4919caa096bb4c2929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20Andr=C3=A9n?= Date: Wed, 27 Jul 2011 17:21:49 -0300 Subject: [media] gspca-stv06xx: Triple frame rate by decreasing the scan rate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Erik Andrén Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index 308add8bc98f..b05a15495144 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -181,8 +181,8 @@ static int vv6410_start(struct sd *sd) } else { stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x00); - stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); } /* Turn on LED */ -- cgit v1.2.3 From b05681b91709a19b40a452f566cc852619b30082 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Jul 2011 02:23:20 -0300 Subject: [media] rc-main: Fix device de-registration logic rc unregister logic were deadly broken, preventing some drivers to be removed. Among the broken things, rc_dev_uevent() is being called during device_del(), causing a data filling on an area that it is not ready anymore. Also, some drivers have a stop callback defined, that needs to be called before data removal, as it stops data polling. Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 51a23f48bc7d..666d4bb5b1fb 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -928,10 +928,6 @@ out: static void rc_dev_release(struct device *device) { - struct rc_dev *dev = to_rc_dev(device); - - kfree(dev); - module_put(THIS_MODULE); } #define ADD_HOTPLUG_VAR(fmt, val...) \ @@ -945,6 +941,9 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); + if (!dev || !dev->input_dev) + return -ENODEV; + if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) @@ -1013,10 +1012,16 @@ EXPORT_SYMBOL_GPL(rc_allocate_device); void rc_free_device(struct rc_dev *dev) { - if (dev) { + if (!dev) + return; + + if (dev->input_dev) input_free_device(dev->input_dev); - put_device(&dev->dev); - } + + put_device(&dev->dev); + + kfree(dev); + module_put(THIS_MODULE); } EXPORT_SYMBOL_GPL(rc_free_device); @@ -1143,14 +1148,18 @@ void rc_unregister_device(struct rc_dev *dev) if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); + /* Freeing the table should also call the stop callback */ + ir_free_table(&dev->rc_map); + IR_dprintk(1, "Freed keycode table\n"); + input_unregister_device(dev->input_dev); dev->input_dev = NULL; - ir_free_table(&dev->rc_map); - IR_dprintk(1, "Freed keycode table\n"); + device_del(&dev->dev); - device_unregister(&dev->dev); + rc_free_device(dev); } + EXPORT_SYMBOL_GPL(rc_unregister_device); /* -- cgit v1.2.3 From 6d51477470728074cea396a0127d73c5590dd441 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Jul 2011 02:26:59 -0300 Subject: [media] em28xx: Fix IR unregister logic The input stop() callback already calls the em28xx_ir_stop method. Calling it again causes an oops. Acked-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/em28xx/em28xx-input.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 5d12b14282e3..679da4804281 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -463,11 +463,11 @@ int em28xx_ir_fini(struct em28xx *dev) if (!ir) return 0; - em28xx_ir_stop(ir->rc); - rc_unregister_device(ir->rc); - kfree(ir); + if (ir->rc) + rc_unregister_device(ir->rc); /* done */ + kfree(ir); dev->ir = NULL; return 0; } -- cgit v1.2.3 From bfd4500c9abf3e70e9c563bcba5675bd302f5a4e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 24 Jul 2011 20:29:16 -0300 Subject: [media] dvb-usb: prepare for multi-frontend support (MFE) Change adapter FE pointer as array of FE pointers. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/af9005.c | 2 +- drivers/media/dvb/dvb-usb/af9015.c | 22 +-- drivers/media/dvb/dvb-usb/anysee.c | 46 ++--- drivers/media/dvb/dvb-usb/au6610.c | 6 +- drivers/media/dvb/dvb-usb/az6027.c | 10 +- drivers/media/dvb/dvb-usb/ce6230.c | 6 +- drivers/media/dvb/dvb-usb/cinergyT2-core.c | 2 +- drivers/media/dvb/dvb-usb/cxusb.c | 60 +++---- drivers/media/dvb/dvb-usb/dib0700_devices.c | 262 ++++++++++++++-------------- drivers/media/dvb/dvb-usb/dibusb-common.c | 18 +- drivers/media/dvb/dvb-usb/dibusb-mb.c | 16 +- drivers/media/dvb/dvb-usb/digitv.c | 8 +- drivers/media/dvb/dvb-usb/dtt200u.c | 2 +- drivers/media/dvb/dvb-usb/dtv5100.c | 8 +- drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 18 +- drivers/media/dvb/dvb-usb/dvb-usb.h | 2 +- drivers/media/dvb/dvb-usb/dw2102.c | 92 +++++----- drivers/media/dvb/dvb-usb/ec168.c | 6 +- drivers/media/dvb/dvb-usb/friio.c | 4 +- drivers/media/dvb/dvb-usb/gl861.c | 6 +- drivers/media/dvb/dvb-usb/gp8psk.c | 2 +- drivers/media/dvb/dvb-usb/lmedm04.c | 28 +-- drivers/media/dvb/dvb-usb/m920x.c | 14 +- drivers/media/dvb/dvb-usb/opera1.c | 6 +- drivers/media/dvb/dvb-usb/technisat-usb2.c | 24 +-- drivers/media/dvb/dvb-usb/ttusb2.c | 10 +- drivers/media/dvb/dvb-usb/umt-010.c | 4 +- drivers/media/dvb/dvb-usb/vp702x.c | 2 +- drivers/media/dvb/dvb-usb/vp7045.c | 2 +- 29 files changed, 344 insertions(+), 344 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c index 51f6439dcfd5..753b86eafa25 100644 --- a/drivers/media/dvb/dvb-usb/af9005.c +++ b/drivers/media/dvb/dvb-usb/af9005.c @@ -815,7 +815,7 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap) debug_dump(buf, 8, printk); } } - adap->fe = af9005_fe_attach(adap->dev); + adap->fe[0] = af9005_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c index d7ad05fc383b..f966b0baeaac 100644 --- a/drivers/media/dvb/dvb-usb/af9015.c +++ b/drivers/media/dvb/dvb-usb/af9015.c @@ -1111,10 +1111,10 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) } /* attach demodulator */ - adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], + adap->fe[0] = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id], &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct mt2060_config af9015_mt2060_config = { @@ -1188,49 +1188,49 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap) switch (af9015_af9013_config[adap->id].tuner) { case AF9013_TUNER_MT2060: case AF9013_TUNER_MT2060_2: - ret = dvb_attach(mt2060_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(mt2060_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mt2060_config, af9015_config.mt2060_if1[adap->id]) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_QT1010: case AF9013_TUNER_QT1010A: - ret = dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_qt1010_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18271: - ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, + ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, &af9015_tda18271_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_TDA18218: - ret = dvb_attach(tda18218_attach, adap->fe, + ret = dvb_attach(tda18218_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_tda18218_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5003D: - ret = dvb_attach(mxl5005s_attach, adap->fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5003_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5005D: case AF9013_TUNER_MXL5005R: - ret = dvb_attach(mxl5005s_attach, adap->fe, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mxl5005_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_ENV77H11D5: - ret = dvb_attach(dvb_pll_attach, adap->fe, 0xc0, + ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, DVB_PLL_TDA665X) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MC44S803: - ret = dvb_attach(mc44s803_attach, adap->fe, + ret = dvb_attach(mc44s803_attach, adap->fe[0], &adap->dev->i2c_adap, &af9015_mc44s803_config) == NULL ? -ENODEV : 0; break; case AF9013_TUNER_MXL5007T: - ret = dvb_attach(mxl5007t_attach, adap->fe, + ret = dvb_attach(mxl5007t_attach, adap->fe[0], &adap->dev->i2c_adap, 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0; break; diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 2cbf19a52e38..1ec88b694d29 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -488,13 +488,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach demod */ - adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config, + adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); - if (adap->fe) + if (adap->fe[0]) break; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -512,7 +512,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); break; @@ -525,7 +525,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; @@ -538,7 +538,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config, + adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config, &adap->dev->i2c_adap); break; @@ -580,12 +580,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config2, &adap->dev->i2c_adap); } else { /* PLL config */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, &adap->dev->i2c_adap); } @@ -605,12 +605,12 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } else { /* PLL config */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); } @@ -647,7 +647,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(zl10353_attach, + adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_tda18212_config, &adap->dev->i2c_adap); } else { @@ -670,7 +670,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(tda10023_attach, + adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_tda18212_config, &adap->dev->i2c_adap, 0x48); } @@ -692,13 +692,13 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config, + adap->fe[0] = dvb_attach(stv0900_attach, &anysee_stv0900_config, &adap->dev->i2c_adap, 0); break; } - if (!adap->fe) { + if (!adap->fe[0]) { /* we have no frontend :-( */ ret = -ENODEV; err("Unsupported Anysee version. " \ @@ -720,7 +720,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579); break; @@ -728,7 +728,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579); break; @@ -736,7 +736,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 C Plus */ /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; @@ -744,7 +744,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); break; @@ -775,7 +775,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; @@ -786,7 +786,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1), + fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); break; @@ -801,7 +801,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap, + fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_tda18212_config); break; @@ -811,12 +811,12 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E7 PS2 */ /* attach tuner */ - fe = dvb_attach(stv6110_attach, adap->fe, + fe = dvb_attach(stv6110_attach, adap->fe[0], &anysee_stv6110_config, &adap->dev->i2c_adap); if (fe) { /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe, + fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, &anysee_isl6423_config); } diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c index 2351077ff2b3..ebe6e1ffc319 100644 --- a/drivers/media/dvb/dvb-usb/au6610.c +++ b/drivers/media/dvb/dvb-usb/au6610.c @@ -140,9 +140,9 @@ static struct zl10353_config au6610_zl10353_config = { static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -155,7 +155,7 @@ static struct qt1010_config au6610_qt1010_config = { static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &au6610_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c index 57e2444d51ab..d59430c48158 100644 --- a/drivers/media/dvb/dvb-usb/az6027.c +++ b/drivers/media/dvb/dvb-usb/az6027.c @@ -910,16 +910,16 @@ static int az6027_frontend_attach(struct dvb_usb_adapter *adap) az6027_frontend_reset(adap); deb_info("adap = %p, dev = %p\n", adap, adap->dev); - adap->fe = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); + adap->fe[0] = stb0899_attach(&az6027_stb0899_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { deb_info("found STB0899 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb0899_config.demod_address); - if (stb6100_attach(adap->fe, &az6027_stb6100_config, &adap->dev->i2c_adap)) { + if (stb6100_attach(adap->fe[0], &az6027_stb6100_config, &adap->dev->i2c_adap)) { deb_info("found STB6100 DVB-S/DVB-S2 frontend @0x%02x", az6027_stb6100_config.tuner_address); - adap->fe->ops.set_voltage = az6027_set_voltage; + adap->fe[0]->ops.set_voltage = az6027_set_voltage; az6027_ci_init(adap); } else { - adap->fe = NULL; + adap->fe[0] = NULL; } } else warn("no front-end attached\n"); diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c index 6d1a3041540d..5655ce411d70 100644 --- a/drivers/media/dvb/dvb-usb/ce6230.c +++ b/drivers/media/dvb/dvb-usb/ce6230.c @@ -186,9 +186,9 @@ static struct zl10353_config ce6230_zl10353_config = { static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; } @@ -214,7 +214,7 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { int ret; deb_info("%s:\n", __func__); - ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + ret = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; return ret; } diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c index 16f2ce2bc15a..0dd42bdbe285 100644 --- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c @@ -69,7 +69,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) char state[3]; int ret; - adap->fe = cinergyt2_fe_attach(adap->dev); + adap->fe[0] = cinergyt2_fe_attach(adap->dev); ret = dvb_usb_generic_rw(adap->dev, query, sizeof(query), state, sizeof(state), 0); diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index acb5fb2d2e73..a76f431d6a26 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -725,7 +725,7 @@ static struct max2165_config mygica_d689_max2165_cfg = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; @@ -733,27 +733,27 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201); + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_LG_Z201); return 0; } static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, NULL, DVB_PLL_THOMSON_DTT7579); return 0; } static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); return 0; } @@ -795,9 +795,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) }; /* FIXME: generalize & move to common area */ - adap->fe->callback = dvico_bluebird_xc2028_callback; + adap->fe[0]->callback = dvico_bluebird_xc2028_callback; - fe = dvb_attach(xc2028_attach, adap->fe, &cfg); + fe = dvb_attach(xc2028_attach, adap->fe[0], &cfg); if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) return -EIO; @@ -808,7 +808,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(mxl5005s_attach, adap->fe, + dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &aver_a868r_tuner); return 0; } @@ -816,7 +816,7 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(mxl5005s_attach, adap->fe, + fe = dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &d680_dmb_tuner); return (fe == NULL) ? -EIO : 0; } @@ -824,7 +824,7 @@ static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; - fe = dvb_attach(max2165_attach, adap->fe, + fe = dvb_attach(max2165_attach, adap->fe[0], &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); return (fe == NULL) ? -EIO : 0; } @@ -837,7 +837,7 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); - if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, + if ((adap->fe[0] = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -851,7 +851,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, + if ((adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -860,9 +860,9 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, + adap->fe[0] = dvb_attach(lgdt330x_attach, &cxusb_aver_lgdt3303_config, &adap->dev->i2c_adap); - if (adap->fe != NULL) + if (adap->fe[0] != NULL) return 0; return -EIO; @@ -876,7 +876,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, + if ((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -890,9 +890,9 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); - if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, + if (((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) || - ((adap->fe = dvb_attach(zl10353_attach, + ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL)) return 0; @@ -917,7 +917,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe = dvb_attach(zl10353_attach, + if ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config_no_i2c_gate, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -1031,9 +1031,9 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &cxusb_dualdig4_rev2_config); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -1084,15 +1084,15 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe, + dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -1108,12 +1108,12 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x01, 1); cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if ((adap->fe = dvb_attach(zl10353_attach, + if ((adap->fe[0] = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; - if ((adap->fe = dvb_attach(mt352_attach, + if ((adap->fe[0] = dvb_attach(mt352_attach, &cxusb_mt352_xc3028_config, &adap->dev->i2c_adap)) != NULL) return 0; @@ -1172,8 +1172,8 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -1223,9 +1223,9 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, + adap->fe[0] = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, &d->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c index d0ea5b64f6b4..754f8ec77e05 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -101,7 +101,7 @@ static int bristol_frontend_attach(struct dvb_usb_adapter *adap) } } st->mt2060_if1[adap->id] = 1220; - return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, + return (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0; } @@ -118,14 +118,14 @@ static int eeprom_read(struct i2c_adapter *adap,u8 adrs,u8 *pval) static int bristol_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; - struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); + struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); s8 a; int if1=1220; if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_500_2)) { if (!eeprom_read(prim_i2c,0x59 + adap->id,&a)) if1=1220+a; } - return dvb_attach(mt2060_attach,adap->fe, tun_i2c,&bristol_mt2060_config[adap->id], + return dvb_attach(mt2060_attach,adap->fe[0], tun_i2c,&bristol_mt2060_config[adap->id], if1) == NULL ? -ENODEV : 0; } @@ -279,10 +279,10 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) @@ -306,17 +306,17 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) } } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2266_attach, adap->fe, tun_i2c, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + return dvb_attach(mt2266_attach, adap->fe[0], tun_i2c, &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; } @@ -396,8 +396,8 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, switch (command) { case XC2028_TUNER_RESET: /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 0); msleep(10); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); break; case XC2028_RESET_CLK: break; @@ -447,25 +447,25 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7700ph_dib7700_xc3028_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; /* FIXME: generalize & move to common area */ - adap->fe->callback = stk7700ph_xc3028_callback; + adap->fe[0]->callback = stk7700ph_xc3028_callback; - return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config) + return dvb_attach(xc2028_attach, adap->fe[0], &stk7700ph_xc3028_config) == NULL ? -ENODEV : 0; } @@ -685,12 +685,12 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0] = 1220; if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); st->is_dib7000pc = 1; } else - adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + adap->fe[0] = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct mt2060_config stk7700p_mt2060_config = { @@ -709,11 +709,11 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; } if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); else - tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = dib7000m_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config, + return dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk7700p_mt2060_config, if1) == NULL ? -ENODEV : 0; } @@ -843,33 +843,33 @@ static int dib7770_set_param_override(struct dvb_frontend *fe, static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7770p_dib0070_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7770_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7770_set_param_override; return 0; } static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL) + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib7070p_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7070_set_param_override; return 0; } @@ -878,26 +878,26 @@ static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); - return dib7000m_pid_filter(adapter->fe, index, pid, onoff); + return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); + return dib7000m_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { struct dib0700_state *st = adapter->dev->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); - return dib7000m_pid_filter_ctrl(adapter->fe, onoff); + return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); + return dib7000m_pid_filter_ctrl(adapter->fe[0], onoff); } static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib7000p_pid_filter(adapter->fe, index, pid, onoff); + return dib7000p_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib7000p_pid_filter_ctrl(adapter->fe, onoff); + return dib7000p_pid_filter_ctrl(adapter->fe[0], onoff); } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { @@ -955,9 +955,9 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK7770P */ @@ -1007,9 +1007,9 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7770p_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* DIB807x generic */ @@ -1225,34 +1225,34 @@ static int dib807x_set_param_override(struct dvb_frontend *fe, static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib807x_dib0070_config[0]) == NULL) return -ENODEV; } else { - if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + if (dvb_attach(dib0070_attach, adap->fe[0], tun_i2c, &dib807x_dib0070_config[1]) == NULL) return -ENODEV; } - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib807x_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib807x_set_param_override; return 0; } static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib8000_pid_filter(adapter->fe, index, pid, onoff); + return dib8000_pid_filter(adapter->fe[0], index, pid, onoff); } static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib8000_pid_filter_ctrl(adapter->fe, onoff); + return dib8000_pid_filter_ctrl(adapter->fe[0], onoff); } /* STK807x */ @@ -1276,10 +1276,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK807xPVR */ @@ -1305,10 +1305,10 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) /* initialize IC 0 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) @@ -1316,10 +1316,10 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) /* initialize IC 1 */ dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } /* STK8096GP */ @@ -1546,13 +1546,13 @@ static int dib8096_set_param_override(struct dvb_frontend *fe, static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1575,30 +1575,30 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe, 1); + struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe[0], 1); if (fe_slave) { tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe->dvb; + fe_slave->dvb = adap->fe[0]->dvb; fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; } - tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL) + tun_i2c = dib8000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib8096_set_param_override; return 0; } @@ -1626,12 +1626,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80); - adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + if (adap->fe[0] == NULL) return -ENODEV; fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe, fe_slave); + dib8000_set_slave_frontend(adap->fe[0], fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1639,12 +1639,12 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) /* STK9090M */ static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff); + return dib9000_fw_pid_filter(adapter->fe[0], index, pid, onoff); } static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff); + return dib9000_fw_pid_filter_ctrl(adapter->fe[0], onoff); } static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff) @@ -1856,15 +1856,15 @@ static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap) stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size; stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data; - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); + adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *state = adap->priv; - struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe); + struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe[0]); u16 data_dib190[10] = { 1, 0x1374, 2, 0x01a2, @@ -1873,13 +1873,13 @@ static int dib9090_tuner_attach(struct dvb_usb_adapter *adap) 8, 0x0486, }; - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL) + if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &dib9090_dib0090_config) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) + if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) return -ENODEV; release_firmware(state->frontend_firmware); return 0; @@ -1925,16 +1925,16 @@ static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap) nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data; dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80); - adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); + adap->fe[0] = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_3_4, 0); dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82); fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]); - dib9000_set_slave_frontend(adap->fe, fe_slave); + dib9000_set_slave_frontend(adap->fe[0], fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1951,26 +1951,26 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) 0, 0x00ef, 8, 0x0406, }; - i2c = dib9000_get_tuner_interface(adap->fe); - if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL) + i2c = dib9000_get_tuner_interface(adap->fe[0]); + if (dvb_attach(dib0090_fw_register, adap->fe[0], i2c, &nim9090md_dib0090_config[0]) == NULL) return -ENODEV; - i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0); + i2c = dib9000_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_GPIO_1_2, 0); if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0) return -ENODEV; dib0700_set_i2c_speed(adap->dev, 2000); - if (dib9000_firmware_post_pll_init(adap->fe) < 0) + if (dib9000_firmware_post_pll_init(adap->fe[0]) < 0) return -ENODEV; - fe_slave = dib9000_get_slave_frontend(adap->fe, 1); + fe_slave = dib9000_get_slave_frontend(adap->fe[0], 1); if (fe_slave != NULL) { - i2c = dib9000_get_component_bus_interface(adap->fe); + i2c = dib9000_get_component_bus_interface(adap->fe[0]); dib9000_set_i2c_adapter(fe_slave, i2c); i2c = dib9000_get_tuner_interface(fe_slave); if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL) return -ENODEV; - fe_slave->dvb = adap->fe->dvb; - dib9000_fw_set_component_bus_speed(adap->fe, 2000); + fe_slave->dvb = adap->fe[0]->dvb; + dib9000_fw_set_component_bus_speed(adap->fe[0], 2000); if (dib9000_firmware_post_pll_init(fe_slave) < 0) return -ENODEV; } @@ -2393,23 +2393,23 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &nim7090_dib0090_config) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2439,11 +2439,11 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) } dib0700_set_i2c_speed(adap->dev, 340); - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); - if (adap->fe == NULL) + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + if (adap->fe[0] == NULL) return -ENODEV; - dib7090_slave_reset(adap->fe); + dib7090_slave_reset(adap->fe[0]); return 0; } @@ -2452,50 +2452,50 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *i2c; - if (adap->dev->adapter[0].fe == NULL) { + if (adap->dev->adapter[0].fe[0] == NULL) { err("the master dib7090 has to be initialized first"); return -ENODEV; /* the master device has not been initialized */ } - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe[0], DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + adap->fe[0] = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); dib0700_set_i2c_speed(adap->dev, 200); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe); + struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe[0]); - if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) + if (dvb_attach(dib0090_register, adap->fe[0], tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); - st->set_param_save = adap->fe->ops.tuner_ops.set_params; - adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup; + st->set_param_save = adap->fe[0]->ops.tuner_ops.set_params; + adap->fe[0]->ops.tuner_ops.set_params = dib7090_agc_startup; return 0; } @@ -2555,14 +2555,14 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); - return adap->fe == NULL ? -ENODEV : 0; + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + return adap->fe[0] == NULL ? -ENODEV : 0; } static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); - return adap->fe == NULL ? -ENODEV : 0; + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + return adap->fe[0] == NULL ? -ENODEV : 0; } /* S5H1411 */ @@ -2617,9 +2617,9 @@ static int s5h1411_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO2, GPIO_OUT, 1); /* GPIOs are initialized, do the attach */ - adap->fe = dvb_attach(s5h1411_attach, &pinnacle_801e_config, + adap->fe[0] = dvb_attach(s5h1411_attach, &pinnacle_801e_config, &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int dib0700_xc5000_tuner_callback(void *priv, int component, @@ -2649,9 +2649,9 @@ static struct xc5000_config s5h1411_xc5000_tunerconfig = { static int xc5000_tuner_attach(struct dvb_usb_adapter *adap) { /* FIXME: generalize & move to common area */ - adap->fe->callback = dib0700_xc5000_tuner_callback; + adap->fe[0]->callback = dib0700_xc5000_tuner_callback; - return dvb_attach(xc5000_attach, adap->fe, &adap->dev->i2c_adap, + return dvb_attach(xc5000_attach, adap->fe[0], &adap->dev->i2c_adap, &s5h1411_xc5000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2663,9 +2663,9 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component, if (command == XC4000_TUNER_RESET) { /* Reset the tuner */ - dib7000p_set_gpio(adap->fe, 8, 0, 0); + dib7000p_set_gpio(adap->fe[0], 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe, 8, 0, 1); + dib7000p_set_gpio(adap->fe[0], 8, 0, 1); } else { err("xc4000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -2771,11 +2771,11 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; } - adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + adap->fe[0] = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, &pctv_340e_config); st->is_dib7000pc = 1; - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static struct xc4000_config dib7000p_xc4000_tunerconfig = { @@ -2791,7 +2791,7 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *tun_i2c; /* The xc4000 is not on the main i2c bus */ - tun_i2c = dib7000p_get_i2c_master(adap->fe, + tun_i2c = dib7000p_get_i2c_master(adap->fe[0], DIBX000_I2C_INTERFACE_TUNER, 1); if (tun_i2c == NULL) { printk(KERN_ERR "Could not reach tuner i2c bus\n"); @@ -2799,9 +2799,9 @@ static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) } /* Setup the reset callback */ - adap->fe->callback = dib0700_xc4000_tuner_callback; + adap->fe[0]->callback = dib0700_xc4000_tuner_callback; - return dvb_attach(xc4000_attach, adap->fe, tun_i2c, + return dvb_attach(xc4000_attach, adap->fe[0], tun_i2c, &dib7000p_xc4000_tunerconfig) == NULL ? -ENODEV : 0; } @@ -2857,16 +2857,16 @@ static int lgdt3305_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(30); - adap->fe = dvb_attach(lgdt3305_attach, + adap->fe[0] = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, &adap->dev->i2c_adap); - return adap->fe == NULL ? -ENODEV : 0; + return adap->fe[0] == NULL ? -ENODEV : 0; } static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap) { - return dvb_attach(mxl5007t_attach, adap->fe, + return dvb_attach(mxl5007t_attach, adap->fe[0], &adap->dev->i2c_adap, 0x60, &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 4c2a689c820e..263235e194f9 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -23,7 +23,7 @@ int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.fifo_ctrl != NULL) - if (st->ops.fifo_ctrl(adap->fe,onoff)) { + if (st->ops.fifo_ctrl(adap->fe[0],onoff)) { err("error while controlling the fifo of the demod."); return -ENODEV; } @@ -37,7 +37,7 @@ int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onof if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_ctrl != NULL) - st->ops.pid_ctrl(adap->fe,index,pid,onoff); + st->ops.pid_ctrl(adap->fe[0],index,pid,onoff); } return 0; } @@ -48,7 +48,7 @@ int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; if (st->ops.pid_parse != NULL) - if (st->ops.pid_parse(adap->fe,onoff) < 0) + if (st->ops.pid_parse(adap->fe[0],onoff) < 0) err("could not handle pid_parser"); } return 0; @@ -254,8 +254,8 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap) msleep(1000); } - if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || - (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { + if ((adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL || + (adap->fe[0] = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) { if (adap->priv != NULL) { struct dibusb_state *st = adap->priv; st->ops.pid_parse = dib3000mc_pid_parse; @@ -309,15 +309,15 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap) } } - tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1); - if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { + tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe[0], 1); + if (dvb_attach(mt2060_attach, adap->fe[0], tun_i2c, &stk3000p_mt2060_config, if1) == NULL) { /* not found - use panasonic pll parameters */ - if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) + if (dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL) return -ENOMEM; } else { st->mt2060_present = 1; /* set the correct parameters for the dib3000p */ - dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config); + dib3000mc_set_config(adap->fe[0], &stk3000p_dib3000p_config); } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index 04d91bdd3562..c653b321e428 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -31,11 +31,11 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap) demod_cfg.demod_address = 0x8; - if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg, + if ((adap->fe[0] = dvb_attach(dib3000mb_attach, &demod_cfg, &adap->dev->i2c_adap, &st->ops)) == NULL) return -ENODEV; - adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; + adap->fe[0]->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl; return 0; } @@ -46,7 +46,7 @@ static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x61; - dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, DVB_PLL_TUA6010XS); return 0; } @@ -57,7 +57,7 @@ static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap) st->tuner_addr = 0x60; - dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_TDA665X); return 0; } @@ -78,16 +78,16 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap) /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60; - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,1); + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],1); if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) { err("tuner i2c write failed."); ret = -EREMOTEIO; } - if (adap->fe->ops.i2c_gate_ctrl) - adap->fe->ops.i2c_gate_ctrl(adap->fe,0); + if (adap->fe[0]->ops.i2c_gate_ctrl) + adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0],0); if (b2[0] == 0xfe) { info("This device has the Thomson Cable onboard. Which is default."); diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index f6344cdd360f..1e17d15bd3e9 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -137,11 +137,11 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe[0] = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 0; return 0; } - if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { + if ((adap->fe[0] = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) { st->is_nxt6000 = 1; return 0; } @@ -152,11 +152,11 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap) { struct digitv_state *st = adap->dev->priv; - if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4)) + if (!dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, NULL, DVB_PLL_TDED4)) return -ENODEV; if (st->is_nxt6000) - adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + adap->fe[0]->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; return 0; } diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c index ecd86eca2548..ea2a46ffbb0a 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u.c +++ b/drivers/media/dvb/dvb-usb/dtt200u.c @@ -90,7 +90,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dtt200u_fe_attach(adap->dev); + adap->fe[0] = dtt200u_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/dtv5100.c b/drivers/media/dvb/dvb-usb/dtv5100.c index 078ce92ca436..75ed55cdd8a0 100644 --- a/drivers/media/dvb/dvb-usb/dtv5100.c +++ b/drivers/media/dvb/dvb-usb/dtv5100.c @@ -115,13 +115,13 @@ static struct zl10353_config dtv5100_zl10353_config = { static int dtv5100_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &dtv5100_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; /* disable i2c gate, or it won't work... is this safe? */ - adap->fe->ops.i2c_gate_ctrl = NULL; + adap->fe[0]->ops.i2c_gate_ctrl = NULL; return 0; } @@ -133,7 +133,7 @@ static struct qt1010_config dtv5100_qt1010_config = { static int dtv5100_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &dtv5100_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index b3cb626ed56e..d8c0bd9107f3 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -186,14 +186,14 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) } /* re-assign sleep and wakeup functions */ - if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) { - adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep; + if (adap->props.frontend_attach(adap) == 0 && adap->fe[0] != NULL) { + adap->fe_init = adap->fe[0]->ops.init; adap->fe[0]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = dvb_usb_fe_sleep; - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { err("Frontend registration failed."); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; return -ENODEV; } @@ -208,9 +208,9 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); + if (adap->fe[0] != NULL) { + dvb_unregister_frontend(adap->fe[0]); + dvb_frontend_detach(adap->fe[0]); } return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 7d35d078342b..2e57bffad3e3 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -363,7 +363,7 @@ struct dvb_usb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe; + struct dvb_frontend *fe[1]; int max_feed_count; int (*fe_init) (struct dvb_frontend *); diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c index 058b2318abed..eb5dff59251d 100644 --- a/drivers/media/dvb/dvb-usb/dw2102.c +++ b/drivers/media/dvb/dvb-usb/dw2102.c @@ -992,18 +992,18 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) struct dvb_tuner_ops *tuner_ops = NULL; if (demod_probe & 4) { - d->fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &dw2104a_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stb6100_attach, d->fe, + if (d->fe[0] != NULL) { + if (dvb_attach(stb6100_attach, d->fe[0], &dw2104a_stb6100_config, &d->dev->i2c_adap)) { - tuner_ops = &d->fe->ops.tuner_ops; + tuner_ops = &d->fe[0]->ops.tuner_ops; tuner_ops->set_frequency = stb6100_set_freq; tuner_ops->get_frequency = stb6100_get_freq; tuner_ops->set_bandwidth = stb6100_set_bandw; tuner_ops->get_bandwidth = stb6100_get_bandw; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STB6100!\n"); return 0; } @@ -1011,13 +1011,13 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 2) { - d->fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &dw2104_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe != NULL) { - if (dvb_attach(stv6110_attach, d->fe, + if (d->fe[0] != NULL) { + if (dvb_attach(stv6110_attach, d->fe[0], &dw2104_stv6110_config, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached STV0900+STV6110A!\n"); return 0; } @@ -1025,19 +1025,19 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d) } if (demod_probe & 1) { - d->fe = dvb_attach(cx24116_attach, &dw2104_config, + d->fe[0] = dvb_attach(cx24116_attach, &dw2104_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached cx24116!\n"); return 0; } } - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached DS3000!\n"); return 0; } @@ -1053,22 +1053,22 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) { if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = NULL;*/ - d->fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, + d->fe[0] = dvb_attach(si21xx_attach, &serit_sp1511lhb_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached si21xx!\n"); return 0; } } if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) { - d->fe = dvb_attach(stv0288_attach, &earda_config, + d->fe[0] = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(stb6000_attach, d->fe, 0x61, + if (d->fe[0] != NULL) { + if (dvb_attach(stb6000_attach, d->fe[0], 0x61, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached stv0288!\n"); return 0; } @@ -1077,10 +1077,10 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) { /*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/ - d->fe = dvb_attach(stv0299_attach, &sharp_z0194a_config, + d->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194a_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - d->fe->ops.set_voltage = dw210x_set_voltage; + if (d->fe[0] != NULL) { + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached stv0299!\n"); return 0; } @@ -1090,9 +1090,9 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d) static int dw3101_frontend_attach(struct dvb_usb_adapter *d) { - d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config, + d->fe[0] = dvb_attach(tda10023_attach, &dw3101_tda10023_config, &d->dev->i2c_adap, 0x48); - if (d->fe != NULL) { + if (d->fe[0] != NULL) { info("Attached tda10023!\n"); return 0; } @@ -1101,12 +1101,12 @@ static int dw3101_frontend_attach(struct dvb_usb_adapter *d) static int zl100313_frontend_attach(struct dvb_usb_adapter *d) { - d->fe = dvb_attach(mt312_attach, &zl313_config, + d->fe[0] = dvb_attach(mt312_attach, &zl313_config, &d->dev->i2c_adap); - if (d->fe != NULL) { - if (dvb_attach(zl10039_attach, d->fe, 0x60, + if (d->fe[0] != NULL) { + if (dvb_attach(zl10039_attach, d->fe[0], 0x60, &d->dev->i2c_adap)) { - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; info("Attached zl100313+zl10039!\n"); return 0; } @@ -1119,16 +1119,16 @@ static int stv0288_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe = dvb_attach(stv0288_attach, &earda_config, + d->fe[0] = dvb_attach(stv0288_attach, &earda_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - if (NULL == dvb_attach(stb6000_attach, d->fe, 0x61, &d->dev->i2c_adap)) + if (NULL == dvb_attach(stb6000_attach, d->fe[0], 0x61, &d->dev->i2c_adap)) return -EIO; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1143,14 +1143,14 @@ static int ds3000_frontend_attach(struct dvb_usb_adapter *d) struct s6x0_state *st = (struct s6x0_state *)d->dev->priv; u8 obuf[] = {7, 1}; - d->fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &dw2104_ds3000_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - st->old_set_voltage = d->fe->ops.set_voltage; - d->fe->ops.set_voltage = s660_set_voltage; + st->old_set_voltage = d->fe[0]->ops.set_voltage; + d->fe[0]->ops.set_voltage = s660_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1163,12 +1163,12 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d) { u8 obuf[] = {7, 1}; - d->fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, + d->fe[0] = dvb_attach(stv0900_attach, &prof_7500_stv0900_config, &d->dev->i2c_adap, 0); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; - d->fe->ops.set_voltage = dw210x_set_voltage; + d->fe[0]->ops.set_voltage = dw210x_set_voltage; dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG); @@ -1204,9 +1204,9 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0) err("command 0x51 transfer failed."); - d->fe = dvb_attach(ds3000_attach, &su3000_ds3000_config, + d->fe[0] = dvb_attach(ds3000_attach, &su3000_ds3000_config, &d->dev->i2c_adap); - if (d->fe == NULL) + if (d->fe[0] == NULL) return -EIO; info("Attached DS3000!\n"); @@ -1216,14 +1216,14 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d) static int dw2102_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_OPERA1); return 0; } static int dw3101_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x60, + dvb_attach(dvb_pll_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, DVB_PLL_TUA6034); return 0; diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c index 1ba3e5dbee10..581bdfc0b1ff 100644 --- a/drivers/media/dvb/dvb-usb/ec168.c +++ b/drivers/media/dvb/dvb-usb/ec168.c @@ -200,9 +200,9 @@ static struct ec100_config ec168_ec100_config = { static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - adap->fe = dvb_attach(ec100_attach, &ec168_ec100_config, + adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -ENODEV; return 0; @@ -228,7 +228,7 @@ static struct mxl5005s_config ec168_mxl5003s_config = { static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) { deb_info("%s:\n", __func__); - return dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap, + return dvb_attach(mxl5005s_attach, adap->fe[0], &adap->dev->i2c_adap, &ec168_mxl5003s_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c index 76159aed9bb0..0e4b559720ea 100644 --- a/drivers/media/dvb/dvb-usb/friio.c +++ b/drivers/media/dvb/dvb-usb/friio.c @@ -403,8 +403,8 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap) if (friio_initialize(adap->dev) < 0) return -EIO; - adap->fe = jdvbt90502_attach(adap->dev); - if (adap->fe == NULL) + adap->fe[0] = jdvbt90502_attach(adap->dev); + if (adap->fe[0] == NULL) return -EIO; return 0; diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c index 6f596ed41761..fba24ed2e843 100644 --- a/drivers/media/dvb/dvb-usb/gl861.c +++ b/drivers/media/dvb/dvb-usb/gl861.c @@ -103,9 +103,9 @@ static struct zl10353_config gl861_zl10353_config = { static int gl861_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config, + adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config, &adap->dev->i2c_adap); - if (adap->fe == NULL) + if (adap->fe[0] == NULL) return -EIO; return 0; @@ -118,7 +118,7 @@ static struct qt1010_config gl861_qt1010_config = { static int gl861_tuner_attach(struct dvb_usb_adapter *adap) { return dvb_attach(qt1010_attach, - adap->fe, &adap->dev->i2c_adap, + adap->fe[0], &adap->dev->i2c_adap, &gl861_qt1010_config) == NULL ? -ENODEV : 0; } diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c index 1cb3d9a66e02..f254e13c35be 100644 --- a/drivers/media/dvb/dvb-usb/gp8psk.c +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -230,7 +230,7 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) { - adap->fe = gp8psk_fe_attach(adap->dev); + adap->fe[0] = gp8psk_fe_attach(adap->dev); return 0; } diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index 37b146961ae2..ef5911a2d342 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c @@ -941,7 +941,7 @@ static int lme_name(struct dvb_usb_adapter *adap) const char *desc = adap->dev->desc->name; char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395", " SHARP:BS2F7HZ0194"}; - char *name = adap->fe->ops.info.name; + char *name = adap->fe[0]->ops.info.name; strlcpy(name, desc, 128); strlcat(name, fe_name[st->tuner_config], 128); @@ -958,10 +958,10 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) st->i2c_talk_onoff = 1; st->i2c_gate = 4; - adap->fe = dvb_attach(tda10086_attach, &tda10086_config, + adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("TUN Found Frontend TDA10086"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 4; @@ -975,9 +975,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 4; - adap->fe = dvb_attach(stv0299_attach, &sharp_z0194_config, + adap->fe[0] = dvb_attach(stv0299_attach, &sharp_z0194_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("FE Found Stv0299"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -991,9 +991,9 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) } st->i2c_gate = 5; - adap->fe = dvb_attach(stv0288_attach, &lme_config, + adap->fe[0] = dvb_attach(stv0288_attach, &lme_config, &adap->dev->i2c_adap); - if (adap->fe) { + if (adap->fe[0]) { info("FE Found Stv0288"); st->i2c_tuner_gate_w = 4; st->i2c_tuner_gate_r = 5; @@ -1010,15 +1010,15 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) end: if (ret) { - if (adap->fe) { - dvb_frontend_detach(adap->fe); - adap->fe = NULL; + if (adap->fe[0]) { + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; } adap->dev->props.rc.core.rc_codes = NULL; return -ENODEV; } - adap->fe->ops.set_voltage = dm04_lme2510_set_voltage; + adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage; ret = lme_name(adap); return ret; } @@ -1031,17 +1031,17 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) switch (st->tuner_config) { case TUNER_LG: - if (dvb_attach(tda826x_attach, adap->fe, 0xc0, + if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0, &adap->dev->i2c_adap, 1)) ret = st->tuner_config; break; case TUNER_S7395: - if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner, + if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner, &adap->dev->i2c_adap)) ret = st->tuner_config; break; case TUNER_S0194: - if (dvb_attach(dvb_pll_attach , adap->fe, 0xc0, + if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0, &adap->dev->i2c_adap, DVB_PLL_OPERA1)) ret = st->tuner_config; break; diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c index 9456792f219b..ed5c161c1c4b 100644 --- a/drivers/media/dvb/dvb-usb/m920x.c +++ b/drivers/media/dvb/dvb-usb/m920x.c @@ -501,7 +501,7 @@ static int m920x_mt352_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(mt352_attach, + if ((adap->fe[0] = dvb_attach(mt352_attach, &m920x_mt352_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -513,7 +513,7 @@ static int m920x_tda10046_08_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(tda10046_attach, + if ((adap->fe[0] = dvb_attach(tda10046_attach, &m920x_tda10046_08_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -525,7 +525,7 @@ static int m920x_tda10046_0b_frontend_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if ((adap->fe = dvb_attach(tda10046_attach, + if ((adap->fe[0] = dvb_attach(tda10046_attach, &m920x_tda10046_0b_config, &adap->dev->i2c_adap)) == NULL) return -EIO; @@ -537,7 +537,7 @@ static int m920x_qt1010_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) + if (dvb_attach(qt1010_attach, adap->fe[0], &adap->dev->i2c_adap, &m920x_qt1010_config) == NULL) return -ENODEV; return 0; @@ -547,7 +547,7 @@ static int m920x_tda8275_60_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -557,7 +557,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) { deb("%s\n",__func__); - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) + if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) return -ENODEV; return 0; @@ -565,7 +565,7 @@ static int m920x_tda8275_61_tuner_attach(struct dvb_usb_adapter *adap) static int m920x_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->dev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); return 0; diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c index 2e4fab7215f5..170b1ef16fac 100644 --- a/drivers/media/dvb/dvb-usb/opera1.c +++ b/drivers/media/dvb/dvb-usb/opera1.c @@ -263,10 +263,10 @@ static struct stv0299_config opera1_stv0299_config = { static int opera1_frontend_attach(struct dvb_usb_adapter *d) { - if ((d->fe = + if ((d->fe[0] = dvb_attach(stv0299_attach, &opera1_stv0299_config, &d->dev->i2c_adap)) != NULL) { - d->fe->ops.set_voltage = opera1_set_voltage; + d->fe[0]->ops.set_voltage = opera1_set_voltage; return 0; } info("not attached stv0299"); @@ -276,7 +276,7 @@ static int opera1_frontend_attach(struct dvb_usb_adapter *d) static int opera1_tuner_attach(struct dvb_usb_adapter *adap) { dvb_attach( - dvb_pll_attach, adap->fe, 0xc0>>1, + dvb_pll_attach, adap->fe[0], 0xc0>>1, &adap->dev->i2c_adap, DVB_PLL_OPERA1 ); return 0; diff --git a/drivers/media/dvb/dvb-usb/technisat-usb2.c b/drivers/media/dvb/dvb-usb/technisat-usb2.c index 473b95ed4d52..2a89d1ef89a3 100644 --- a/drivers/media/dvb/dvb-usb/technisat-usb2.c +++ b/drivers/media/dvb/dvb-usb/technisat-usb2.c @@ -292,7 +292,7 @@ static void technisat_usb2_green_led_control(struct work_struct *work) { struct technisat_usb2_state *state = container_of(work, struct technisat_usb2_state, green_led_work.work); - struct dvb_frontend *fe = state->dev->adapter[0].fe; + struct dvb_frontend *fe = state->dev->adapter[0].fe[0]; if (state->power_state == 0) goto schedule; @@ -505,14 +505,14 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) struct usb_device *udev = a->dev->udev; int ret; - a->fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, + a->fe[0] = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config, &a->dev->i2c_adap, STV090x_DEMODULATOR_0); - if (a->fe) { + if (a->fe[0]) { struct stv6110x_devctl *ctl; ctl = dvb_attach(stv6110x_attach, - a->fe, + a->fe[0], &technisat_usb2_stv6110x_config, &a->dev->i2c_adap); @@ -532,8 +532,8 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) /* call the init function once to initialize tuner's clock output divider and demod's master clock */ - if (a->fe->ops.init) - a->fe->ops.init(a->fe); + if (a->fe[0]->ops.init) + a->fe[0]->ops.init(a->fe[0]); if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0) return -EAGAIN; @@ -548,20 +548,20 @@ static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a) if (ret != 0) err("could not set IF_CLK to external"); - a->fe->ops.set_voltage = technisat_usb2_set_voltage; + a->fe[0]->ops.set_voltage = technisat_usb2_set_voltage; /* if everything was successful assign a nice name to the frontend */ - strlcpy(a->fe->ops.info.name, a->dev->desc->name, - sizeof(a->fe->ops.info.name)); + strlcpy(a->fe[0]->ops.info.name, a->dev->desc->name, + sizeof(a->fe[0]->ops.info.name)); } else { - dvb_frontend_detach(a->fe); - a->fe = NULL; + dvb_frontend_detach(a->fe[0]); + a->fe[0] = NULL; } } technisat_usb2_set_led_timer(a->dev, 1, 1); - return a->fe == NULL ? -ENODEV : 0; + return a->fe[0] == NULL ? -ENODEV : 0; } /* Remote control */ diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 0d4709ff9cbb..c0f5ef56f5e9 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -195,7 +195,7 @@ static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap) if (usb_set_interface(adap->dev->udev,0,3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { + if ((adap->fe[0] = dvb_attach(tda10086_attach, &tda10086_config, &adap->dev->i2c_adap)) == NULL) { deb_info("TDA10086 attach failed\n"); return -ENODEV; } @@ -207,7 +207,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 3) < 0) err("set interface to alts=3 failed"); - if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { + if ((adap->fe[0] = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) { deb_info("TDA10023 attach failed\n"); return -ENODEV; } @@ -216,7 +216,7 @@ static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap) static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) { + if (dvb_attach(tda827x_attach, adap->fe[0], 0x61, &adap->dev->i2c_adap, NULL) == NULL) { printk(KERN_ERR "%s: No tda827x found!\n", __func__); return -ENODEV; } @@ -225,12 +225,12 @@ static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap) static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap) { - if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) { + if (dvb_attach(tda826x_attach, adap->fe[0], 0x60, &adap->dev->i2c_adap, 0) == NULL) { deb_info("TDA8263 attach failed\n"); return -ENODEV; } - if (dvb_attach(lnbp21_attach, adap->fe, &adap->dev->i2c_adap, 0, 0) == NULL) { + if (dvb_attach(lnbp21_attach, adap->fe[0], &adap->dev->i2c_adap, 0, 0) == NULL) { deb_info("LNBP21 attach failed\n"); return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 118aab1a3e54..ed4765a1f323 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -60,14 +60,14 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap) umt_config.demod_init = umt_mt352_demod_init; umt_config.demod_address = 0xf; - adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap); return 0; } static int umt_tuner_attach (struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034); + dvb_attach(dvb_pll_attach, adap->fe[0], 0x61, NULL, DVB_PLL_TUA6034); return 0; } diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c index 54355f84a98f..47b3462cead8 100644 --- a/drivers/media/dvb/dvb-usb/vp702x.c +++ b/drivers/media/dvb/dvb-usb/vp702x.c @@ -320,7 +320,7 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) vp702x_init_pid_filter(adap); - adap->fe = vp702x_fe_attach(adap->dev); + adap->fe[0] = vp702x_fe_attach(adap->dev); vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0); return 0; diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c index 3db89e3cb0bb..4264523fcf67 100644 --- a/drivers/media/dvb/dvb-usb/vp7045.c +++ b/drivers/media/dvb/dvb-usb/vp7045.c @@ -214,7 +214,7 @@ static int vp7045_frontend_attach(struct dvb_usb_adapter *adap) /* Dump the EEPROM */ /* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */ - adap->fe = vp7045_fe_attach(adap->dev); + adap->fe[0] = vp7045_fe_attach(adap->dev); return 0; } -- cgit v1.2.3 From 9bd9e3bd2c57530dfe3057dd0aa9bdb37824925d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 25 Jul 2011 20:16:13 -0300 Subject: [media] dvb-usb: multi-frontend support (MFE) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dvb-usb-dvb.c | 85 +++++++++++++++++++++++++------- drivers/media/dvb/dvb-usb/dvb-usb-init.c | 4 ++ drivers/media/dvb/dvb-usb/dvb-usb.h | 11 +++-- 3 files changed, 78 insertions(+), 22 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index d8c0bd9107f3..5e34df70ad6e 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -162,8 +162,11 @@ static int dvb_usb_fe_wakeup(struct dvb_frontend *fe) dvb_usb_device_power_ctrl(adap->dev, 1); - if (adap->fe_init) - adap->fe_init(fe); + if (adap->props.frontend_ctrl) + adap->props.frontend_ctrl(fe, 1); + + if (adap->fe_init[fe->id]) + adap->fe_init[fe->id](fe); return 0; } @@ -172,45 +175,89 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) { struct dvb_usb_adapter *adap = fe->dvb->priv; - if (adap->fe_sleep) - adap->fe_sleep(fe); + if (adap->fe_sleep[fe->id]) + adap->fe_sleep[fe->id](fe); + + if (adap->props.frontend_ctrl) + adap->props.frontend_ctrl(fe, 0); return dvb_usb_device_power_ctrl(adap->dev, 0); } int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) { + int ret, i, x; + + memset(adap->fe, 0, sizeof(adap->fe)); + if (adap->props.frontend_attach == NULL) { - err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id); + err("strange: '%s' #%d doesn't want to attach a frontend.", + adap->dev->desc->name, adap->id); + return 0; } - /* re-assign sleep and wakeup functions */ - if (adap->props.frontend_attach(adap) == 0 && adap->fe[0] != NULL) { - adap->fe_init = adap->fe[0]->ops.init; adap->fe[0]->ops.init = dvb_usb_fe_wakeup; - adap->fe_sleep = adap->fe[0]->ops.sleep; adap->fe[0]->ops.sleep = dvb_usb_fe_sleep; + /* register all given adapter frontends */ + if (adap->props.num_frontends) + x = adap->props.num_frontends - 1; + else + x = 0; + + for (i = 0; i <= x; i++) { + ret = adap->props.frontend_attach(adap); + if (ret || adap->fe[i] == NULL) { + /* only print error when there is no FE at all */ + if (i == 0) + err("no frontend was attached by '%s'", + adap->dev->desc->name); + + return 0; + } - if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { - err("Frontend registration failed."); - dvb_frontend_detach(adap->fe[0]); - adap->fe[0] = NULL; - return -ENODEV; + adap->fe[i]->id = i; + + /* re-assign sleep and wakeup functions */ + adap->fe_init[i] = adap->fe[i]->ops.init; + adap->fe[i]->ops.init = dvb_usb_fe_wakeup; + adap->fe_sleep[i] = adap->fe[i]->ops.sleep; + adap->fe[i]->ops.sleep = dvb_usb_fe_sleep; + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[i])) { + err("Frontend %d registration failed.", i); + dvb_frontend_detach(adap->fe[i]); + adap->fe[i] = NULL; + /* In error case, do not try register more FEs, + * still leaving already registered FEs alive. */ + if (i == 0) + return -ENODEV; + else + return 0; } /* only attach the tuner if the demod is there */ if (adap->props.tuner_attach != NULL) adap->props.tuner_attach(adap); - } else - err("no frontend was attached by '%s'",adap->dev->desc->name); + } return 0; } int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap) { - if (adap->fe[0] != NULL) { - dvb_unregister_frontend(adap->fe[0]); - dvb_frontend_detach(adap->fe[0]); + int i; + + /* unregister all given adapter frontends */ + if (adap->props.num_frontends) + i = adap->props.num_frontends - 1; + else + i = 0; + + for (; i >= 0; i--) { + if (adap->fe[i] != NULL) { + dvb_unregister_frontend(adap->fe[i]); + dvb_frontend_detach(adap->fe[i]); + } } + return 0; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c index 2e3ea0fa28e0..f9af3484834f 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c @@ -77,6 +77,10 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) return ret; } + /* use exclusive FE lock if there is multiple shared FEs */ + if (adap->fe[1]) + adap->dvb_adap.mfe_shared = 1; + d->num_adapters_initialized++; d->state |= DVB_USB_STATE_DVB; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index 2e57bffad3e3..a3e77b2e2261 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -124,6 +124,8 @@ struct usb_data_stream_properties { * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware * PID-filter. + * @num_frontends: number of frontends of the DVB USB adapter. + * @frontend_ctrl: called to power on/off active frontend. * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the * device (not URB submitting/killing). * @pid_filter_ctrl: called to en/disable the PID filter, if any. @@ -141,7 +143,9 @@ struct dvb_usb_adapter_properties { #define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08 int caps; int pid_filter_count; + int num_frontends; + int (*frontend_ctrl) (struct dvb_frontend *, int); int (*streaming_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int); int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int); @@ -345,6 +349,7 @@ struct usb_data_stream { * * @stream: the usb data stream. */ +#define MAX_NO_OF_FE_PER_ADAP 2 struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; @@ -363,11 +368,11 @@ struct dvb_usb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe[1]; + struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; int max_feed_count; - int (*fe_init) (struct dvb_frontend *); - int (*fe_sleep) (struct dvb_frontend *); + int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); + int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); struct usb_data_stream stream; -- cgit v1.2.3 From 449d1a0ad1732476d394fb2b885092a5c554f983 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 25 Jul 2011 20:25:21 -0300 Subject: [media] anysee: use multi-frontend (MFE) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/anysee.c | 299 +++++++++++++++++++++++++------------ drivers/media/dvb/dvb-usb/anysee.h | 1 + 2 files changed, 206 insertions(+), 94 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c index 1ec88b694d29..d4d2420155b4 100644 --- a/drivers/media/dvb/dvb-usb/anysee.c +++ b/drivers/media/dvb/dvb-usb/anysee.c @@ -446,6 +446,114 @@ static struct isl6423_config anysee_isl6423_config = { * IOE[5] STV0903 1=enabled */ +static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct anysee_state *state = adap->dev->priv; + int ret; + + deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff); + + /* no frontend sleep control */ + if (onoff == 0) + return 0; + + switch (state->hw) { + case ANYSEE_HW_507FA: /* 15 */ + /* E30 Combo Plus */ + /* E30 C Plus */ + + if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), + 0x01); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-C tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), + 0x01); + if (ret) + goto error; + + /* enable DVB-T tuner on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + } + + break; + case ANYSEE_HW_508TC: /* 18 */ + case ANYSEE_HW_508PTC: /* 21 */ + /* E7 TC */ + /* E7 PTC */ + + if ((fe->id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), + 0x40); + if (ret) + goto error; + + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), + 0x01); + if (ret) + goto error; + } else { + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); + if (ret) + goto error; + + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + 0x40); + if (ret) + goto error; + + /* enable IF route on IOE[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), + 0x01); + if (ret) + goto error; + } + + break; + default: + ret = 0; + } + +error: + return ret; +} + static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { int ret; @@ -466,27 +574,37 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) } }; - /* Check which hardware we have. - * We must do this call two times to get reliable values (hw bug). - */ - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; + /* detect hardware only once */ + if (adap->fe[0] == NULL) { + /* Check which hardware we have. + * We must do this call two times to get reliable values (hw bug). + */ + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; - ret = anysee_get_hw_info(adap->dev, hw_info); - if (ret) - goto error; + ret = anysee_get_hw_info(adap->dev, hw_info); + if (ret) + goto error; + + /* Meaning of these info bytes are guessed. */ + info("firmware version:%d.%d hardware id:%d", + hw_info[1], hw_info[2], hw_info[0]); - /* Meaning of these info bytes are guessed. */ - info("firmware version:%d.%d hardware id:%d", - hw_info[1], hw_info[2], hw_info[0]); + state->hw = hw_info[0]; + } - state->hw = hw_info[0]; + /* set current frondend ID for devices having two frondends */ + if (adap->fe[0]) + state->fe_id++; switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ /* E30 */ + if (state->fe_id) + break; + /* attach demod */ adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config, &adap->dev->i2c_adap); @@ -501,6 +619,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) case ANYSEE_HW_507CD: /* 6 */ /* E30 Plus */ + if (state->fe_id) + break; + /* enable DVB-T demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) @@ -512,26 +633,32 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe[0] = dvb_attach(zl10353_attach, + &anysee_zl10353_config, &adap->dev->i2c_adap); break; case ANYSEE_HW_507DC: /* 10 */ /* E30 C Plus */ + if (state->fe_id) + break; + /* enable DVB-C demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[0] = dvb_attach(tda10023_attach, + &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48); break; case ANYSEE_HW_507SI: /* 11 */ /* E30 S2 Plus */ + if (state->fe_id) + break; + /* enable DVB-S/S2 demod on IOD[0] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01); if (ret) @@ -564,55 +691,59 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto error; - if (dvb_usb_anysee_delsys) { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); + if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), + 0x01); if (ret) goto error; - /* enable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), - 0x01); + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); if (ret) goto error; /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config2, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach( + tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); } else { /* PLL config */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_config, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach( + tda10023_attach, + &anysee_tda10023_config, + &adap->dev->i2c_adap, 0x48); } } else { - /* disable DVB-T demod on IOD[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0), - 0x01); + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), + 0x20); if (ret) goto error; - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), - 0x20); + /* enable DVB-T demod on IOD[0] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), + 0x01); if (ret) goto error; /* attach demod */ if (tmp == 0xc7) { /* TDA18212 config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach( + zl10353_attach, + &anysee_zl10353_tda18212_config2, + &adap->dev->i2c_adap); } else { /* PLL config */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach( + zl10353_attach, + &anysee_zl10353_config, + &adap->dev->i2c_adap); } } @@ -627,52 +758,40 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (ret) goto error; - if (dvb_usb_anysee_delsys) { - /* disable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), - 0x20); - if (ret) - goto error; - - /* enable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0) { + /* disable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), 0x40); if (ret) goto error; - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); + /* enable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + 0x20); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(zl10353_attach, - &anysee_zl10353_tda18212_config, - &adap->dev->i2c_adap); + adap->fe[state->fe_id] = dvb_attach(tda10023_attach, + &anysee_tda10023_tda18212_config, + &adap->dev->i2c_adap, 0x48); } else { - /* disable DVB-T demod on IOD[6] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6), - 0x40); - if (ret) - goto error; - - /* enable DVB-C demod on IOD[5] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5), + /* disable DVB-C demod on IOD[5] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5), 0x20); if (ret) goto error; - /* enable IF route on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); + /* enable DVB-T demod on IOD[6] */ + ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6), + 0x40); if (ret) goto error; /* attach demod */ - adap->fe[0] = dvb_attach(tda10023_attach, - &anysee_tda10023_tda18212_config, - &adap->dev->i2c_adap, 0x48); + adap->fe[state->fe_id] = dvb_attach(zl10353_attach, + &anysee_zl10353_tda18212_config, + &adap->dev->i2c_adap); } break; @@ -681,6 +800,9 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* E7 S2 */ /* E7 PS2 */ + if (state->fe_id) + break; + /* enable transport stream on IOA[7] */ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80); if (ret) @@ -713,7 +835,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) struct anysee_state *state = adap->dev->priv; struct dvb_frontend *fe; int ret; - deb_info("%s:\n", __func__); + deb_info("%s: fe=%d\n", __func__, state->fe_id); switch (state->hw) { case ANYSEE_HW_507T: /* 2 */ @@ -744,28 +866,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) /* E30 S2 Plus */ /* attach LNB controller */ - fe = dvb_attach(isl6423_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_isl6423_config); + fe = dvb_attach(isl6423_attach, adap->fe[0], + &adap->dev->i2c_adap, &anysee_isl6423_config); break; case ANYSEE_HW_507FA: /* 15 */ /* E30 Combo Plus */ /* E30 C Plus */ - if (dvb_usb_anysee_delsys) { - /* enable DVB-T tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0), - 0x01); - if (ret) - goto error; - } else { - /* enable DVB-C tuner on IOE[0] */ - ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0), - 0x01); - if (ret) - goto error; - } - /* Try first attach TDA18212 silicon tuner on IOE[4], if that * fails attach old simple PLL. */ @@ -775,8 +883,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + &adap->dev->i2c_adap, &anysee_tda18212_config); if (fe) break; @@ -786,8 +894,9 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1), - &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A); + fe = dvb_attach(dvb_pll_attach, adap->fe[state->fe_id], + (0xc0 >> 1), &adap->dev->i2c_adap, + DVB_PLL_SAMSUNG_DTOS403IH102A); break; case ANYSEE_HW_508TC: /* 18 */ @@ -801,8 +910,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap) goto error; /* attach tuner */ - fe = dvb_attach(tda18212_attach, adap->fe[0], &adap->dev->i2c_adap, - &anysee_tda18212_config); + fe = dvb_attach(tda18212_attach, adap->fe[state->fe_id], + &adap->dev->i2c_adap, &anysee_tda18212_config); break; case ANYSEE_HW_508S2: /* 19 */ @@ -918,6 +1027,8 @@ static struct dvb_usb_device_properties anysee_properties = { .num_adapters = 1, .adapter = { { + .num_frontends = 2, + .frontend_ctrl = anysee_frontend_ctrl, .streaming_ctrl = anysee_streaming_ctrl, .frontend_attach = anysee_frontend_attach, .tuner_attach = anysee_tuner_attach, diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h index ad6ccd1ea2d9..57ee500b8c0e 100644 --- a/drivers/media/dvb/dvb-usb/anysee.h +++ b/drivers/media/dvb/dvb-usb/anysee.h @@ -59,6 +59,7 @@ enum cmd { struct anysee_state { u8 hw; /* PCB ID */ u8 seq; + u8 fe_id:1; /* frondend ID */ }; #define ANYSEE_HW_507T 2 /* E30 */ -- cgit v1.2.3 From a5f2db539bd2a977cdee3fecc5c15dd0941c1ab3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 31 Jul 2011 09:37:56 -0300 Subject: v4l2-ioctl: properly return -EINVAL when parameters are wrong Whan an ioctl is implemented, but the parameters are invalid, the error code should be -EINVAL. However, if the ioctl is not defined, it should return -ENOTTY instead. Reported-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/v4l2-ioctl.c | 89 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 002ce1363443..9f80e9d1fdb7 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -55,6 +55,14 @@ memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) +#define no_ioctl_err(foo) ( ( \ + ops->vidioc_##foo##_fmt_vid_cap || \ + ops->vidioc_##foo##_fmt_vid_out || \ + ops->vidioc_##foo##_fmt_vid_cap_mplane || \ + ops->vidioc_##foo##_fmt_vid_out_mplane || \ + ops->vidioc_##foo##_fmt_vid_overlay || \ + ops->vidioc_##foo##_fmt_type_private) ? -EINVAL : -ENOTTY) + struct std_descr { v4l2_std_id std; const char *descr; @@ -591,7 +599,7 @@ static long __video_do_ioctl(struct file *file, ret = v4l2_prio_check(vfd->prio, vfh->prio); if (ret) goto exit_prio; - ret = -EINVAL; + ret = -ENOTTY; break; } } @@ -638,7 +646,7 @@ static long __video_do_ioctl(struct file *file, enum v4l2_priority *p = arg; if (!ops->vidioc_s_priority && !use_fh_prio) - break; + break; dbgarg(cmd, "setting priority to %d\n", *p); if (ops->vidioc_s_priority) ret = ops->vidioc_s_priority(file, fh, *p); @@ -654,37 +662,37 @@ static long __video_do_ioctl(struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (ops->vidioc_enum_fmt_vid_cap) + if (likely(ops->vidioc_enum_fmt_vid_cap)) ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (ops->vidioc_enum_fmt_vid_cap_mplane) + if (likely(ops->vidioc_enum_fmt_vid_cap_mplane)) ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_enum_fmt_vid_overlay) + if (likely(ops->vidioc_enum_fmt_vid_overlay)) ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (ops->vidioc_enum_fmt_vid_out) + if (likely(ops->vidioc_enum_fmt_vid_out)) ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (ops->vidioc_enum_fmt_vid_out_mplane) + if (likely(ops->vidioc_enum_fmt_vid_out_mplane)) ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_enum_fmt_type_private) + if (likely(ops->vidioc_enum_fmt_type_private)) ret = ops->vidioc_enum_fmt_type_private(file, fh, f); break; default: break; } - if (!ret) + if (likely (!ret)) dbgarg(cmd, "index=%d, type=%d, flags=%d, " "pixelformat=%c%c%c%c, description='%s'\n", f->index, f->type, f->flags, @@ -693,6 +701,8 @@ static long __video_do_ioctl(struct file *file, (f->pixelformat >> 16) & 0xff, (f->pixelformat >> 24) & 0xff, f->description); + else if (ret == -ENOTTY) + ret = no_ioctl_err(enum); break; } case VIDIOC_G_FMT: @@ -744,7 +754,7 @@ static long __video_do_ioctl(struct file *file, v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (ops->vidioc_g_fmt_vid_overlay) + if (likely(ops->vidioc_g_fmt_vid_overlay)) ret = ops->vidioc_g_fmt_vid_overlay(file, fh, f); break; @@ -789,34 +799,36 @@ static long __video_do_ioctl(struct file *file, v4l_print_pix_fmt_mplane(vfd, &f->fmt.pix_mp); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (ops->vidioc_g_fmt_vid_out_overlay) + if (likely(ops->vidioc_g_fmt_vid_out_overlay)) ret = ops->vidioc_g_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (ops->vidioc_g_fmt_vbi_cap) + if (likely(ops->vidioc_g_fmt_vbi_cap)) ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (ops->vidioc_g_fmt_vbi_out) + if (likely(ops->vidioc_g_fmt_vbi_out)) ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (ops->vidioc_g_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_g_fmt_sliced_vbi_cap)) ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (ops->vidioc_g_fmt_sliced_vbi_out) + if (likely(ops->vidioc_g_fmt_sliced_vbi_out)) ret = ops->vidioc_g_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (ops->vidioc_g_fmt_type_private) + if (likely(ops->vidioc_g_fmt_type_private)) ret = ops->vidioc_g_fmt_type_private(file, fh, f); break; } + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } @@ -926,33 +938,36 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_cap) + if (likely(ops->vidioc_s_fmt_vbi_cap)) ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_s_fmt_vbi_out) + if (likely(ops->vidioc_s_fmt_vbi_out)) ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_s_fmt_sliced_vbi_cap)) ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_s_fmt_sliced_vbi_out) + if (likely(ops->vidioc_s_fmt_sliced_vbi_out)) ret = ops->vidioc_s_fmt_sliced_vbi_out(file, fh, f); + break; case V4L2_BUF_TYPE_PRIVATE: /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_s_fmt_type_private) + if (likely(ops->vidioc_s_fmt_type_private)) ret = ops->vidioc_s_fmt_type_private(file, fh, f); break; } + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } case VIDIOC_TRY_FMT: @@ -1008,7 +1023,7 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_overlay) + if (likely(ops->vidioc_try_fmt_vid_overlay)) ret = ops->vidioc_try_fmt_vid_overlay(file, fh, f); break; @@ -1057,40 +1072,43 @@ static long __video_do_ioctl(struct file *file, break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: CLEAR_AFTER_FIELD(f, fmt.win); - if (ops->vidioc_try_fmt_vid_out_overlay) + if (likely(ops->vidioc_try_fmt_vid_out_overlay)) ret = ops->vidioc_try_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_cap) + if (likely(ops->vidioc_try_fmt_vbi_cap)) ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.vbi); - if (ops->vidioc_try_fmt_vbi_out) + if (likely(ops->vidioc_try_fmt_vbi_out)) ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_cap) + if (likely(ops->vidioc_try_fmt_sliced_vbi_cap)) ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: CLEAR_AFTER_FIELD(f, fmt.sliced); - if (ops->vidioc_try_fmt_sliced_vbi_out) + if (likely(ops->vidioc_try_fmt_sliced_vbi_out)) ret = ops->vidioc_try_fmt_sliced_vbi_out(file, fh, f); + else + ret = no_ioctl_err(try); break; case V4L2_BUF_TYPE_PRIVATE: /* CLEAR_AFTER_FIELD(f, fmt.raw_data); <- does nothing */ - if (ops->vidioc_try_fmt_type_private) + if (likely(ops->vidioc_try_fmt_type_private)) ret = ops->vidioc_try_fmt_type_private(file, fh, f); break; } - + if (unlikely(ret == -ENOTTY)) + ret = no_ioctl_err(g); break; } /* FIXME: Those buf reqs could be handled here, @@ -1262,16 +1280,15 @@ static long __video_do_ioctl(struct file *file, { v4l2_std_id *id = arg; - ret = 0; /* Calls the specific handler */ if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, id); - else if (vfd->current_norm) + else if (vfd->current_norm) { + ret = 0; *id = vfd->current_norm; - else - ret = -EINVAL; + } - if (!ret) + if (likely(!ret)) dbgarg(cmd, "std=0x%08Lx\n", (long long unsigned)*id); break; } @@ -1288,8 +1305,6 @@ static long __video_do_ioctl(struct file *file, /* Calls the specific handler */ if (ops->vidioc_s_std) ret = ops->vidioc_s_std(file, fh, &norm); - else - ret = -EINVAL; /* Updates standard information */ if (ret >= 0) @@ -1812,7 +1827,7 @@ static long __video_do_ioctl(struct file *file, if (ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, &std); else if (std == 0) - ret = -EINVAL; + ret = -ENOTTY; if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); -- cgit v1.2.3 From 63d77173266c1791f1553e9e8ccea65dc87c4485 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 31 Jul 2011 13:54:50 -0700 Subject: random: Add support for architectural random hooks Add support for architecture-specific hooks into the kernel-directed random number generator interfaces. This patchset does not use the architecture random number generator interfaces for the userspace-directed interfaces (/dev/random and /dev/urandom), thus eliminating the need to distinguish between them based on a pool pointer. Changes in version 3: - Moved the hooks from extract_entropy() to get_random_bytes(). - Changes the hooks to inlines. Signed-off-by: H. Peter Anvin Cc: Fenghua Yu Cc: Matt Mackall Cc: Herbert Xu Cc: "Theodore Ts'o" --- drivers/char/random.c | 25 ++++++++++++++++++++++--- include/linux/random.h | 13 +++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index d4ddeba56682..bb587127fb9d 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -932,7 +932,21 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, */ void get_random_bytes(void *buf, int nbytes) { - extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); + char *p = buf; + + while (nbytes) { + unsigned long v; + int chunk = min(nbytes, (int)sizeof(unsigned long)); + + if (!arch_get_random_long(&v)) + break; + + memcpy(buf, &v, chunk); + p += chunk; + nbytes -= chunk; + } + + extract_entropy(&nonblocking_pool, p, nbytes, 0, 0); } EXPORT_SYMBOL(get_random_bytes); @@ -1635,8 +1649,13 @@ DEFINE_PER_CPU(__u32 [4], get_random_int_hash); unsigned int get_random_int(void) { struct keydata *keyptr; - __u32 *hash = get_cpu_var(get_random_int_hash); - int ret; + __u32 *hash; + unsigned int ret; + + if (arch_get_random_int(&ret)) + return ret; + + hash = get_cpu_var(get_random_int_hash); keyptr = get_keyptr(); hash[0] += current->pid + jiffies + get_cycles(); diff --git a/include/linux/random.h b/include/linux/random.h index fb7ab9de5f36..079cbba39a28 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -102,6 +102,19 @@ static inline void prandom32_seed(struct rnd_state *state, u64 seed) state->s3 = __seed(i, 15); } +#ifdef CONFIG_ARCH_RANDOM +# include +#else +static inline int arch_get_random_long(unsigned long *v) +{ + return 0; +} +static inline int arch_get_random_int(unsigned int *v) +{ + return 0; +} +#endif + #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ -- cgit v1.2.3 From 628c6246d47b85f5357298601df2444d7f4dd3fd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 31 Jul 2011 13:59:29 -0700 Subject: x86, random: Architectural inlines to get random integers with RDRAND Architectural inlines to get random ints and longs using the RDRAND instruction. Intel has introduced a new RDRAND instruction, a Digital Random Number Generator (DRNG), which is functionally an high bandwidth entropy source, cryptographic whitener, and integrity monitor all built into hardware. This enables RDRAND to be used directly, bypassing the kernel random number pool. For technical documentation, see: http://software.intel.com/en-us/articles/download-the-latest-bull-mountain-software-implementation-guide/ In this patch, this is *only* used for the nonblocking random number pool. RDRAND is a nonblocking source, similar to our /dev/urandom, and is therefore not a direct replacement for /dev/random. The architectural hooks presented in the previous patch only feed the kernel internal users, which only use the nonblocking pool, and so this is not a problem. Since this instruction is available in userspace, there is no reason to have a /dev/hw_rng device driver for the purpose of feeding rngd. This is especially so since RDRAND is a nonblocking source, and needs additional whitening and reduction (see the above technical documentation for details) in order to be of "pure entropy source" quality. The CONFIG_EXPERT compile-time option can be used to disable this use of RDRAND. Signed-off-by: H. Peter Anvin Originally-by: Fenghua Yu Cc: Matt Mackall Cc: Herbert Xu Cc: "Theodore Ts'o" --- arch/x86/Kconfig | 9 +++++ arch/x86/include/asm/archrandom.h | 73 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 arch/x86/include/asm/archrandom.h diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 37357a599dca..a0e9bda72fda 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1451,6 +1451,15 @@ config ARCH_USES_PG_UNCACHED def_bool y depends on X86_PAT +config ARCH_RANDOM + def_bool y + prompt "x86 architectural random number generator" if EXPERT + ---help--- + Enable the x86 architectural RDRAND instruction + (Intel Bull Mountain technology) to generate random numbers. + If supported, this is a high bandwidth, cryptographically + secure hardware random number generator. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h new file mode 100644 index 000000000000..b7b5bc02e361 --- /dev/null +++ b/arch/x86/include/asm/archrandom.h @@ -0,0 +1,73 @@ +/* + * This file is part of the Linux kernel. + * + * Copyright (c) 2011, Intel Corporation + * Authors: Fenghua Yu , + * H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef ASM_X86_ARCHRANDOM_H +#define ASM_X86_ARCHRANDOM_H + +#include +#include +#include +#include + +#define RDRAND_RETRY_LOOPS 10 + +#define RDRAND_INT ".byte 0x0f,0xc7,0xf0" +#ifdef CONFIG_X86_64 +# define RDRAND_LONG ".byte 0x48,0x0f,0xc7,0xf0" +#else +# define RDRAND_LONG RDRAND_INT +#endif + +#ifdef CONFIG_ARCH_RANDOM + +#define GET_RANDOM(name, type, rdrand, nop) \ +static inline int name(type *v) \ +{ \ + int ok; \ + alternative_io("movl $0, %0\n\t" \ + nop, \ + "\n1: " rdrand "\n\t" \ + "jc 2f\n\t" \ + "decl %0\n\t" \ + "jnz 1b\n\t" \ + "2:", \ + X86_FEATURE_RDRAND, \ + ASM_OUTPUT2("=r" (ok), "=a" (*v)), \ + "0" (RDRAND_RETRY_LOOPS)); \ + return ok; \ +} + +#ifdef CONFIG_X86_64 + +GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP5); +GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP4); + +#else + +GET_RANDOM(arch_get_random_long, unsigned long, RDRAND_LONG, ASM_NOP3); +GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); + +#endif /* CONFIG_X86_64 */ + +#endif /* CONFIG_ARCH_RANDOM */ + +#endif /* ASM_X86_ARCHRANDOM_H */ -- cgit v1.2.3 From 49d859d78c5aeb998b6936fcb5f288f78d713489 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 31 Jul 2011 14:02:19 -0700 Subject: x86, random: Verify RDRAND functionality and allow it to be disabled If the CPU declares that RDRAND is available, go through a guranteed reseed sequence, and make sure that it is actually working (producing data.) If it does not, disable the CPU feature flag. Allow RDRAND to be disabled on the command line (as opposed to at compile time) for a user who has special requirements with regards to random numbers. Signed-off-by: H. Peter Anvin Cc: Matt Mackall Cc: Herbert Xu Cc: "Theodore Ts'o" --- Documentation/kernel-parameters.txt | 5 +++ arch/x86/include/asm/archrandom.h | 2 + arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/common.c | 2 + arch/x86/kernel/cpu/rdrand.c | 73 +++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 arch/x86/kernel/cpu/rdrand.c diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index aa47be71df4c..397ee05132a3 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1764,6 +1764,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted. noresidual [PPC] Don't use residual data on PReP machines. + nordrand [X86] Disable the direct use of the RDRAND + instruction even if it is supported by the + processor. RDRAND is still available to user + space applications. + noresume [SWSUSP] Disables resume and restores original swap space. diff --git a/arch/x86/include/asm/archrandom.h b/arch/x86/include/asm/archrandom.h index b7b5bc02e361..0d9ec770f2f8 100644 --- a/arch/x86/include/asm/archrandom.h +++ b/arch/x86/include/asm/archrandom.h @@ -70,4 +70,6 @@ GET_RANDOM(arch_get_random_int, unsigned int, RDRAND_INT, ASM_NOP3); #endif /* CONFIG_ARCH_RANDOM */ +extern void x86_init_rdrand(struct cpuinfo_x86 *c); + #endif /* ASM_X86_ARCHRANDOM_H */ diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 6042981d0309..0e3a82a41a66 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -15,6 +15,7 @@ CFLAGS_common.o := $(nostackp) obj-y := intel_cacheinfo.o scattered.o topology.o obj-y += proc.o capflags.o powerflags.o common.o obj-y += vmware.o hypervisor.o sched.o mshyperv.o +obj-y += rdrand.o obj-$(CONFIG_X86_32) += bugs.o obj-$(CONFIG_X86_64) += bugs_64.o diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 22a073d7fbff..8dbd9294f4f2 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -857,6 +858,7 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) #endif init_hypervisor(c); + x86_init_rdrand(c); /* * Clear/Set all flags overriden by options, need do it diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c new file mode 100644 index 000000000000..feca286c2bb4 --- /dev/null +++ b/arch/x86/kernel/cpu/rdrand.c @@ -0,0 +1,73 @@ +/* + * This file is part of the Linux kernel. + * + * Copyright (c) 2011, Intel Corporation + * Authors: Fenghua Yu , + * H. Peter Anvin + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include + +static int __init x86_rdrand_setup(char *s) +{ + setup_clear_cpu_cap(X86_FEATURE_RDRAND); + return 1; +} +__setup("nordrand", x86_rdrand_setup); + +/* We can't use arch_get_random_long() here since alternatives haven't run */ +static inline int rdrand_long(unsigned long *v) +{ + int ok; + asm volatile("1: " RDRAND_LONG "\n\t" + "jc 2f\n\t" + "decl %0\n\t" + "jnz 1b\n\t" + "2:" + : "=r" (ok), "=a" (*v) + : "0" (RDRAND_RETRY_LOOPS)); + return ok; +} + +/* + * Force a reseed cycle; we are architecturally guaranteed a reseed + * after no more than 512 128-bit chunks of random data. This also + * acts as a test of the CPU capability. + */ +#define RESEED_LOOP ((512*128)/sizeof(unsigned long)) + +void __cpuinit x86_init_rdrand(struct cpuinfo_x86 *c) +{ +#ifdef CONFIG_ARCH_RANDOM + unsigned long tmp; + int i, count, ok; + + if (!cpu_has(c, X86_FEATURE_RDRAND)) + return; /* Nothing to do */ + + for (count = i = 0; i < RESEED_LOOP; i++) { + ok = rdrand_long(&tmp); + if (ok) + count++; + } + + if (count != RESEED_LOOP) + clear_cpu_cap(c, X86_FEATURE_RDRAND); +#endif +} -- cgit v1.2.3 From 1a1952779b8e92a404dceaecca70ba120bea2d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 25 Jul 2011 12:05:09 +0200 Subject: ARM: mx5: fix remaining inconsistent names for irqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mx5/clock-mx51-mx53.c | 2 +- arch/arm/mach-mx5/devices.c | 10 +-- arch/arm/mach-mx5/mm.c | 8 +- arch/arm/plat-mxc/include/mach/mx51.h | 162 +++++++++++++++++----------------- 4 files changed, 91 insertions(+), 91 deletions(-) diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index 7f20308c4dbd..bd5f697db0e4 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -1564,7 +1564,7 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, /* System timer */ mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), - MX51_MXC_INT_GPT); + MX51_INT_GPT); return 0; } diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 371ca8c8414c..5fd8f0c7c844 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -23,8 +23,8 @@ static struct resource mxc_hsi2c_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_HS_I2C, - .end = MX51_MXC_INT_HS_I2C, + .start = MX51_INT_HS_I2C, + .end = MX51_INT_HS_I2C, .flags = IORESOURCE_IRQ, }, }; @@ -45,7 +45,7 @@ static struct resource usbotg_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_USB_OTG, + .start = MX51_INT_USB_OTG, .flags = IORESOURCE_IRQ, }, }; @@ -80,7 +80,7 @@ static struct resource usbh1_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_USB_H1, + .start = MX51_INT_USB_H1, .flags = IORESOURCE_IRQ, }, }; @@ -103,7 +103,7 @@ static struct resource usbh2_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = MX51_MXC_INT_USB_H2, + .start = MX51_INT_USB_H2, .flags = IORESOURCE_IRQ, }, }; diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c index baea6e5cddd9..fcc5c4ce53f1 100644 --- a/arch/arm/mach-mx5/mm.c +++ b/arch/arm/mach-mx5/mm.c @@ -141,10 +141,10 @@ static struct sdma_platform_data imx53_sdma_pdata __initdata = { void __init imx51_soc_init(void) { /* i.mx51 has the i.mx31 type gpio */ - mxc_register_gpio("imx31-gpio", 0, MX51_GPIO1_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO1_LOW, MX51_MXC_INT_GPIO1_HIGH); - mxc_register_gpio("imx31-gpio", 1, MX51_GPIO2_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO2_LOW, MX51_MXC_INT_GPIO2_HIGH); - mxc_register_gpio("imx31-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO3_LOW, MX51_MXC_INT_GPIO3_HIGH); - mxc_register_gpio("imx31-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_MXC_INT_GPIO4_LOW, MX51_MXC_INT_GPIO4_HIGH); + mxc_register_gpio("imx31-gpio", 0, MX51_GPIO1_BASE_ADDR, SZ_16K, MX51_INT_GPIO1_LOW, MX51_INT_GPIO1_HIGH); + mxc_register_gpio("imx31-gpio", 1, MX51_GPIO2_BASE_ADDR, SZ_16K, MX51_INT_GPIO2_LOW, MX51_INT_GPIO2_HIGH); + mxc_register_gpio("imx31-gpio", 2, MX51_GPIO3_BASE_ADDR, SZ_16K, MX51_INT_GPIO3_LOW, MX51_INT_GPIO3_HIGH); + mxc_register_gpio("imx31-gpio", 3, MX51_GPIO4_BASE_ADDR, SZ_16K, MX51_INT_GPIO4_LOW, MX51_INT_GPIO4_HIGH); /* i.mx51 has the i.mx35 type sdma */ imx_add_imx_sdma("imx35-sdma", MX51_SDMA_BASE_ADDR, MX51_INT_SDMA, &imx51_sdma_pdata); diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h index dede19a766ff..d240b6f267b1 100644 --- a/arch/arm/plat-mxc/include/mach/mx51.h +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -240,110 +240,110 @@ /* * Interrupt numbers */ -#define MX51_MXC_INT_BASE 0 -#define MX51_MXC_INT_RESV0 0 +#define MX51_INT_BASE 0 +#define MX51_INT_RESV0 0 #define MX51_INT_ESDHC1 1 #define MX51_INT_ESDHC2 2 #define MX51_INT_ESDHC3 3 #define MX51_INT_ESDHC4 4 -#define MX51_MXC_INT_RESV5 5 +#define MX51_INT_RESV5 5 #define MX51_INT_SDMA 6 -#define MX51_MXC_INT_IOMUX 7 +#define MX51_INT_IOMUX 7 #define MX51_INT_NFC 8 -#define MX51_MXC_INT_VPU 9 +#define MX51_INT_VPU 9 #define MX51_INT_IPU_ERR 10 #define MX51_INT_IPU_SYN 11 -#define MX51_MXC_INT_GPU 12 -#define MX51_MXC_INT_RESV13 13 -#define MX51_MXC_INT_USB_H1 14 -#define MX51_MXC_INT_EMI 15 -#define MX51_MXC_INT_USB_H2 16 -#define MX51_MXC_INT_USB_H3 17 -#define MX51_MXC_INT_USB_OTG 18 -#define MX51_MXC_INT_SAHARA_H0 19 -#define MX51_MXC_INT_SAHARA_H1 20 -#define MX51_MXC_INT_SCC_SMN 21 -#define MX51_MXC_INT_SCC_STZ 22 -#define MX51_MXC_INT_SCC_SCM 23 -#define MX51_MXC_INT_SRTC_NTZ 24 -#define MX51_MXC_INT_SRTC_TZ 25 -#define MX51_MXC_INT_RTIC 26 -#define MX51_MXC_INT_CSU 27 -#define MX51_MXC_INT_SLIM_B 28 +#define MX51_INT_GPU 12 +#define MX51_INT_RESV13 13 +#define MX51_INT_USB_H1 14 +#define MX51_INT_EMI 15 +#define MX51_INT_USB_H2 16 +#define MX51_INT_USB_H3 17 +#define MX51_INT_USB_OTG 18 +#define MX51_INT_SAHARA_H0 19 +#define MX51_INT_SAHARA_H1 20 +#define MX51_INT_SCC_SMN 21 +#define MX51_INT_SCC_STZ 22 +#define MX51_INT_SCC_SCM 23 +#define MX51_INT_SRTC_NTZ 24 +#define MX51_INT_SRTC_TZ 25 +#define MX51_INT_RTIC 26 +#define MX51_INT_CSU 27 +#define MX51_INT_SLIM_B 28 #define MX51_INT_SSI1 29 #define MX51_INT_SSI2 30 #define MX51_INT_UART1 31 #define MX51_INT_UART2 32 #define MX51_INT_UART3 33 -#define MX51_MXC_INT_RESV34 34 -#define MX51_MXC_INT_RESV35 35 +#define MX51_INT_RESV34 34 +#define MX51_INT_RESV35 35 #define MX51_INT_ECSPI1 36 #define MX51_INT_ECSPI2 37 #define MX51_INT_CSPI 38 -#define MX51_MXC_INT_GPT 39 -#define MX51_MXC_INT_EPIT1 40 -#define MX51_MXC_INT_EPIT2 41 -#define MX51_MXC_INT_GPIO1_INT7 42 -#define MX51_MXC_INT_GPIO1_INT6 43 -#define MX51_MXC_INT_GPIO1_INT5 44 -#define MX51_MXC_INT_GPIO1_INT4 45 -#define MX51_MXC_INT_GPIO1_INT3 46 -#define MX51_MXC_INT_GPIO1_INT2 47 -#define MX51_MXC_INT_GPIO1_INT1 48 -#define MX51_MXC_INT_GPIO1_INT0 49 -#define MX51_MXC_INT_GPIO1_LOW 50 -#define MX51_MXC_INT_GPIO1_HIGH 51 -#define MX51_MXC_INT_GPIO2_LOW 52 -#define MX51_MXC_INT_GPIO2_HIGH 53 -#define MX51_MXC_INT_GPIO3_LOW 54 -#define MX51_MXC_INT_GPIO3_HIGH 55 -#define MX51_MXC_INT_GPIO4_LOW 56 -#define MX51_MXC_INT_GPIO4_HIGH 57 -#define MX51_MXC_INT_WDOG1 58 -#define MX51_MXC_INT_WDOG2 59 +#define MX51_INT_GPT 39 +#define MX51_INT_EPIT1 40 +#define MX51_INT_EPIT2 41 +#define MX51_INT_GPIO1_INT7 42 +#define MX51_INT_GPIO1_INT6 43 +#define MX51_INT_GPIO1_INT5 44 +#define MX51_INT_GPIO1_INT4 45 +#define MX51_INT_GPIO1_INT3 46 +#define MX51_INT_GPIO1_INT2 47 +#define MX51_INT_GPIO1_INT1 48 +#define MX51_INT_GPIO1_INT0 49 +#define MX51_INT_GPIO1_LOW 50 +#define MX51_INT_GPIO1_HIGH 51 +#define MX51_INT_GPIO2_LOW 52 +#define MX51_INT_GPIO2_HIGH 53 +#define MX51_INT_GPIO3_LOW 54 +#define MX51_INT_GPIO3_HIGH 55 +#define MX51_INT_GPIO4_LOW 56 +#define MX51_INT_GPIO4_HIGH 57 +#define MX51_INT_WDOG1 58 +#define MX51_INT_WDOG2 59 #define MX51_INT_KPP 60 #define MX51_INT_PWM1 61 #define MX51_INT_I2C1 62 #define MX51_INT_I2C2 63 -#define MX51_MXC_INT_HS_I2C 64 -#define MX51_MXC_INT_RESV65 65 -#define MX51_MXC_INT_RESV66 66 -#define MX51_MXC_INT_SIM_IPB 67 -#define MX51_MXC_INT_SIM_DAT 68 -#define MX51_MXC_INT_IIM 69 -#define MX51_MXC_INT_ATA 70 -#define MX51_MXC_INT_CCM1 71 -#define MX51_MXC_INT_CCM2 72 -#define MX51_MXC_INT_GPC1 73 -#define MX51_MXC_INT_GPC2 74 -#define MX51_MXC_INT_SRC 75 -#define MX51_MXC_INT_NM 76 -#define MX51_MXC_INT_PMU 77 -#define MX51_MXC_INT_CTI_IRQ 78 -#define MX51_MXC_INT_CTI1_TG0 79 -#define MX51_MXC_INT_CTI1_TG1 80 -#define MX51_MXC_INT_MCG_ERR 81 -#define MX51_MXC_INT_MCG_TMR 82 -#define MX51_MXC_INT_MCG_FUNC 83 -#define MX51_MXC_INT_GPU2_IRQ 84 -#define MX51_MXC_INT_GPU2_BUSY 85 -#define MX51_MXC_INT_RESV86 86 +#define MX51_INT_HS_I2C 64 +#define MX51_INT_RESV65 65 +#define MX51_INT_RESV66 66 +#define MX51_INT_SIM_IPB 67 +#define MX51_INT_SIM_DAT 68 +#define MX51_INT_IIM 69 +#define MX51_INT_ATA 70 +#define MX51_INT_CCM1 71 +#define MX51_INT_CCM2 72 +#define MX51_INT_GPC1 73 +#define MX51_INT_GPC2 74 +#define MX51_INT_SRC 75 +#define MX51_INT_NM 76 +#define MX51_INT_PMU 77 +#define MX51_INT_CTI_IRQ 78 +#define MX51_INT_CTI1_TG0 79 +#define MX51_INT_CTI1_TG1 80 +#define MX51_INT_MCG_ERR 81 +#define MX51_INT_MCG_TMR 82 +#define MX51_INT_MCG_FUNC 83 +#define MX51_INT_GPU2_IRQ 84 +#define MX51_INT_GPU2_BUSY 85 +#define MX51_INT_RESV86 86 #define MX51_INT_FEC 87 -#define MX51_MXC_INT_OWIRE 88 -#define MX51_MXC_INT_CTI1_TG2 89 -#define MX51_MXC_INT_SJC 90 -#define MX51_MXC_INT_SPDIF 91 -#define MX51_MXC_INT_TVE 92 -#define MX51_MXC_INT_FIRI 93 +#define MX51_INT_OWIRE 88 +#define MX51_INT_CTI1_TG2 89 +#define MX51_INT_SJC 90 +#define MX51_INT_SPDIF 91 +#define MX51_INT_TVE 92 +#define MX51_INT_FIRI 93 #define MX51_INT_PWM2 94 -#define MX51_MXC_INT_SLIM_EXP 95 +#define MX51_INT_SLIM_EXP 95 #define MX51_INT_SSI3 96 -#define MX51_MXC_INT_EMI_BOOT 97 -#define MX51_MXC_INT_CTI1_TG3 98 -#define MX51_MXC_INT_SMC_RX 99 -#define MX51_MXC_INT_VPU_IDLE 100 -#define MX51_MXC_INT_EMI_NFC 101 -#define MX51_MXC_INT_GPU_IDLE 102 +#define MX51_INT_EMI_BOOT 97 +#define MX51_INT_CTI1_TG3 98 +#define MX51_INT_SMC_RX 99 +#define MX51_INT_VPU_IDLE 100 +#define MX51_INT_EMI_NFC 101 +#define MX51_INT_GPU_IDLE 102 #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS) extern int mx51_revision(void); -- cgit v1.2.3 From b7ca83273d0f4dc160711727292a277522d5e4a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 31 Jul 2011 00:18:57 +0200 Subject: ARM: mx5: remove unused #includes of devices.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mx5/board-mx51_3ds.c | 1 - arch/arm/mach-mx5/board-mx51_efikamx.c | 1 - arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c | 1 - arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c | 1 - 4 files changed, 4 deletions(-) diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-mx5/board-mx51_3ds.c index 07a38154da21..e5db7c1af5da 100644 --- a/arch/arm/mach-mx5/board-mx51_3ds.c +++ b/arch/arm/mach-mx5/board-mx51_3ds.c @@ -25,7 +25,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #define EXPIO_PARENT_INT gpio_to_irq(IMX_GPIO_NR(1, 6)) #define MX51_3DS_ECSPI2_CS (GPIO_PORTC + 28) diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c index f70700dc0ec1..43ac100cfba9 100644 --- a/arch/arm/mach-mx5/board-mx51_efikamx.c +++ b/arch/arm/mach-mx5/board-mx51_efikamx.c @@ -39,7 +39,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #include "efika.h" #define EFIKAMX_PCBID0 IMX_GPIO_NR(3, 16) diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c index bbf4564bd050..72ce75505b1e 100644 --- a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c +++ b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c @@ -28,7 +28,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #define MBIMX51_TSC2007_GPIO IMX_GPIO_NR(3, 30) #define MBIMX51_LED0 IMX_GPIO_NR(3, 5) diff --git a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c index 261923997643..90f5c9c6306b 100644 --- a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c +++ b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c @@ -41,7 +41,6 @@ #include #include "devices-imx51.h" -#include "devices.h" static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = { /* LED */ -- cgit v1.2.3 From 7d92e8e6c4d45d33dd32a028081c89a6dedab032 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 30 Jul 2011 23:41:49 +0200 Subject: ARM: mx5: dynamically allocate mxc-ehci devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Additionally make the usb related defines consistent with the other imx SoCs. Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mx5/Kconfig | 6 ++- arch/arm/mach-mx5/board-cpuimx51.c | 12 +++--- arch/arm/mach-mx5/board-cpuimx51sd.c | 12 +++--- arch/arm/mach-mx5/board-mx51_babbage.c | 12 +++--- arch/arm/mach-mx5/board-mx51_efikasb.c | 5 +-- arch/arm/mach-mx5/devices-imx51.h | 7 +++ arch/arm/mach-mx5/devices.c | 61 +-------------------------- arch/arm/mach-mx5/devices.h | 3 -- arch/arm/mach-mx5/ehci.c | 2 +- arch/arm/mach-mx5/mx51_efika.c | 14 +++--- arch/arm/plat-mxc/devices/platform-mxc-ehci.c | 9 ++++ arch/arm/plat-mxc/include/mach/mx51.h | 11 +++-- 12 files changed, 57 insertions(+), 97 deletions(-) diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index b4e7c58bbb38..2905110954c2 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -68,6 +68,7 @@ config MACH_MX51_BABBAGE select IMX_HAVE_PLATFORM_IMX2_WDT select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX select IMX_HAVE_PLATFORM_SPI_IMX help @@ -93,6 +94,7 @@ config MACH_EUKREA_CPUIMX51 select SOC_IMX51 select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI select IMX_HAVE_PLATFORM_MXC_NAND select IMX_HAVE_PLATFORM_SPI_IMX help @@ -120,9 +122,10 @@ config MACH_EUKREA_CPUIMX51SD bool "Support Eukrea CPUIMX51SD module" select SOC_IMX51 select IMX_HAVE_PLATFORM_IMX_I2C - select IMX_HAVE_PLATFORM_SPI_IMX select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SPI_IMX help Include support for Eukrea CPUIMX51SD platform. This includes specific configurations for the module and its peripherals. @@ -147,6 +150,7 @@ config MX51_EFIKA_COMMON bool select SOC_IMX51 select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX select IMX_HAVE_PLATFORM_SPI_IMX select MXC_ULPI if USB_ULPI diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c index 7c893fa70266..aa1ff79e5a74 100644 --- a/arch/arm/mach-mx5/board-cpuimx51.c +++ b/arch/arm/mach-mx5/board-cpuimx51.c @@ -167,7 +167,7 @@ static int initialize_otg_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -190,7 +190,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -206,7 +206,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) MXC_EHCI_ITC_NO_THRESHOLD); } -static struct mxc_usbh_platform_data dr_utmi_config = { +static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .init = initialize_otg_port, .portsc = MXC_EHCI_UTMI_16BIT, }; @@ -216,7 +216,7 @@ static struct fsl_usb2_platform_data usb_pdata = { .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; -static struct mxc_usbh_platform_data usbh1_config = { +static const struct mxc_usbh_platform_data usbh1_config __initconst = { .init = initialize_usbh1_port, .portsc = MXC_EHCI_MODE_ULPI, }; @@ -270,12 +270,12 @@ static void __init eukrea_cpuimx51_init(void) ARRAY_SIZE(eukrea_cpuimx51_i2c_devices)); if (otg_mode_host) - mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); } - mxc_register_device(&mxc_usbh1_device, &usbh1_config); + imx51_add_mxc_ehci_hs(1, &usbh1_config); #ifdef CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD eukrea_mbimx51_baseboard_init(); diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c index ff096d587299..bca3719e2726 100644 --- a/arch/arm/mach-mx5/board-cpuimx51sd.c +++ b/arch/arm/mach-mx5/board-cpuimx51sd.c @@ -149,7 +149,7 @@ static int initialize_otg_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -172,7 +172,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -189,7 +189,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) MXC_EHCI_ITC_NO_THRESHOLD); } -static struct mxc_usbh_platform_data dr_utmi_config = { +static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .init = initialize_otg_port, .portsc = MXC_EHCI_UTMI_16BIT, }; @@ -199,7 +199,7 @@ static struct fsl_usb2_platform_data usb_pdata = { .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; -static struct mxc_usbh_platform_data usbh1_config = { +static const struct mxc_usbh_platform_data usbh1_config __initconst = { .init = initialize_usbh1_port, .portsc = MXC_EHCI_MODE_ULPI, }; @@ -303,7 +303,7 @@ static void __init eukrea_cpuimx51sd_init(void) platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); if (otg_mode_host) - mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); @@ -313,7 +313,7 @@ static void __init eukrea_cpuimx51sd_init(void) gpio_direction_output(USBH1_RST, 0); msleep(20); gpio_set_value(USBH1_RST, 1); - mxc_register_device(&mxc_usbh1_device, &usbh1_config); + imx51_add_mxc_ehci_hs(1, &usbh1_config); #ifdef CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD eukrea_mbimxsd51_baseboard_init(); diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index e400b09109ce..1d15297ab8b4 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -249,7 +249,7 @@ static int initialize_otg_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -272,7 +272,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; @@ -288,7 +288,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) MXC_EHCI_ITC_NO_THRESHOLD); } -static struct mxc_usbh_platform_data dr_utmi_config = { +static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .init = initialize_otg_port, .portsc = MXC_EHCI_UTMI_16BIT, }; @@ -298,7 +298,7 @@ static struct fsl_usb2_platform_data usb_pdata = { .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; -static struct mxc_usbh_platform_data usbh1_config = { +static const struct mxc_usbh_platform_data usbh1_config __initconst = { .init = initialize_usbh1_port, .portsc = MXC_EHCI_MODE_ULPI, }; @@ -384,14 +384,14 @@ static void __init mx51_babbage_init(void) mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data); if (otg_mode_host) - mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); } gpio_usbh1_active(); - mxc_register_device(&mxc_usbh1_device, &usbh1_config); + imx51_add_mxc_ehci_hs(1, &usbh1_config); /* setback USBH1_STP to be function */ mxc_iomux_v3_setup_pad(usbh1stp); babbage_usbhub_reset(); diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c index 2e4d9d32a87c..10f0562c3c48 100644 --- a/arch/arm/mach-mx5/board-mx51_efikasb.c +++ b/arch/arm/mach-mx5/board-mx51_efikasb.c @@ -42,7 +42,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #include "efika.h" #define EFIKASB_USBH2_STP IMX_GPIO_NR(2, 20) @@ -119,7 +118,7 @@ static int initialize_usbh2_port(struct platform_device *pdev) return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_ITC_NO_THRESHOLD); } -static struct mxc_usbh_platform_data usbh2_config = { +static struct mxc_usbh_platform_data usbh2_config __initdata = { .init = initialize_usbh2_port, .portsc = MXC_EHCI_MODE_ULPI, }; @@ -129,7 +128,7 @@ static void __init mx51_efikasb_usb(void) usbh2_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND); if (usbh2_config.otg) - mxc_register_device(&mxc_usbh2_device, &usbh2_config); + imx51_add_mxc_ehci_hs(2, &usbh2_config); } static const struct gpio_led mx51_efikasb_leds[] __initconst = { diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h index e11bc0e0ec49..f42acf5545e6 100644 --- a/arch/arm/mach-mx5/devices-imx51.h +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -25,6 +25,13 @@ extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[]; #define imx51_add_imx_uart(id, pdata) \ imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata) +extern const struct imx_mxc_ehci_data imx51_mxc_ehci_otg_data; +#define imx51_add_mxc_ehci_otg(pdata) \ + imx_add_mxc_ehci(&imx51_mxc_ehci_otg_data, pdata) +extern const struct imx_mxc_ehci_data imx51_mxc_ehci_hs_data[]; +#define imx51_add_mxc_ehci_hs(id, pdata) \ + imx_add_mxc_ehci(&imx51_mxc_ehci_hs_data[id - 1], pdata) + extern const struct imx_mxc_nand_data imx51_mxc_nand_data; #define imx51_add_mxc_nand(pdata) \ imx_add_mxc_nand(&imx51_mxc_nand_data, pdata) diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 5fd8f0c7c844..88edf26299f4 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -40,8 +40,8 @@ static u64 usb_dma_mask = DMA_BIT_MASK(32); static struct resource usbotg_resources[] = { { - .start = MX51_OTG_BASE_ADDR, - .end = MX51_OTG_BASE_ADDR + 0x1ff, + .start = MX51_USB_OTG_BASE_ADDR, + .end = MX51_USB_OTG_BASE_ADDR + 0x1ff, .flags = IORESOURCE_MEM, }, { @@ -61,60 +61,3 @@ struct platform_device mxc_usbdr_udc_device = { .coherent_dma_mask = DMA_BIT_MASK(32), }, }; - -struct platform_device mxc_usbdr_host_device = { - .name = "mxc-ehci", - .id = 0, - .num_resources = ARRAY_SIZE(usbotg_resources), - .resource = usbotg_resources, - .dev = { - .dma_mask = &usb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct resource usbh1_resources[] = { - { - .start = MX51_OTG_BASE_ADDR + 0x200, - .end = MX51_OTG_BASE_ADDR + 0x200 + 0x1ff, - .flags = IORESOURCE_MEM, - }, - { - .start = MX51_INT_USB_H1, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device mxc_usbh1_device = { - .name = "mxc-ehci", - .id = 1, - .num_resources = ARRAY_SIZE(usbh1_resources), - .resource = usbh1_resources, - .dev = { - .dma_mask = &usb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; - -static struct resource usbh2_resources[] = { - { - .start = MX51_OTG_BASE_ADDR + 0x400, - .end = MX51_OTG_BASE_ADDR + 0x400 + 0x1ff, - .flags = IORESOURCE_MEM, - }, - { - .start = MX51_INT_USB_H2, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device mxc_usbh2_device = { - .name = "mxc-ehci", - .id = 2, - .num_resources = ARRAY_SIZE(usbh2_resources), - .resource = usbh2_resources, - .dev = { - .dma_mask = &usb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index 55a5129bc29f..0f30a6e7138c 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -1,5 +1,2 @@ -extern struct platform_device mxc_usbdr_host_device; -extern struct platform_device mxc_usbh1_device; -extern struct platform_device mxc_usbh2_device; extern struct platform_device mxc_usbdr_udc_device; extern struct platform_device mxc_hsi2c_device; diff --git a/arch/arm/mach-mx5/ehci.c b/arch/arm/mach-mx5/ehci.c index 7ce12c804a32..c17fa131728b 100644 --- a/arch/arm/mach-mx5/ehci.c +++ b/arch/arm/mach-mx5/ehci.c @@ -52,7 +52,7 @@ int mx51_initialize_usb_hw(int port, unsigned int flags) void __iomem *usbother_base; int ret = 0; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) { printk(KERN_ERR "%s(): ioremap failed\n", __func__); return -ENOMEM; diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-mx5/mx51_efika.c index 4435e03cea5d..e99dead65b38 100644 --- a/arch/arm/mach-mx5/mx51_efika.c +++ b/arch/arm/mach-mx5/mx51_efika.c @@ -41,7 +41,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #include "efika.h" #include "cpu_op-mx51.h" @@ -133,7 +132,7 @@ static int initialize_otg_port(struct platform_device *pdev) u32 v; void __iomem *usb_base; void __iomem *usbother_base; - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); if (!usb_base) return -ENOMEM; usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET); @@ -150,7 +149,7 @@ static int initialize_otg_port(struct platform_device *pdev) return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY); } -static struct mxc_usbh_platform_data dr_utmi_config = { +static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .init = initialize_otg_port, .portsc = MXC_EHCI_UTMI_16BIT, }; @@ -170,7 +169,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) gpio_set_value(EFIKAMX_USBH1_STP, 1); msleep(1); - usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K); socregs_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET); /* The clock for the USBH1 ULPI port will come externally */ @@ -189,7 +188,7 @@ static int initialize_usbh1_port(struct platform_device *pdev) return mx51_initialize_usb_hw(0, MXC_EHCI_ITC_NO_THRESHOLD); } -static struct mxc_usbh_platform_data usbh1_config = { +static struct mxc_usbh_platform_data usbh1_config __initdata = { .init = initialize_usbh1_port, .portsc = MXC_EHCI_MODE_ULPI, }; @@ -217,9 +216,9 @@ static void __init mx51_efika_usb(void) usbh1_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND); - mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + imx51_add_mxc_ehci_otg(&dr_utmi_config); if (usbh1_config.otg) - mxc_register_device(&mxc_usbh1_device, &usbh1_config); + imx51_add_mxc_ehci_hs(1, &usbh1_config); } static struct mtd_partition mx51_efika_spi_nor_partitions[] = { @@ -631,4 +630,3 @@ void __init efika_board_common_init(void) get_cpu_op = mx51_get_cpu_op; #endif } - diff --git a/arch/arm/plat-mxc/devices/platform-mxc-ehci.c b/arch/arm/plat-mxc/devices/platform-mxc-ehci.c index e1763e03e7cb..35851d889aca 100644 --- a/arch/arm/plat-mxc/devices/platform-mxc-ehci.c +++ b/arch/arm/plat-mxc/devices/platform-mxc-ehci.c @@ -49,6 +49,15 @@ const struct imx_mxc_ehci_data imx35_mxc_ehci_hs_data __initconst = imx_mxc_ehci_data_entry_single(MX35, 1, HS); #endif /* ifdef CONFIG_SOC_IMX35 */ +#ifdef CONFIG_SOC_IMX51 +const struct imx_mxc_ehci_data imx51_mxc_ehci_otg_data __initconst = + imx_mxc_ehci_data_entry_single(MX51, 0, OTG); +const struct imx_mxc_ehci_data imx51_mxc_ehci_hs_data[] __initconst = { + imx_mxc_ehci_data_entry_single(MX51, 1, HS1), + imx_mxc_ehci_data_entry_single(MX51, 2, HS2), +}; +#endif /* ifdef CONFIG_SOC_IMX51 */ + struct platform_device *__init imx_add_mxc_ehci( const struct imx_mxc_ehci_data *data, const struct mxc_usbh_platform_data *pdata) diff --git a/arch/arm/plat-mxc/include/mach/mx51.h b/arch/arm/plat-mxc/include/mach/mx51.h index d240b6f267b1..9666e31956b7 100644 --- a/arch/arm/plat-mxc/include/mach/mx51.h +++ b/arch/arm/plat-mxc/include/mach/mx51.h @@ -55,7 +55,10 @@ #define MX51_AIPS1_BASE_ADDR 0x73f00000 #define MX51_AIPS1_SIZE SZ_1M -#define MX51_OTG_BASE_ADDR (MX51_AIPS1_BASE_ADDR + 0x80000) +#define MX51_USB_BASE_ADDR (MX51_AIPS1_BASE_ADDR + 0x80000) +#define MX51_USB_OTG_BASE_ADDR (MX51_USB_BASE_ADDR + 0x0000) +#define MX51_USB_HS1_BASE_ADDR (MX51_USB_BASE_ADDR + 0x0200) +#define MX51_USB_HS2_BASE_ADDR (MX51_USB_BASE_ADDR + 0x0400) #define MX51_GPIO1_BASE_ADDR (MX51_AIPS1_BASE_ADDR + 0x84000) #define MX51_GPIO2_BASE_ADDR (MX51_AIPS1_BASE_ADDR + 0x88000) #define MX51_GPIO3_BASE_ADDR (MX51_AIPS1_BASE_ADDR + 0x8c000) @@ -255,10 +258,10 @@ #define MX51_INT_IPU_SYN 11 #define MX51_INT_GPU 12 #define MX51_INT_RESV13 13 -#define MX51_INT_USB_H1 14 +#define MX51_INT_USB_HS1 14 #define MX51_INT_EMI 15 -#define MX51_INT_USB_H2 16 -#define MX51_INT_USB_H3 17 +#define MX51_INT_USB_HS2 16 +#define MX51_INT_USB_HS3 17 #define MX51_INT_USB_OTG 18 #define MX51_INT_SAHARA_H0 19 #define MX51_INT_SAHARA_H1 20 -- cgit v1.2.3 From 6cafe48a6bfa8934d5564fbf9976a51040dac819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 30 Jul 2011 23:57:25 +0200 Subject: ARM: mx5: dynamically allocate fsl-usb2-udc devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mx5/Kconfig | 3 +++ arch/arm/mach-mx5/board-cpuimx51.c | 5 ++--- arch/arm/mach-mx5/board-cpuimx51sd.c | 5 ++--- arch/arm/mach-mx5/board-mx51_babbage.c | 4 ++-- arch/arm/mach-mx5/devices-imx51.h | 4 ++++ arch/arm/mach-mx5/devices.c | 26 ----------------------- arch/arm/mach-mx5/devices.h | 1 - arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c | 5 +++++ 8 files changed, 18 insertions(+), 35 deletions(-) diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig index 2905110954c2..d8691a0000c5 100644 --- a/arch/arm/mach-mx5/Kconfig +++ b/arch/arm/mach-mx5/Kconfig @@ -65,6 +65,7 @@ comment "i.MX51 machines:" config MACH_MX51_BABBAGE bool "Support MX51 BABBAGE platforms" select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC select IMX_HAVE_PLATFORM_IMX2_WDT select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_UART @@ -92,6 +93,7 @@ config MACH_MX51_3DS config MACH_EUKREA_CPUIMX51 bool "Support Eukrea CPUIMX51 module" select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_UART select IMX_HAVE_PLATFORM_MXC_EHCI @@ -121,6 +123,7 @@ endchoice config MACH_EUKREA_CPUIMX51SD bool "Support Eukrea CPUIMX51SD module" select SOC_IMX51 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC select IMX_HAVE_PLATFORM_IMX_I2C select IMX_HAVE_PLATFORM_IMX_UART select IMX_HAVE_PLATFORM_MXC_EHCI diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c index aa1ff79e5a74..e2afe0c2a12e 100644 --- a/arch/arm/mach-mx5/board-cpuimx51.c +++ b/arch/arm/mach-mx5/board-cpuimx51.c @@ -36,7 +36,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #define CPUIMX51_USBH1_STP IMX_GPIO_NR(1, 27) #define CPUIMX51_QUARTA_GPIO IMX_GPIO_NR(3, 28) @@ -211,7 +210,7 @@ static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .portsc = MXC_EHCI_UTMI_16BIT, }; -static struct fsl_usb2_platform_data usb_pdata = { +static const struct fsl_usb2_platform_data usb_pdata __initconst = { .operating_mode = FSL_USB2_DR_DEVICE, .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; @@ -273,7 +272,7 @@ static void __init eukrea_cpuimx51_init(void) imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); - mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + imx51_add_fsl_usb2_udc(&usb_pdata); } imx51_add_mxc_ehci_hs(1, &usbh1_config); diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c index bca3719e2726..71a5832d0929 100644 --- a/arch/arm/mach-mx5/board-cpuimx51sd.c +++ b/arch/arm/mach-mx5/board-cpuimx51sd.c @@ -39,7 +39,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #include "cpu_op-mx51.h" #define USBH1_RST IMX_GPIO_NR(2, 28) @@ -194,7 +193,7 @@ static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .portsc = MXC_EHCI_UTMI_16BIT, }; -static struct fsl_usb2_platform_data usb_pdata = { +static const struct fsl_usb2_platform_data usb_pdata __initconst = { .operating_mode = FSL_USB2_DR_DEVICE, .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; @@ -306,7 +305,7 @@ static void __init eukrea_cpuimx51sd_init(void) imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); - mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + imx51_add_fsl_usb2_udc(&usb_pdata); } gpio_request(USBH1_RST, "usb_rst"); diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 1d15297ab8b4..576a7992c23d 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -293,7 +293,7 @@ static const struct mxc_usbh_platform_data dr_utmi_config __initconst = { .portsc = MXC_EHCI_UTMI_16BIT, }; -static struct fsl_usb2_platform_data usb_pdata = { +static const struct fsl_usb2_platform_data usb_pdata __initconst = { .operating_mode = FSL_USB2_DR_DEVICE, .phy_mode = FSL_USB2_PHY_UTMI_WIDE, }; @@ -387,7 +387,7 @@ static void __init mx51_babbage_init(void) imx51_add_mxc_ehci_otg(&dr_utmi_config); else { initialize_otg_port(NULL); - mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + imx51_add_fsl_usb2_udc(&usb_pdata); } gpio_usbh1_active(); diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h index f42acf5545e6..2f2cdb93bfe2 100644 --- a/arch/arm/mach-mx5/devices-imx51.h +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -13,6 +13,10 @@ extern const struct imx_fec_data imx51_fec_data; #define imx51_add_fec(pdata) \ imx_add_fec(&imx51_fec_data, pdata) +extern const struct imx_fsl_usb2_udc_data imx51_fsl_usb2_udc_data; +#define imx51_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx51_fsl_usb2_udc_data, pdata) + extern const struct imx_imx_i2c_data imx51_imx_i2c_data[]; #define imx51_add_imx_i2c(id, pdata) \ imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c index 88edf26299f4..1c09026b314b 100644 --- a/arch/arm/mach-mx5/devices.c +++ b/arch/arm/mach-mx5/devices.c @@ -35,29 +35,3 @@ struct platform_device mxc_hsi2c_device = { .num_resources = ARRAY_SIZE(mxc_hsi2c_resources), .resource = mxc_hsi2c_resources }; - -static u64 usb_dma_mask = DMA_BIT_MASK(32); - -static struct resource usbotg_resources[] = { - { - .start = MX51_USB_OTG_BASE_ADDR, - .end = MX51_USB_OTG_BASE_ADDR + 0x1ff, - .flags = IORESOURCE_MEM, - }, - { - .start = MX51_INT_USB_OTG, - .flags = IORESOURCE_IRQ, - }, -}; - -/* OTG gadget device */ -struct platform_device mxc_usbdr_udc_device = { - .name = "fsl-usb2-udc", - .id = -1, - .num_resources = ARRAY_SIZE(usbotg_resources), - .resource = usbotg_resources, - .dev = { - .dma_mask = &usb_dma_mask, - .coherent_dma_mask = DMA_BIT_MASK(32), - }, -}; diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h index 0f30a6e7138c..6b2edfea129b 100644 --- a/arch/arm/mach-mx5/devices.h +++ b/arch/arm/mach-mx5/devices.h @@ -1,2 +1 @@ -extern struct platform_device mxc_usbdr_udc_device; extern struct platform_device mxc_hsi2c_device; diff --git a/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c b/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c index 23ce08e6ffd2..848038f301fd 100644 --- a/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c +++ b/arch/arm/plat-mxc/devices/platform-fsl-usb2-udc.c @@ -36,6 +36,11 @@ const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data __initconst = imx_fsl_usb2_udc_data_entry_single(MX35); #endif /* ifdef CONFIG_SOC_IMX35 */ +#ifdef CONFIG_SOC_IMX51 +const struct imx_fsl_usb2_udc_data imx51_fsl_usb2_udc_data __initconst = + imx_fsl_usb2_udc_data_entry_single(MX51); +#endif + struct platform_device *__init imx_add_fsl_usb2_udc( const struct imx_fsl_usb2_udc_data *data, const struct fsl_usb2_platform_data *pdata) -- cgit v1.2.3 From f26888549dd68c3902f43f544cddc670135d2477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 1 Aug 2011 09:07:54 +0200 Subject: ARM: mx5: dynamically allocate high speed i2c (imx-i2c actually) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the last device from devices.c. Signed-off-by: Uwe Kleine-König --- arch/arm/mach-mx5/Makefile | 2 +- arch/arm/mach-mx5/board-mx51_babbage.c | 5 ++-- arch/arm/mach-mx5/devices-imx51.h | 2 ++ arch/arm/mach-mx5/devices.c | 37 ---------------------------- arch/arm/mach-mx5/devices.h | 1 - arch/arm/plat-mxc/devices/platform-imx-i2c.c | 6 +++++ 6 files changed, 11 insertions(+), 42 deletions(-) delete mode 100644 arch/arm/mach-mx5/devices.c delete mode 100644 arch/arm/mach-mx5/devices.h diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile index 383e7cd3fbcb..7f452433a690 100644 --- a/arch/arm/mach-mx5/Makefile +++ b/arch/arm/mach-mx5/Makefile @@ -3,7 +3,7 @@ # # Object file lists. -obj-y := cpu.o mm.o clock-mx51-mx53.o devices.o ehci.o system.o +obj-y := cpu.o mm.o clock-mx51-mx53.o ehci.o system.o obj-$(CONFIG_SOC_IMX50) += mm-mx50.o obj-$(CONFIG_PM) += pm-imx5.o diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c index 576a7992c23d..41a911f50e65 100644 --- a/arch/arm/mach-mx5/board-mx51_babbage.c +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -31,7 +31,6 @@ #include #include "devices-imx51.h" -#include "devices.h" #include "cpu_op-mx51.h" #define BABBAGE_USB_HUB_RESET IMX_GPIO_NR(1, 7) @@ -176,7 +175,7 @@ static const struct imxi2c_platform_data babbage_i2c_data __initconst = { .bitrate = 100000, }; -static struct imxi2c_platform_data babbage_hsi2c_data = { +static const struct imxi2c_platform_data babbage_hsi2c_data __initconst = { .bitrate = 400000, }; @@ -381,7 +380,7 @@ static void __init mx51_babbage_init(void) imx51_add_imx_i2c(0, &babbage_i2c_data); imx51_add_imx_i2c(1, &babbage_i2c_data); - mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data); + imx51_add_hsi2c(&babbage_hsi2c_data); if (otg_mode_host) imx51_add_mxc_ehci_otg(&dr_utmi_config); diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h index 2f2cdb93bfe2..f311c9616bb1 100644 --- a/arch/arm/mach-mx5/devices-imx51.h +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -20,6 +20,8 @@ extern const struct imx_fsl_usb2_udc_data imx51_fsl_usb2_udc_data; extern const struct imx_imx_i2c_data imx51_imx_i2c_data[]; #define imx51_add_imx_i2c(id, pdata) \ imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) +#define imx51_add_hsi2c(pdata) \ + imx51_add_imx_i2c(2, pdata) extern const struct imx_imx_ssi_data imx51_imx_ssi_data[]; #define imx51_add_imx_ssi(id, pdata) \ diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c deleted file mode 100644 index 1c09026b314b..000000000000 --- a/arch/arm/mach-mx5/devices.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2009 Amit Kucheria - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include -#include -#include -#include -#include - -static struct resource mxc_hsi2c_resources[] = { - { - .start = MX51_HSI2C_DMA_BASE_ADDR, - .end = MX51_HSI2C_DMA_BASE_ADDR + SZ_16K - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MX51_INT_HS_I2C, - .end = MX51_INT_HS_I2C, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device mxc_hsi2c_device = { - .name = "imx-i2c", - .id = 2, - .num_resources = ARRAY_SIZE(mxc_hsi2c_resources), - .resource = mxc_hsi2c_resources -}; diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h deleted file mode 100644 index 6b2edfea129b..000000000000 --- a/arch/arm/mach-mx5/devices.h +++ /dev/null @@ -1 +0,0 @@ -extern struct platform_device mxc_hsi2c_device; diff --git a/arch/arm/plat-mxc/devices/platform-imx-i2c.c b/arch/arm/plat-mxc/devices/platform-imx-i2c.c index afe60f7244a8..19ad580c0be3 100644 --- a/arch/arm/plat-mxc/devices/platform-imx-i2c.c +++ b/arch/arm/plat-mxc/devices/platform-imx-i2c.c @@ -85,6 +85,12 @@ const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = { imx_imx_i2c_data_entry(MX51, _id, _hwid, SZ_4K) imx51_imx_i2c_data_entry(0, 1), imx51_imx_i2c_data_entry(1, 2), + { + .id = 2, + .iobase = MX51_HSI2C_DMA_BASE_ADDR, + .iosize = SZ_16K, + .irq = MX51_INT_HS_I2C, + }, }; #endif /* ifdef CONFIG_SOC_IMX51 */ -- cgit v1.2.3 From f2f07be02d6f4423b981279cb200107c5b596c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 31 Jul 2011 00:19:55 +0200 Subject: ARM: imx/mx1ads: dynamically allocate physmap-flash device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/mach-imx/mach-mx1ads.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c index 5cd8bee46960..e8867ffd68cf 100644 --- a/arch/arm/mach-imx/mach-mx1ads.c +++ b/arch/arm/mach-imx/mach-mx1ads.c @@ -68,23 +68,16 @@ static const struct imxuart_platform_data uart1_pdata __initconst = { * Physmap flash */ -static struct physmap_flash_data mx1ads_flash_data = { +static const struct physmap_flash_data mx1ads_flash_data __initconst = { .width = 4, /* bankwidth in bytes */ }; -static struct resource flash_resource = { +static const struct resource flash_resource __initconst = { .start = MX1_CS0_PHYS, .end = MX1_CS0_PHYS + SZ_32M - 1, .flags = IORESOURCE_MEM, }; -static struct platform_device flash_device = { - .name = "physmap-flash", - .id = 0, - .resource = &flash_resource, - .num_resources = 1, -}; - /* * I2C */ @@ -125,7 +118,9 @@ static void __init mx1ads_init(void) imx1_add_imx_uart1(&uart1_pdata); /* Physmap flash */ - mxc_register_device(&flash_device, &mx1ads_flash_data); + platform_device_register_resndata(NULL, "physmap-flash", 0, + &flash_resource, 1, + &mx1ads_flash_data, sizeof(mx1ads_flash_data)); /* I2C */ i2c_register_board_info(0, mx1ads_i2c_devices, -- cgit v1.2.3 From 47ccfc340aa83e0741d9cabd7f5a3e74659a411d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 31 Jul 2011 00:20:30 +0200 Subject: ARM: imx/armadillo5x0: dynamically allocate physmap-flash device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/mach-imx/mach-armadillo5x0.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c index ede2710f8b76..83e5e3a7b12b 100644 --- a/arch/arm/mach-imx/mach-armadillo5x0.c +++ b/arch/arm/mach-imx/mach-armadillo5x0.c @@ -314,25 +314,19 @@ static struct mtd_partition armadillo5x0_nor_flash_partitions[] = { }, }; -static struct physmap_flash_data armadillo5x0_nor_flash_pdata = { +static const struct physmap_flash_data + armadillo5x0_nor_flash_pdata __initconst = { .width = 2, .parts = armadillo5x0_nor_flash_partitions, .nr_parts = ARRAY_SIZE(armadillo5x0_nor_flash_partitions), }; -static struct resource armadillo5x0_nor_flash_resource = { +static const struct resource armadillo5x0_nor_flash_resource __initconst = { .flags = IORESOURCE_MEM, .start = MX31_CS0_BASE_ADDR, .end = MX31_CS0_BASE_ADDR + SZ_64M - 1, }; -static struct platform_device armadillo5x0_nor_flash = { - .name = "physmap-flash", - .id = -1, - .num_resources = 1, - .resource = &armadillo5x0_nor_flash_resource, -}; - /* * FB support */ @@ -514,8 +508,10 @@ static void __init armadillo5x0_init(void) imx31_add_mx3_sdc_fb(&mx3fb_pdata); /* Register NOR Flash */ - mxc_register_device(&armadillo5x0_nor_flash, - &armadillo5x0_nor_flash_pdata); + platform_device_register_resndata(NULL, "physmap-flash", -1, + &armadillo5x0_nor_flash_resource, 1, + &armadillo5x0_nor_flash_pdata, + sizeof(armadillo5x0_nor_flash_pdata)); /* Register NAND Flash */ imx31_add_mxc_nand(&armadillo5x0_nand_board_info); -- cgit v1.2.3 From 160a84cfc975f4aaec1cb32a48bba23ccaf43761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 1 Aug 2011 10:51:00 +0200 Subject: ARM: mxc: drop now unused function mxc_register_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König --- arch/arm/plat-mxc/devices.c | 14 -------------- arch/arm/plat-mxc/include/mach/common.h | 1 - 2 files changed, 15 deletions(-) diff --git a/arch/arm/plat-mxc/devices.c b/arch/arm/plat-mxc/devices.c index 0d6ed31bdbf2..5aaa8c5f3420 100644 --- a/arch/arm/plat-mxc/devices.c +++ b/arch/arm/plat-mxc/devices.c @@ -23,20 +23,6 @@ #include #include -int __init mxc_register_device(struct platform_device *pdev, void *data) -{ - int ret; - - pdev->dev.platform_data = data; - - ret = platform_device_register(pdev); - if (ret) - pr_debug("Unable to register platform device '%s': %d\n", - pdev->name, ret); - - return ret; -} - struct platform_device *__init imx_add_platform_device_dmamask( const char *name, int id, const struct resource *res, unsigned int num_resources, diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h index 4e3d97890d69..91d810cef6fa 100644 --- a/arch/arm/plat-mxc/include/mach/common.h +++ b/arch/arm/plat-mxc/include/mach/common.h @@ -66,7 +66,6 @@ extern int mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2); extern struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); -extern int mxc_register_device(struct platform_device *pdev, void *data); extern void mxc_set_cpu_type(unsigned int type); extern void mxc_arch_reset_init(void __iomem *); extern void mx51_efikamx_reset(void); -- cgit v1.2.3 From 25032c119e5f43725b624ab30e2ccb8c23b9ebd3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Aug 2011 13:52:48 +0900 Subject: ASoC: Trivial formatting fix in soc-core.c Utterly trivial but it annoys me. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 9d3935bbbd0c..ae93aa81244c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -105,7 +105,7 @@ static int format_register_str(struct snd_soc_codec *codec, if (wordsize + regsize + 2 + 1 != len) return -EINVAL; - ret = snd_soc_read(codec , reg); + ret = snd_soc_read(codec, reg); if (ret < 0) { memset(regbuf, 'X', regsize); regbuf[regsize] = '\0'; -- cgit v1.2.3 From 79ef0abcd85842bc12ffb3297b958565f060464c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Aug 2011 13:02:17 +0900 Subject: ASoC: Implement new DC servo readback mode for late WM8994 revisions Later WM8994 devices implement a new DC servo readback mode with the register used to access the offset moved to register 0x59. Implement support for this and enable it on the appropriate devices. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/linux/mfd/wm8994/registers.h | 1 + sound/soc/codecs/wm8994.c | 3 ++- sound/soc/codecs/wm_hubs.c | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h index f3ee84284670..61529143db57 100644 --- a/include/linux/mfd/wm8994/registers.h +++ b/include/linux/mfd/wm8994/registers.h @@ -72,6 +72,7 @@ #define WM8994_DC_SERVO_2 0x55 #define WM8994_DC_SERVO_4 0x57 #define WM8994_DC_SERVO_READBACK 0x58 +#define WM8994_DC_SERVO_4E 0x59 #define WM8994_ANALOGUE_HP_1 0x60 #define WM8958_MIC_DETECT_1 0xD0 #define WM8958_MIC_DETECT_2 0xD1 diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 09e680ae88b2..c0956899d5b5 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -107,6 +107,7 @@ static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg) case WM8994_LDO_2: case WM8958_DSP2_EXECCONTROL: case WM8958_MIC_DETECT_3: + case WM8994_DC_SERVO_4E: return 1; default: return 0; @@ -2978,7 +2979,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) wm8994->hubs.series_startup = 1; break; default: - wm8994->hubs.dcs_readback_mode = 1; + wm8994->hubs.dcs_readback_mode = 2; break; } diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 4cc2d567f22f..84a84f4eed95 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -116,14 +117,23 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) { struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); s8 offset; - u16 reg, reg_l, reg_r, dcs_cfg; + u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg; + + switch (hubs->dcs_readback_mode) { + case 2: + dcs_reg = WM8994_DC_SERVO_4E; + break; + default: + dcs_reg = WM8993_DC_SERVO_3; + break; + } /* If we're using a digital only path and have a previously * callibrated DC servo offset stored then use that. */ if (hubs->class_w && hubs->class_w_dcs) { dev_dbg(codec->dev, "Using cached DC servo offset %x\n", hubs->class_w_dcs); - snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs); + snd_soc_write(codec, dcs_reg, hubs->class_w_dcs); wait_for_dc_servo(codec, WM8993_DCS_TRIG_DAC_WR_0 | WM8993_DCS_TRIG_DAC_WR_1); @@ -154,8 +164,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2) & WM8993_DCS_INTEG_CHAN_1_MASK; break; + case 2: case 1: - reg = snd_soc_read(codec, WM8993_DC_SERVO_3); + reg = snd_soc_read(codec, dcs_reg); reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; @@ -185,7 +196,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg); /* Do it */ - snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg); + snd_soc_write(codec, dcs_reg, dcs_cfg); wait_for_dc_servo(codec, WM8993_DCS_TRIG_DAC_WR_0 | WM8993_DCS_TRIG_DAC_WR_1); -- cgit v1.2.3 From 4537c4e7618d05c77e9f8c5259c977f927a37e2f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 1 Aug 2011 13:10:16 +0900 Subject: ASoC: Support separate left and right channel dcs_codes values Some devices can have performance optimized by setting different offsets for left and right channels. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8993.c | 3 ++- sound/soc/codecs/wm8994.c | 3 ++- sound/soc/codecs/wm_hubs.c | 13 +++++++------ sound/soc/codecs/wm_hubs.h | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 6e85b8869af7..f014e5676d20 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1433,7 +1433,8 @@ static int wm8993_probe(struct snd_soc_codec *codec) int ret, i, val; wm8993->hubs_data.hp_startup_mode = 1; - wm8993->hubs_data.dcs_codes = -2; + wm8993->hubs_data.dcs_codes_l = -2; + wm8993->hubs_data.dcs_codes_r = -2; wm8993->hubs_data.series_startup = 1; ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c0956899d5b5..fb5c96163610 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2973,7 +2973,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) switch (wm8994->revision) { case 2: case 3: - wm8994->hubs.dcs_codes = -5; + wm8994->hubs.dcs_codes_l = -5; + wm8994->hubs.dcs_codes_r = -5; wm8994->hubs.hp_startup_mode = 1; wm8994->hubs.dcs_readback_mode = 1; wm8994->hubs.series_startup = 1; diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 84a84f4eed95..26e21d01e137 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -179,18 +179,19 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r); /* Apply correction to DC servo result */ - if (hubs->dcs_codes) { - dev_dbg(codec->dev, "Applying %d code DC servo correction\n", - hubs->dcs_codes); + if (hubs->dcs_codes_l || hubs->dcs_codes_r) { + dev_dbg(codec->dev, + "Applying %d/%d code DC servo correction\n", + hubs->dcs_codes_l, hubs->dcs_codes_r); /* HPOUT1R */ offset = reg_r; - offset += hubs->dcs_codes; + offset += hubs->dcs_codes_r; dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; /* HPOUT1L */ offset = reg_l; - offset += hubs->dcs_codes; + offset += hubs->dcs_codes_l; dcs_cfg |= (u8)offset; dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg); @@ -228,7 +229,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, /* If we're applying an offset correction then updating the * callibration would be likely to introduce further offsets. */ - if (hubs->dcs_codes || hubs->no_series_update) + if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update) return ret; /* Only need to do this if the outputs are active */ diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index 676b1252ab91..c674c7a502a6 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h @@ -23,7 +23,8 @@ extern const unsigned int wm_hubs_spkmix_tlv[]; /* This *must* be the first element of the codec->private_data struct */ struct wm_hubs_data { - int dcs_codes; + int dcs_codes_l; + int dcs_codes_r; int dcs_readback_mode; int hp_startup_mode; int series_startup; -- cgit v1.2.3 From c56c5d08e121d103adc026df112ed11ee3a8d1d1 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Mon, 1 Aug 2011 19:41:18 +0800 Subject: ASoC: sgtl5000: add one missed cache reg Signed-off-by: Dong Aisheng Signed-off-by: Zeng Zhaoming Acked-by: Wolfram Sang Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/codecs/sgtl5000.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index cf6eea8b458e..d9f8becafbf6 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -50,6 +50,7 @@ static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] = { 0x0000, /* 0x0016, reserved */ 0x0000, /* 0x0018, reserved */ 0x0000, /* 0x001A, reserved */ + 0x0000, /* 0x001C, reserved */ 0x0000, /* 0x001E, reserved */ 0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */ 0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */ -- cgit v1.2.3 From eaefb38f344d12321cd5372d1c8ad35d264d1b35 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Jul 2011 16:27:18 +0100 Subject: ASoC: Parse board ID/revision information from WM1250-EV1 board The WM1250-EV1 board has an ID chip on it, check the board ID and display the board revision during startup. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm1250-ev1.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index bcc208967917..bbcf9ec34759 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -56,8 +56,26 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = { }; static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) + const struct i2c_device_id *i2c_id) { + int ret, id, board, rev; + + board = i2c_smbus_read_byte_data(i2c, 0); + if (board < 0) { + dev_err(&i2c->dev, "Failed to read ID: %d\n", ret); + return ret; + } + + id = (board & 0xfe) >> 2; + rev = board & 0x3; + + if (id != 1) { + dev_err(&i2c->dev, "Unknown board ID %d\n", id); + return -ENODEV; + } + + dev_info(&i2c->dev, "revision %d\n", rev); + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1, &wm1250_ev1_dai, 1); } -- cgit v1.2.3 From 9665408eac564374f95cc8a216e9db0aecb17ef5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Aug 2011 13:04:14 +0900 Subject: ASoC: Remove -codec from WM8523 driver name It's redundant to specify it. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8523.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 4fd4d8dca0fc..131200917c56 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -551,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); static struct i2c_driver wm8523_i2c_driver = { .driver = { - .name = "wm8523-codec", + .name = "wm8523", .owner = THIS_MODULE, }, .probe = wm8523_i2c_probe, -- cgit v1.2.3 From 722d0daf2b607a32dad1357bf797e3803484af0a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Aug 2011 13:21:53 +0900 Subject: ASoC: Remove redundant -codec from WM8580 driver name Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- sound/soc/codecs/wm8580.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 4bbc0a79f01e..95ac6651094f 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -943,7 +943,7 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); static struct i2c_driver wm8580_i2c_driver = { .driver = { - .name = "wm8580-codec", + .name = "wm8580", .owner = THIS_MODULE, }, .probe = wm8580_i2c_probe, -- cgit v1.2.3 From 11205bb63e5c2e5174f377595103005b00c68370 Mon Sep 17 00:00:00 2001 From: Amy Maloche Date: Mon, 1 Aug 2011 23:41:44 -0700 Subject: Input: add support for pm8xxx based vibrator driver Add support for pm8xx based vibrator to facilitate haptics. This module uses the ff-memless framework. Signed-off-by: Amy Maloche Signed-off-by: Anirudh Ghayal Reviewed-by: Wanlong Gao Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 34 ++-- drivers/input/misc/Makefile | 3 +- drivers/input/misc/pm8xxx-vibrator.c | 296 +++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+), 12 deletions(-) create mode 100644 drivers/input/misc/pm8xxx-vibrator.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 01344280e145..40bcedafd4ac 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -74,6 +74,29 @@ config INPUT_PCSPKR To compile this driver as a module, choose M here: the module will be called pcspkr. +config INPUT_PM8XXX_VIBRATOR + tristate "Qualcomm PM8XXX vibrator support" + depends on MFD_PM8XXX + select INPUT_FF_MEMLESS + help + This option enables device driver support for the vibrator + on Qualcomm PM8xxx chip. This driver supports ff-memless interface + from input framework. + + To compile this driver as module, choose M here: the + module will be called pm8xxx-vibrator. + +config INPUT_PMIC8XXX_PWRKEY + tristate "PMIC8XXX power key support" + depends on MFD_PM8XXX + help + Say Y here if you want support for the PMIC8XXX power key. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pmic8xxx-pwrkey. + config INPUT_SPARCSPKR tristate "SPARC Speaker support" depends on PCI && SPARC64 @@ -368,17 +391,6 @@ config INPUT_PWM_BEEPER To compile this driver as a module, choose M here: the module will be called pwm-beeper. -config INPUT_PMIC8XXX_PWRKEY - tristate "PMIC8XXX power key support" - depends on MFD_PM8XXX - help - Say Y here if you want support for the PMIC8XXX power key. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pmic8xxx-pwrkey. - config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" depends on GPIOLIB && GENERIC_GPIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index be39d813354d..0caad97e7dd0 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -34,9 +34,10 @@ obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o +obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o +obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o -obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c new file mode 100644 index 000000000000..43192930824b --- /dev/null +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIB_DRV 0x4A + +#define VIB_DRV_SEL_MASK 0xf8 +#define VIB_DRV_SEL_SHIFT 0x03 +#define VIB_DRV_EN_MANUAL_MASK 0xfc + +#define VIB_MAX_LEVEL_mV (3100) +#define VIB_MIN_LEVEL_mV (1200) +#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) + +#define MAX_FF_SPEED 0xff + +/** + * struct pm8xxx_vib - structure to hold vibrator data + * @vib_input_dev: input device supporting force feedback + * @work: work structure to set the vibration parameters + * @dev: device supporting force feedback + * @speed: speed of vibration set from userland + * @active: state of vibrator + * @level: level of vibration to set in the chip + * @reg_vib_drv: VIB_DRV register value + */ +struct pm8xxx_vib { + struct input_dev *vib_input_dev; + struct work_struct work; + struct device *dev; + int speed; + int level; + bool active; + u8 reg_vib_drv; +}; + +/** + * pm8xxx_vib_read_u8 - helper to read a byte from pmic chip + * @vib: pointer to vibrator structure + * @data: placeholder for data to be read + * @reg: register address + */ +static int pm8xxx_vib_read_u8(struct pm8xxx_vib *vib, + u8 *data, u16 reg) +{ + int rc; + + rc = pm8xxx_readb(vib->dev->parent, reg, data); + if (rc < 0) + dev_warn(vib->dev, "Error reading pm8xxx reg 0x%x(0x%x)\n", + reg, rc); + return rc; +} + +/** + * pm8xxx_vib_write_u8 - helper to write a byte to pmic chip + * @vib: pointer to vibrator structure + * @data: data to write + * @reg: register address + */ +static int pm8xxx_vib_write_u8(struct pm8xxx_vib *vib, + u8 data, u16 reg) +{ + int rc; + + rc = pm8xxx_writeb(vib->dev->parent, reg, data); + if (rc < 0) + dev_warn(vib->dev, "Error writing pm8xxx reg 0x%x(0x%x)\n", + reg, rc); + return rc; +} + +/** + * pm8xxx_vib_set - handler to start/stop vibration + * @vib: pointer to vibrator structure + * @on: state to set + */ +static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) +{ + int rc; + u8 val = vib->reg_vib_drv; + + if (on) + val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); + else + val &= ~VIB_DRV_SEL_MASK; + + rc = pm8xxx_vib_write_u8(vib, val, VIB_DRV); + if (rc < 0) + return rc; + + vib->reg_vib_drv = val; + return 0; +} + +/** + * pm8xxx_work_handler - worker to set vibration level + * @work: pointer to work_struct + */ +static void pm8xxx_work_handler(struct work_struct *work) +{ + struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); + int rc; + u8 val; + + rc = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); + if (rc < 0) + return; + + /* + * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so + * scale the level to fit into these ranges. + */ + if (vib->speed) { + vib->active = true; + vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + + VIB_MIN_LEVEL_mV; + vib->level /= 100; + } else { + vib->active = false; + vib->level = VIB_MIN_LEVEL_mV / 100; + } + + pm8xxx_vib_set(vib, vib->active); +} + +/** + * pm8xxx_vib_close - callback of input close callback + * @dev: input device pointer + * + * Turns off the vibrator. + */ +static void pm8xxx_vib_close(struct input_dev *dev) +{ + struct pm8xxx_vib *vib = input_get_drvdata(dev); + + cancel_work_sync(&vib->work); + if (vib->active) + pm8xxx_vib_set(vib, false); +} + +/** + * pm8xxx_vib_play_effect - function to handle vib effects. + * @dev: input device pointer + * @data: data of effect + * @effect: effect to play + * + * Currently this driver supports only rumble effects. + */ +static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct pm8xxx_vib *vib = input_get_drvdata(dev); + + vib->speed = effect->u.rumble.strong_magnitude >> 8; + if (!vib->speed) + vib->speed = effect->u.rumble.weak_magnitude >> 9; + + schedule_work(&vib->work); + + return 0; +} + +static int __devinit pm8xxx_vib_probe(struct platform_device *pdev) + +{ + struct pm8xxx_vib *vib; + struct input_dev *input_dev; + int error; + u8 val; + + vib = kzalloc(sizeof(*vib), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!vib || !input_dev) { + dev_err(&pdev->dev, "couldn't allocate memory\n"); + error = -ENOMEM; + goto err_free_mem; + } + + INIT_WORK(&vib->work, pm8xxx_work_handler); + vib->dev = &pdev->dev; + vib->vib_input_dev = input_dev; + + /* operate in manual mode */ + error = pm8xxx_vib_read_u8(vib, &val, VIB_DRV); + if (error < 0) + goto err_free_mem; + val &= ~VIB_DRV_EN_MANUAL_MASK; + error = pm8xxx_vib_write_u8(vib, val, VIB_DRV); + if (error < 0) + goto err_free_mem; + + vib->reg_vib_drv = val; + + input_dev->name = "pm8xxx_vib_ffmemless"; + input_dev->id.version = 1; + input_dev->dev.parent = &pdev->dev; + input_dev->close = pm8xxx_vib_close; + input_set_drvdata(input_dev, vib); + input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); + + error = input_ff_create_memless(input_dev, NULL, + pm8xxx_vib_play_effect); + if (error) { + dev_err(&pdev->dev, + "couldn't register vibrator as FF device\n"); + goto err_free_mem; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&pdev->dev, "couldn't register input device\n"); + goto err_destroy_memless; + } + + platform_set_drvdata(pdev, vib); + return 0; + +err_destroy_memless: + input_ff_destroy(input_dev); +err_free_mem: + input_free_device(input_dev); + kfree(vib); + + return error; +} + +static int __devexit pm8xxx_vib_remove(struct platform_device *pdev) +{ + struct pm8xxx_vib *vib = platform_get_drvdata(pdev); + + input_unregister_device(vib->vib_input_dev); + kfree(vib); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pm8xxx_vib_suspend(struct device *dev) +{ + struct pm8xxx_vib *vib = dev_get_drvdata(dev); + + /* Turn off the vibrator */ + pm8xxx_vib_set(vib, false); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); + +static struct platform_driver pm8xxx_vib_driver = { + .probe = pm8xxx_vib_probe, + .remove = __devexit_p(pm8xxx_vib_remove), + .driver = { + .name = "pm8xxx-vib", + .owner = THIS_MODULE, + .pm = &pm8xxx_vib_pm_ops, + }, +}; + +static int __init pm8xxx_vib_init(void) +{ + return platform_driver_register(&pm8xxx_vib_driver); +} +module_init(pm8xxx_vib_init); + +static void __exit pm8xxx_vib_exit(void) +{ + platform_driver_unregister(&pm8xxx_vib_driver); +} +module_exit(pm8xxx_vib_exit); + +MODULE_ALIAS("platform:pm8xxx_vib"); +MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Amy Maloche "); -- cgit v1.2.3 From c39cc377f9168e24d58f82419af9595226fdc4ff Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Wed, 3 Aug 2011 14:07:11 +0800 Subject: crypto: padlock-aes - Make module loading even quieter when hardware is missing When loading aes via the module alias, a padlock module failing to load due to missing hardware is not particularly notable. With v2.6.27-rc1~1107^2~14 (crypto: padlock - Make module loading quieter when hardware isn't available, 2008-07-03), the padlock-aes module suppresses the relevant messages when the "quiet" flag is in use; but better to suppress this particular message completely, since the administrator can already distinguish such errors by the absence of a message indicating initialization failing or succeeding. This avoids occasional messages in syslog of the form padlock_aes: VIA PadLock not detected. Signed-off-by: Jonathan Nieder Signed-off-by: Herbert Xu --- drivers/crypto/padlock-aes.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c index db33d300aa23..29b9469f8378 100644 --- a/drivers/crypto/padlock-aes.c +++ b/drivers/crypto/padlock-aes.c @@ -508,10 +508,8 @@ static int __init padlock_init(void) int ret; struct cpuinfo_x86 *c = &cpu_data(0); - if (!cpu_has_xcrypt) { - printk(KERN_NOTICE PFX "VIA PadLock not detected.\n"); + if (!cpu_has_xcrypt) return -ENODEV; - } if (!cpu_has_xcrypt_enabled) { printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n"); -- cgit v1.2.3 From d66fee5d65d947da32783ab0c32511ffe55ff5f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 2 Aug 2011 15:39:31 +0200 Subject: ALSA: hda - Add basic tracepoints Add a few tracepoints to HD-audio driver. Signed-off-by: Takashi Iwai --- sound/pci/hda/Makefile | 3 ++ sound/pci/hda/hda_codec.c | 11 +++++- sound/pci/hda/hda_trace.h | 95 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 sound/pci/hda/hda_trace.h diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 87365d5ea2a9..f928d6634723 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -6,6 +6,9 @@ snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o +# for trace-points +CFLAGS_hda_codec.o := -I$(src) + snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 3e7850c238c3..e105b653130d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -34,6 +34,9 @@ #include "hda_beep.h" #include +#define CREATE_TRACE_POINTS +#include "hda_trace.h" + /* * vendor / preset table */ @@ -208,15 +211,19 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, again: snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); + trace_hda_send_cmd(codec, cmd); err = bus->ops.command(bus, cmd); - if (!err && res) + if (!err && res) { *res = bus->ops.get_response(bus, codec->addr); + trace_hda_get_response(codec, *res); + } mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); if (res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { snd_printd("hda_codec: resetting BUS due to " "fatal communication error\n"); + trace_hda_bus_reset(bus); bus->ops.bus_reset(bus); } goto again; @@ -4083,6 +4090,7 @@ static void hda_power_work(struct work_struct *work) return; } + trace_hda_power_down(codec); hda_call_codec_suspend(codec); if (bus->ops.pm_notify) bus->ops.pm_notify(bus); @@ -4121,6 +4129,7 @@ void snd_hda_power_up(struct hda_codec *codec) if (codec->power_on || codec->power_transition) return; + trace_hda_power_up(codec); snd_hda_update_power_acct(codec); codec->power_on = 1; codec->power_jiffies = jiffies; diff --git a/sound/pci/hda/hda_trace.h b/sound/pci/hda/hda_trace.h new file mode 100644 index 000000000000..b446cfcf60de --- /dev/null +++ b/sound/pci/hda/hda_trace.h @@ -0,0 +1,95 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hda +#define TRACE_INCLUDE_FILE hda_trace + +#if !defined(_TRACE_HDA_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HDA_H + +#include + +struct hda_bus; +struct hda_codec; + +DECLARE_EVENT_CLASS(hda_cmd, + + TP_PROTO(struct hda_codec *codec, unsigned int val), + + TP_ARGS(codec, val), + + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, addr ) + __field( unsigned int, val ) + ), + + TP_fast_assign( + __entry->card = (codec)->bus->card->number; + __entry->addr = (codec)->addr; + __entry->val = (val); + ), + + TP_printk("[%d:%d] val=%x", __entry->card, __entry->addr, __entry->val) +); + +DEFINE_EVENT(hda_cmd, hda_send_cmd, + TP_PROTO(struct hda_codec *codec, unsigned int val), + TP_ARGS(codec, val) +); + +DEFINE_EVENT(hda_cmd, hda_get_response, + TP_PROTO(struct hda_codec *codec, unsigned int val), + TP_ARGS(codec, val) +); + +TRACE_EVENT(hda_bus_reset, + + TP_PROTO(struct hda_bus *bus), + + TP_ARGS(bus), + + TP_STRUCT__entry( + __field( unsigned int, card ) + ), + + TP_fast_assign( + __entry->card = (bus)->card->number; + ), + + TP_printk("[%d]", __entry->card) +); + +DECLARE_EVENT_CLASS(hda_power, + + TP_PROTO(struct hda_codec *codec), + + TP_ARGS(codec), + + TP_STRUCT__entry( + __field( unsigned int, card ) + __field( unsigned int, addr ) + ), + + TP_fast_assign( + __entry->card = (codec)->bus->card->number; + __entry->addr = (codec)->addr; + ), + + TP_printk("[%d:%d]", __entry->card, __entry->addr) +); + +DEFINE_EVENT(hda_power, hda_power_down, + TP_PROTO(struct hda_codec *codec), + TP_ARGS(codec) +); + +DEFINE_EVENT(hda_power, hda_power_up, + TP_PROTO(struct hda_codec *codec), + TP_ARGS(codec) +); + +#endif /* _TRACE_HDA_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include -- cgit v1.2.3 From 2ae66c26550cd94b0e2606a9275eb0ab7070ad0e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Thu, 4 Aug 2011 10:12:56 -0500 Subject: ALSA: hda: option to enable arbitrary buffer/period sizes Add new parameter to disable rounding of buffer/period sizes to multiples of 128 bytes. This is more efficient in terms of memory access but isn't required by the HDA spec and prevents users from specifying exact period/buffer sizes. For example for 44.1kHz, a period size set to 20ms will be rounded to 19.59ms. Tested and enabled on Intel HDA controllers. Option is disabled by default for other controllers. Tested-by: Wu Fengguang Signed-off-by: Pierre-Louis Bossart Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 5 ++ sound/pci/hda/hda_intel.c | 68 +++++++++++++++++++------ 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 89757012c7ff..27126c469f70 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -886,6 +886,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. disable) power_save_controller - Reset HD-audio controller in power-saving mode (default = on) + align_buffer_size - Force rounding of buffer/period sizes to multiples + of 128 bytes. This is more efficient in terms of memory + access but isn't required by the HDA spec and prevents + users from specifying exact period/buffer sizes. + (default = on) This module supports multiple cards and autoprobe. diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index be6982289c0d..2a8bed94d4fa 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -116,6 +116,11 @@ module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); #endif +static int align_buffer_size = 1; +module_param(align_buffer_size, bool, 0644); +MODULE_PARM_DESC(align_buffer_size, + "Force buffer and period sizes to be multiple of 128 bytes."); + MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, ICH6M}," @@ -481,6 +486,7 @@ enum { #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ +#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -1599,6 +1605,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; unsigned long flags; int err; + int buff_step; mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); @@ -1613,10 +1620,25 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) runtime->hw.rates = hinfo->rates; snd_pcm_limit_hw_rates(runtime); snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (align_buffer_size) + /* constrain buffer sizes to be multiple of 128 + bytes. This is more efficient in terms of memory + access but isn't required by the HDA spec and + prevents users from specifying exact period/buffer + sizes. For example for 44.1kHz, a period size set + to 20ms will be rounded to 19.59ms. */ + buff_step = 128; + else + /* Don't enforce steps on buffer sizes, still need to + be multiple of 4 bytes (HDA spec). Tested on Intel + HDA controllers, may not work on all devices where + option needs to be disabled */ + buff_step = 4; + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - 128); + buff_step); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - 128); + buff_step); snd_hda_power_up(apcm->codec); err = hinfo->ops.open(hinfo, apcm->codec, substream); if (err < 0) { @@ -2616,6 +2638,10 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, gcap &= ~ICH6_GCAP_64OK; } + /* disable buffer size rounding to 128-byte multiples if supported */ + if (chip->driver_caps & AZX_DCAPS_BUFSIZE) + align_buffer_size = 0; + /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); @@ -2817,37 +2843,49 @@ static void __devexit azx_remove(struct pci_dev *pci) static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, /* SCH */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | + AZX_DCAPS_BUFSIZE}, { PCI_DEVICE(0x8086, 0x2668), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH6 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH6 */ { PCI_DEVICE(0x8086, 0x27d8), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH7 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH7 */ { PCI_DEVICE(0x8086, 0x269a), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ESB2 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ESB2 */ { PCI_DEVICE(0x8086, 0x284b), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH8 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH8 */ { PCI_DEVICE(0x8086, 0x293e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x293f), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH9 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH9 */ { PCI_DEVICE(0x8086, 0x3a3e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH10 */ { PCI_DEVICE(0x8086, 0x3a6e), - .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC }, /* ICH10 */ + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | + AZX_DCAPS_BUFSIZE }, /* ICH10 */ /* Generic Intel */ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, - .driver_data = AZX_DRIVER_ICH }, + .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE }, /* ATI SB 450/600/700/800/900 */ { PCI_DEVICE(0x1002, 0x437b), .driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB }, -- cgit v1.2.3 From d11b7fa3d5b6d4b3a730f563e7b14dfc859c40c6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 5 Aug 2011 12:49:46 +0200 Subject: ALSA: hda - Add documentation for tracepoints Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index c82beb007634..ba2a155f3a30 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -524,6 +524,53 @@ power-saving. See /sys/module/snd_hda_intel/parameters/power_save to check the current value. If it's non-zero, the feature is turned on. +Tracepoints +~~~~~~~~~~~ +The hd-audio driver gives a few basic tracepoints. +`hda:hda_send_cmd` traces each CORB write while `hda:hda_get_response` +traces the response from RIRB (only when read from the codec driver). +`hda:hda_bus_reset` traces the bus-reset due to fatal error, etc, and +`hda:hda_power_down` and `hda:hda_power_up` trace the power down/up +via power-saving behavior. + +Enabling all tracepoints can be done like +------------------------------------------------------------------------ + # echo 1 > /sys/kernel/debug/tracing/events/hda/enable +------------------------------------------------------------------------ +then after some commands, you can traces from +/sys/kernel/debug/tracing/trace file. For example, when you want to +trace what codec command is sent, enable the tracepoint like: +------------------------------------------------------------------------ + # cat /sys/kernel/debug/tracing/trace + # tracer: nop + # + # TASK-PID CPU# TIMESTAMP FUNCTION + # | | | | | + <...>-7807 [002] 105147.774889: hda_send_cmd: [0:0] val=e3a019 + <...>-7807 [002] 105147.774893: hda_send_cmd: [0:0] val=e39019 + <...>-7807 [002] 105147.999542: hda_send_cmd: [0:0] val=e3a01a + <...>-7807 [002] 105147.999543: hda_send_cmd: [0:0] val=e3901a + <...>-26764 [001] 349222.837143: hda_send_cmd: [0:0] val=e3a019 + <...>-26764 [001] 349222.837148: hda_send_cmd: [0:0] val=e39019 + <...>-26764 [001] 349223.058539: hda_send_cmd: [0:0] val=e3a01a + <...>-26764 [001] 349223.058541: hda_send_cmd: [0:0] val=e3901a +------------------------------------------------------------------------ +Here `[0:0]` indicates the card number and the codec address, and +`val` shows the value sent to the codec, respectively. The value is +a packed value, and you can decode it via hda-decode-verb program +included in hda-emu package below. For example, the value e3a019 is +to set the left output-amp value to 25. +------------------------------------------------------------------------ + % hda-decode-verb 0xe3a019 + raw value = 0x00e3a019 + cid = 0, nid = 0x0e, verb = 0x3a0, parm = 0x19 + raw value: verb = 0x3a0, parm = 0x19 + verbname = set_amp_gain_mute + amp raw val = 0xa019 + output, left, idx=0, mute=0, val=25 +------------------------------------------------------------------------ + + Development Tree ~~~~~~~~~~~~~~~~ The latest development codes for HD-audio are found on sound git tree: -- cgit v1.2.3 From d60defb7b2c05b5c4b187171c09b714b0a00efe9 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 21 May 2011 22:46:31 +0000 Subject: viafb: use more compact modesetting functions This patch replaces the old timing setup code with a redesigned one. The new code might be slightly faster as it has no conditinals and does not write the same register multiple times. Also it makes the comparison to the documentation easier. Regressions are unlikely but could happen as a lot of hardware is undocumented. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 296 +----------------------------------- drivers/video/via/hw.h | 273 --------------------------------- drivers/video/via/share.h | 19 +-- drivers/video/via/via_modesetting.c | 100 ++++++++++++ drivers/video/via/via_modesetting.h | 18 +++ 5 files changed, 128 insertions(+), 578 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 47b13535ed2b..372ce4f071c2 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -191,67 +191,6 @@ static struct fetch_count fetch_count_reg = { {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } } }; -static struct iga1_crtc_timing iga1_crtc_reg = { - /* IGA1 Horizontal Total */ - {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } }, - /* IGA1 Horizontal Addressable Video */ - {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } }, - /* IGA1 Horizontal Blank Start */ - {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } }, - /* IGA1 Horizontal Blank End */ - {IGA1_HOR_BLANK_END_REG_NUM, - {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } }, - /* IGA1 Horizontal Sync Start */ - {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } }, - /* IGA1 Horizontal Sync End */ - {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } }, - /* IGA1 Vertical Total */ - {IGA1_VER_TOTAL_REG_NUM, - {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } }, - /* IGA1 Vertical Addressable Video */ - {IGA1_VER_ADDR_REG_NUM, - {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } }, - /* IGA1 Vertical Blank Start */ - {IGA1_VER_BLANK_START_REG_NUM, - {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } }, - /* IGA1 Vertical Blank End */ - {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } }, - /* IGA1 Vertical Sync Start */ - {IGA1_VER_SYNC_START_REG_NUM, - {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } }, - /* IGA1 Vertical Sync End */ - {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } } -}; - -static struct iga2_crtc_timing iga2_crtc_reg = { - /* IGA2 Horizontal Total */ - {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } }, - /* IGA2 Horizontal Addressable Video */ - {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } }, - /* IGA2 Horizontal Blank Start */ - {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } }, - /* IGA2 Horizontal Blank End */ - {IGA2_HOR_BLANK_END_REG_NUM, - {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } }, - /* IGA2 Horizontal Sync Start */ - {IGA2_HOR_SYNC_START_REG_NUM, - {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } }, - /* IGA2 Horizontal Sync End */ - {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } }, - /* IGA2 Vertical Total */ - {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } }, - /* IGA2 Vertical Addressable Video */ - {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } }, - /* IGA2 Vertical Blank Start */ - {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } }, - /* IGA2 Vertical Blank End */ - {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } }, - /* IGA2 Vertical Sync Start */ - {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } }, - /* IGA2 Vertical Sync End */ - {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } } -}; - static struct rgbLUT palLUT_table[] = { /* {R,G,B} */ /* Index 0x00~0x03 */ @@ -1531,234 +1470,15 @@ void viafb_set_vclock(u32 clk, int set_iga) void viafb_load_crtc_timing(struct display_timing device_timing, int set_iga) { - int i; - int viafb_load_reg_num = 0; - int reg_value = 0; - struct io_register *reg = NULL; - - viafb_unlock_crt(); - - for (i = 0; i < 12; i++) { - if (set_iga == IGA1) { - switch (i) { - case H_TOTAL_INDEX: - reg_value = - IGA1_HOR_TOTAL_FORMULA(device_timing. - hor_total); - viafb_load_reg_num = - iga1_crtc_reg.hor_total.reg_num; - reg = iga1_crtc_reg.hor_total.reg; - break; - case H_ADDR_INDEX: - reg_value = - IGA1_HOR_ADDR_FORMULA(device_timing. - hor_addr); - viafb_load_reg_num = - iga1_crtc_reg.hor_addr.reg_num; - reg = iga1_crtc_reg.hor_addr.reg; - break; - case H_BLANK_START_INDEX: - reg_value = - IGA1_HOR_BLANK_START_FORMULA - (device_timing.hor_blank_start); - viafb_load_reg_num = - iga1_crtc_reg.hor_blank_start.reg_num; - reg = iga1_crtc_reg.hor_blank_start.reg; - break; - case H_BLANK_END_INDEX: - reg_value = - IGA1_HOR_BLANK_END_FORMULA - (device_timing.hor_blank_start, - device_timing.hor_blank_end); - viafb_load_reg_num = - iga1_crtc_reg.hor_blank_end.reg_num; - reg = iga1_crtc_reg.hor_blank_end.reg; - break; - case H_SYNC_START_INDEX: - reg_value = - IGA1_HOR_SYNC_START_FORMULA - (device_timing.hor_sync_start); - viafb_load_reg_num = - iga1_crtc_reg.hor_sync_start.reg_num; - reg = iga1_crtc_reg.hor_sync_start.reg; - break; - case H_SYNC_END_INDEX: - reg_value = - IGA1_HOR_SYNC_END_FORMULA - (device_timing.hor_sync_start, - device_timing.hor_sync_end); - viafb_load_reg_num = - iga1_crtc_reg.hor_sync_end.reg_num; - reg = iga1_crtc_reg.hor_sync_end.reg; - break; - case V_TOTAL_INDEX: - reg_value = - IGA1_VER_TOTAL_FORMULA(device_timing. - ver_total); - viafb_load_reg_num = - iga1_crtc_reg.ver_total.reg_num; - reg = iga1_crtc_reg.ver_total.reg; - break; - case V_ADDR_INDEX: - reg_value = - IGA1_VER_ADDR_FORMULA(device_timing. - ver_addr); - viafb_load_reg_num = - iga1_crtc_reg.ver_addr.reg_num; - reg = iga1_crtc_reg.ver_addr.reg; - break; - case V_BLANK_START_INDEX: - reg_value = - IGA1_VER_BLANK_START_FORMULA - (device_timing.ver_blank_start); - viafb_load_reg_num = - iga1_crtc_reg.ver_blank_start.reg_num; - reg = iga1_crtc_reg.ver_blank_start.reg; - break; - case V_BLANK_END_INDEX: - reg_value = - IGA1_VER_BLANK_END_FORMULA - (device_timing.ver_blank_start, - device_timing.ver_blank_end); - viafb_load_reg_num = - iga1_crtc_reg.ver_blank_end.reg_num; - reg = iga1_crtc_reg.ver_blank_end.reg; - break; - case V_SYNC_START_INDEX: - reg_value = - IGA1_VER_SYNC_START_FORMULA - (device_timing.ver_sync_start); - viafb_load_reg_num = - iga1_crtc_reg.ver_sync_start.reg_num; - reg = iga1_crtc_reg.ver_sync_start.reg; - break; - case V_SYNC_END_INDEX: - reg_value = - IGA1_VER_SYNC_END_FORMULA - (device_timing.ver_sync_start, - device_timing.ver_sync_end); - viafb_load_reg_num = - iga1_crtc_reg.ver_sync_end.reg_num; - reg = iga1_crtc_reg.ver_sync_end.reg; - break; - - } - } - - if (set_iga == IGA2) { - switch (i) { - case H_TOTAL_INDEX: - reg_value = - IGA2_HOR_TOTAL_FORMULA(device_timing. - hor_total); - viafb_load_reg_num = - iga2_crtc_reg.hor_total.reg_num; - reg = iga2_crtc_reg.hor_total.reg; - break; - case H_ADDR_INDEX: - reg_value = - IGA2_HOR_ADDR_FORMULA(device_timing. - hor_addr); - viafb_load_reg_num = - iga2_crtc_reg.hor_addr.reg_num; - reg = iga2_crtc_reg.hor_addr.reg; - break; - case H_BLANK_START_INDEX: - reg_value = - IGA2_HOR_BLANK_START_FORMULA - (device_timing.hor_blank_start); - viafb_load_reg_num = - iga2_crtc_reg.hor_blank_start.reg_num; - reg = iga2_crtc_reg.hor_blank_start.reg; - break; - case H_BLANK_END_INDEX: - reg_value = - IGA2_HOR_BLANK_END_FORMULA - (device_timing.hor_blank_start, - device_timing.hor_blank_end); - viafb_load_reg_num = - iga2_crtc_reg.hor_blank_end.reg_num; - reg = iga2_crtc_reg.hor_blank_end.reg; - break; - case H_SYNC_START_INDEX: - reg_value = - IGA2_HOR_SYNC_START_FORMULA - (device_timing.hor_sync_start); - if (UNICHROME_CN700 <= - viaparinfo->chip_info->gfx_chip_name) - viafb_load_reg_num = - iga2_crtc_reg.hor_sync_start. - reg_num; - else - viafb_load_reg_num = 3; - reg = iga2_crtc_reg.hor_sync_start.reg; - break; - case H_SYNC_END_INDEX: - reg_value = - IGA2_HOR_SYNC_END_FORMULA - (device_timing.hor_sync_start, - device_timing.hor_sync_end); - viafb_load_reg_num = - iga2_crtc_reg.hor_sync_end.reg_num; - reg = iga2_crtc_reg.hor_sync_end.reg; - break; - case V_TOTAL_INDEX: - reg_value = - IGA2_VER_TOTAL_FORMULA(device_timing. - ver_total); - viafb_load_reg_num = - iga2_crtc_reg.ver_total.reg_num; - reg = iga2_crtc_reg.ver_total.reg; - break; - case V_ADDR_INDEX: - reg_value = - IGA2_VER_ADDR_FORMULA(device_timing. - ver_addr); - viafb_load_reg_num = - iga2_crtc_reg.ver_addr.reg_num; - reg = iga2_crtc_reg.ver_addr.reg; - break; - case V_BLANK_START_INDEX: - reg_value = - IGA2_VER_BLANK_START_FORMULA - (device_timing.ver_blank_start); - viafb_load_reg_num = - iga2_crtc_reg.ver_blank_start.reg_num; - reg = iga2_crtc_reg.ver_blank_start.reg; - break; - case V_BLANK_END_INDEX: - reg_value = - IGA2_VER_BLANK_END_FORMULA - (device_timing.ver_blank_start, - device_timing.ver_blank_end); - viafb_load_reg_num = - iga2_crtc_reg.ver_blank_end.reg_num; - reg = iga2_crtc_reg.ver_blank_end.reg; - break; - case V_SYNC_START_INDEX: - reg_value = - IGA2_VER_SYNC_START_FORMULA - (device_timing.ver_sync_start); - viafb_load_reg_num = - iga2_crtc_reg.ver_sync_start.reg_num; - reg = iga2_crtc_reg.ver_sync_start.reg; - break; - case V_SYNC_END_INDEX: - reg_value = - IGA2_VER_SYNC_END_FORMULA - (device_timing.ver_sync_start, - device_timing.ver_sync_end); - viafb_load_reg_num = - iga2_crtc_reg.ver_sync_end.reg_num; - reg = iga2_crtc_reg.ver_sync_end.reg; - break; + device_timing.hor_blank_end += device_timing.hor_blank_start; + device_timing.hor_sync_end += device_timing.hor_sync_start; + device_timing.ver_blank_end += device_timing.ver_blank_start; + device_timing.ver_sync_end += device_timing.ver_sync_start; - } - } - viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR); - } - - viafb_lock_crt(); + if (set_iga == IGA1) + via_set_primary_timing(&device_timing); + else if (set_iga == IGA2) + via_set_secondary_timing(&device_timing); } void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index c7239eb83bae..267c669be736 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -51,40 +51,6 @@ #define VIA_HSYNC_NEGATIVE 0x01 #define VIA_VSYNC_NEGATIVE 0x02 -/*************************************************** -* Definition IGA1 Design Method of CRTC Registers * -****************************************************/ -#define IGA1_HOR_TOTAL_FORMULA(x) (((x)/8)-5) -#define IGA1_HOR_ADDR_FORMULA(x) (((x)/8)-1) -#define IGA1_HOR_BLANK_START_FORMULA(x) (((x)/8)-1) -#define IGA1_HOR_BLANK_END_FORMULA(x, y) (((x+y)/8)-1) -#define IGA1_HOR_SYNC_START_FORMULA(x) ((x)/8) -#define IGA1_HOR_SYNC_END_FORMULA(x, y) ((x+y)/8) - -#define IGA1_VER_TOTAL_FORMULA(x) ((x)-2) -#define IGA1_VER_ADDR_FORMULA(x) ((x)-1) -#define IGA1_VER_BLANK_START_FORMULA(x) ((x)-1) -#define IGA1_VER_BLANK_END_FORMULA(x, y) ((x+y)-1) -#define IGA1_VER_SYNC_START_FORMULA(x) ((x)-1) -#define IGA1_VER_SYNC_END_FORMULA(x, y) ((x+y)-1) - -/*************************************************** -** Definition IGA2 Design Method of CRTC Registers * -****************************************************/ -#define IGA2_HOR_TOTAL_FORMULA(x) ((x)-1) -#define IGA2_HOR_ADDR_FORMULA(x) ((x)-1) -#define IGA2_HOR_BLANK_START_FORMULA(x) ((x)-1) -#define IGA2_HOR_BLANK_END_FORMULA(x, y) ((x+y)-1) -#define IGA2_HOR_SYNC_START_FORMULA(x) ((x)-1) -#define IGA2_HOR_SYNC_END_FORMULA(x, y) ((x+y)-1) - -#define IGA2_VER_TOTAL_FORMULA(x) ((x)-1) -#define IGA2_VER_ADDR_FORMULA(x) ((x)-1) -#define IGA2_VER_BLANK_START_FORMULA(x) ((x)-1) -#define IGA2_VER_BLANK_END_FORMULA(x, y) ((x+y)-1) -#define IGA2_VER_SYNC_START_FORMULA(x) ((x)-1) -#define IGA2_VER_SYNC_END_FORMULA(x, y) ((x+y)-1) - /**********************************************************/ /* Definition IGA2 Design Method of CRTC Shadow Registers */ /**********************************************************/ @@ -97,33 +63,6 @@ #define IGA2_VER_SYNC_START_SHADOW_FORMULA(x) (x) #define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y) (x+y) -/* Define Register Number for IGA1 CRTC Timing */ - -/* location: {CR00,0,7},{CR36,3,3} */ -#define IGA1_HOR_TOTAL_REG_NUM 2 -/* location: {CR01,0,7} */ -#define IGA1_HOR_ADDR_REG_NUM 1 -/* location: {CR02,0,7} */ -#define IGA1_HOR_BLANK_START_REG_NUM 1 -/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */ -#define IGA1_HOR_BLANK_END_REG_NUM 3 -/* location: {CR04,0,7},{CR33,4,4} */ -#define IGA1_HOR_SYNC_START_REG_NUM 2 -/* location: {CR05,0,4} */ -#define IGA1_HOR_SYNC_END_REG_NUM 1 -/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */ -#define IGA1_VER_TOTAL_REG_NUM 4 -/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */ -#define IGA1_VER_ADDR_REG_NUM 4 -/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */ -#define IGA1_VER_BLANK_START_REG_NUM 4 -/* location: {CR16,0,7} */ -#define IGA1_VER_BLANK_END_REG_NUM 1 -/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */ -#define IGA1_VER_SYNC_START_REG_NUM 4 -/* location: {CR11,0,3} */ -#define IGA1_VER_SYNC_END_REG_NUM 1 - /* Define Register Number for IGA2 Shadow CRTC Timing */ /* location: {CR6D,0,7},{CR71,3,3} */ @@ -143,37 +82,6 @@ /* location: {CR76,0,3} */ #define IGA2_SHADOW_VER_SYNC_END_REG_NUM 1 -/* Define Register Number for IGA2 CRTC Timing */ - -/* location: {CR50,0,7},{CR55,0,3} */ -#define IGA2_HOR_TOTAL_REG_NUM 2 -/* location: {CR51,0,7},{CR55,4,6} */ -#define IGA2_HOR_ADDR_REG_NUM 2 -/* location: {CR52,0,7},{CR54,0,2} */ -#define IGA2_HOR_BLANK_START_REG_NUM 2 -/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6] -is reserved, so it may have problem to set 1600x1200 on IGA2. */ -/* Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */ -#define IGA2_HOR_BLANK_END_REG_NUM 3 -/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */ -/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */ -#define IGA2_HOR_SYNC_START_REG_NUM 4 - -/* location: {CR57,0,7},{CR5C,6,6} */ -#define IGA2_HOR_SYNC_END_REG_NUM 2 -/* location: {CR58,0,7},{CR5D,0,2} */ -#define IGA2_VER_TOTAL_REG_NUM 2 -/* location: {CR59,0,7},{CR5D,3,5} */ -#define IGA2_VER_ADDR_REG_NUM 2 -/* location: {CR5A,0,7},{CR5C,0,2} */ -#define IGA2_VER_BLANK_START_REG_NUM 2 -/* location: {CR5E,0,7},{CR5C,3,5} */ -#define IGA2_VER_BLANK_END_REG_NUM 2 -/* location: {CR5E,0,7},{CR5F,5,7} */ -#define IGA2_VER_SYNC_START_REG_NUM 2 -/* location: {CR5F,0,4} */ -#define IGA2_VER_SYNC_END_REG_NUM 1 - /* Define Fetch Count Register*/ /* location: {SR1C,0,7},{SR1D,0,1} */ @@ -446,87 +354,12 @@ is reserved, so it may have problem to set 1600x1200 on IGA2. */ /* location: {CR78,0,7},{CR79,6,7} */ #define LCD_VER_SCALING_FACTOR_REG_NUM_CLE 2 -/************************************************ - ***** Define IGA1 Display Timing ***** - ************************************************/ struct io_register { u8 io_addr; u8 start_bit; u8 end_bit; }; -/* IGA1 Horizontal Total */ -struct iga1_hor_total { - int reg_num; - struct io_register reg[IGA1_HOR_TOTAL_REG_NUM]; -}; - -/* IGA1 Horizontal Addressable Video */ -struct iga1_hor_addr { - int reg_num; - struct io_register reg[IGA1_HOR_ADDR_REG_NUM]; -}; - -/* IGA1 Horizontal Blank Start */ -struct iga1_hor_blank_start { - int reg_num; - struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM]; -}; - -/* IGA1 Horizontal Blank End */ -struct iga1_hor_blank_end { - int reg_num; - struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM]; -}; - -/* IGA1 Horizontal Sync Start */ -struct iga1_hor_sync_start { - int reg_num; - struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM]; -}; - -/* IGA1 Horizontal Sync End */ -struct iga1_hor_sync_end { - int reg_num; - struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM]; -}; - -/* IGA1 Vertical Total */ -struct iga1_ver_total { - int reg_num; - struct io_register reg[IGA1_VER_TOTAL_REG_NUM]; -}; - -/* IGA1 Vertical Addressable Video */ -struct iga1_ver_addr { - int reg_num; - struct io_register reg[IGA1_VER_ADDR_REG_NUM]; -}; - -/* IGA1 Vertical Blank Start */ -struct iga1_ver_blank_start { - int reg_num; - struct io_register reg[IGA1_VER_BLANK_START_REG_NUM]; -}; - -/* IGA1 Vertical Blank End */ -struct iga1_ver_blank_end { - int reg_num; - struct io_register reg[IGA1_VER_BLANK_END_REG_NUM]; -}; - -/* IGA1 Vertical Sync Start */ -struct iga1_ver_sync_start { - int reg_num; - struct io_register reg[IGA1_VER_SYNC_START_REG_NUM]; -}; - -/* IGA1 Vertical Sync End */ -struct iga1_ver_sync_end { - int reg_num; - struct io_register reg[IGA1_VER_SYNC_END_REG_NUM]; -}; - /***************************************************** ** Define IGA2 Shadow Display Timing **** *****************************************************/ @@ -579,82 +412,6 @@ struct iga2_shadow_ver_sync_end { struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM]; }; -/***************************************************** -** Define IGA2 Display Timing **** -******************************************************/ - -/* IGA2 Horizontal Total */ -struct iga2_hor_total { - int reg_num; - struct io_register reg[IGA2_HOR_TOTAL_REG_NUM]; -}; - -/* IGA2 Horizontal Addressable Video */ -struct iga2_hor_addr { - int reg_num; - struct io_register reg[IGA2_HOR_ADDR_REG_NUM]; -}; - -/* IGA2 Horizontal Blank Start */ -struct iga2_hor_blank_start { - int reg_num; - struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM]; -}; - -/* IGA2 Horizontal Blank End */ -struct iga2_hor_blank_end { - int reg_num; - struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM]; -}; - -/* IGA2 Horizontal Sync Start */ -struct iga2_hor_sync_start { - int reg_num; - struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM]; -}; - -/* IGA2 Horizontal Sync End */ -struct iga2_hor_sync_end { - int reg_num; - struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM]; -}; - -/* IGA2 Vertical Total */ -struct iga2_ver_total { - int reg_num; - struct io_register reg[IGA2_VER_TOTAL_REG_NUM]; -}; - -/* IGA2 Vertical Addressable Video */ -struct iga2_ver_addr { - int reg_num; - struct io_register reg[IGA2_VER_ADDR_REG_NUM]; -}; - -/* IGA2 Vertical Blank Start */ -struct iga2_ver_blank_start { - int reg_num; - struct io_register reg[IGA2_VER_BLANK_START_REG_NUM]; -}; - -/* IGA2 Vertical Blank End */ -struct iga2_ver_blank_end { - int reg_num; - struct io_register reg[IGA2_VER_BLANK_END_REG_NUM]; -}; - -/* IGA2 Vertical Sync Start */ -struct iga2_ver_sync_start { - int reg_num; - struct io_register reg[IGA2_VER_SYNC_START_REG_NUM]; -}; - -/* IGA2 Vertical Sync End */ -struct iga2_ver_sync_end { - int reg_num; - struct io_register reg[IGA2_VER_SYNC_END_REG_NUM]; -}; - /* IGA1 Fetch Count Register */ struct iga1_fetch_count { int reg_num; @@ -817,21 +574,6 @@ struct display_queue_expire_num { iga2_display_queue_expire_num_reg; }; -struct iga1_crtc_timing { - struct iga1_hor_total hor_total; - struct iga1_hor_addr hor_addr; - struct iga1_hor_blank_start hor_blank_start; - struct iga1_hor_blank_end hor_blank_end; - struct iga1_hor_sync_start hor_sync_start; - struct iga1_hor_sync_end hor_sync_end; - struct iga1_ver_total ver_total; - struct iga1_ver_addr ver_addr; - struct iga1_ver_blank_start ver_blank_start; - struct iga1_ver_blank_end ver_blank_end; - struct iga1_ver_sync_start ver_sync_start; - struct iga1_ver_sync_end ver_sync_end; -}; - struct iga2_shadow_crtc_timing { struct iga2_shadow_hor_total hor_total_shadow; struct iga2_shadow_hor_blank_end hor_blank_end_shadow; @@ -843,21 +585,6 @@ struct iga2_shadow_crtc_timing { struct iga2_shadow_ver_sync_end ver_sync_end_shadow; }; -struct iga2_crtc_timing { - struct iga2_hor_total hor_total; - struct iga2_hor_addr hor_addr; - struct iga2_hor_blank_start hor_blank_start; - struct iga2_hor_blank_end hor_blank_end; - struct iga2_hor_sync_start hor_sync_start; - struct iga2_hor_sync_end hor_sync_end; - struct iga2_ver_total ver_total; - struct iga2_ver_addr ver_addr; - struct iga2_ver_blank_start ver_blank_start; - struct iga2_ver_blank_end ver_blank_end; - struct iga2_ver_sync_start ver_sync_start; - struct iga2_ver_sync_end ver_sync_end; -}; - /* device ID */ #define CLE266_FUNCTION3 0x3123 #define KM400_FUNCTION3 0x3205 diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 61b0bd596b85..2906b2d23434 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -22,6 +22,8 @@ #ifndef __SHARE_H__ #define __SHARE_H__ +#include "via_modesetting.h" + /* Define Bit Field */ #define BIT0 0x01 #define BIT1 0x02 @@ -648,23 +650,6 @@ #define LCD_OPENLDI 0x00 #define LCD_SPWG 0x01 -/* Define display timing -*/ -struct display_timing { - u16 hor_total; - u16 hor_addr; - u16 hor_blank_start; - u16 hor_blank_end; - u16 hor_sync_start; - u16 hor_sync_end; - u16 ver_total; - u16 ver_addr; - u16 ver_blank_start; - u16 ver_blank_end; - u16 ver_sync_start; - u16 ver_sync_end; -}; - struct crt_mode_table { int refresh_rate; int h_sync_polarity; diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c index 3cddcff88ab9..016d457b6681 100644 --- a/drivers/video/via/via_modesetting.c +++ b/drivers/video/via/via_modesetting.c @@ -29,6 +29,106 @@ #include "share.h" #include "debug.h" + +void via_set_primary_timing(const struct display_timing *timing) +{ + struct display_timing raw; + + raw.hor_total = timing->hor_total / 8 - 5; + raw.hor_addr = timing->hor_addr / 8 - 1; + raw.hor_blank_start = timing->hor_blank_start / 8 - 1; + raw.hor_blank_end = timing->hor_blank_end / 8 - 1; + raw.hor_sync_start = timing->hor_sync_start / 8; + raw.hor_sync_end = timing->hor_sync_end / 8; + raw.ver_total = timing->ver_total - 2; + raw.ver_addr = timing->ver_addr - 1; + raw.ver_blank_start = timing->ver_blank_start - 1; + raw.ver_blank_end = timing->ver_blank_end - 1; + raw.ver_sync_start = timing->ver_sync_start - 1; + raw.ver_sync_end = timing->ver_sync_end - 1; + + /* unlock timing registers */ + via_write_reg_mask(VIACR, 0x11, 0x00, 0x80); + + via_write_reg(VIACR, 0x00, raw.hor_total & 0xFF); + via_write_reg(VIACR, 0x01, raw.hor_addr & 0xFF); + via_write_reg(VIACR, 0x02, raw.hor_blank_start & 0xFF); + via_write_reg_mask(VIACR, 0x03, raw.hor_blank_end & 0x1F, 0x1F); + via_write_reg(VIACR, 0x04, raw.hor_sync_start & 0xFF); + via_write_reg_mask(VIACR, 0x05, (raw.hor_sync_end & 0x1F) + | (raw.hor_blank_end << (7 - 5) & 0x80), 0x9F); + via_write_reg(VIACR, 0x06, raw.ver_total & 0xFF); + via_write_reg_mask(VIACR, 0x07, (raw.ver_total >> 8 & 0x01) + | (raw.ver_addr >> (8 - 1) & 0x02) + | (raw.ver_sync_start >> (8 - 2) & 0x04) + | (raw.ver_blank_start >> (8 - 3) & 0x08) + | (raw.ver_total >> (9 - 5) & 0x20) + | (raw.ver_addr >> (9 - 6) & 0x40) + | (raw.ver_sync_start >> (9 - 7) & 0x80), 0xEF); + via_write_reg_mask(VIACR, 0x09, raw.ver_blank_start >> (9 - 5) & 0x20, + 0x20); + via_write_reg(VIACR, 0x10, raw.ver_sync_start & 0xFF); + via_write_reg_mask(VIACR, 0x11, raw.ver_sync_end & 0x0F, 0x0F); + via_write_reg(VIACR, 0x12, raw.ver_addr & 0xFF); + via_write_reg(VIACR, 0x15, raw.ver_blank_start & 0xFF); + via_write_reg(VIACR, 0x16, raw.ver_blank_end & 0xFF); + via_write_reg_mask(VIACR, 0x33, (raw.hor_sync_start >> (8 - 4) & 0x10) + | (raw.hor_blank_end >> (6 - 5) & 0x20), 0x30); + via_write_reg_mask(VIACR, 0x35, (raw.ver_total >> 10 & 0x01) + | (raw.ver_sync_start >> (10 - 1) & 0x02) + | (raw.ver_addr >> (10 - 2) & 0x04) + | (raw.ver_blank_start >> (10 - 3) & 0x08), 0x0F); + via_write_reg_mask(VIACR, 0x36, raw.hor_total >> (8 - 3) & 0x08, 0x08); + + /* lock timing registers */ + via_write_reg_mask(VIACR, 0x11, 0x80, 0x80); +} + +void via_set_secondary_timing(const struct display_timing *timing) +{ + struct display_timing raw; + + raw.hor_total = timing->hor_total - 1; + raw.hor_addr = timing->hor_addr - 1; + raw.hor_blank_start = timing->hor_blank_start - 1; + raw.hor_blank_end = timing->hor_blank_end - 1; + raw.hor_sync_start = timing->hor_sync_start - 1; + raw.hor_sync_end = timing->hor_sync_end - 1; + raw.ver_total = timing->ver_total - 1; + raw.ver_addr = timing->ver_addr - 1; + raw.ver_blank_start = timing->ver_blank_start - 1; + raw.ver_blank_end = timing->ver_blank_end - 1; + raw.ver_sync_start = timing->ver_sync_start - 1; + raw.ver_sync_end = timing->ver_sync_end - 1; + + via_write_reg(VIACR, 0x50, raw.hor_total & 0xFF); + via_write_reg(VIACR, 0x51, raw.hor_addr & 0xFF); + via_write_reg(VIACR, 0x52, raw.hor_blank_start & 0xFF); + via_write_reg(VIACR, 0x53, raw.hor_blank_end & 0xFF); + via_write_reg(VIACR, 0x54, (raw.hor_blank_start >> 8 & 0x07) + | (raw.hor_blank_end >> (8 - 3) & 0x38) + | (raw.hor_sync_start >> (8 - 6) & 0xC0)); + via_write_reg_mask(VIACR, 0x55, (raw.hor_total >> 8 & 0x0F) + | (raw.hor_addr >> (8 - 4) & 0x70), 0x7F); + via_write_reg(VIACR, 0x56, raw.hor_sync_start & 0xFF); + via_write_reg(VIACR, 0x57, raw.hor_sync_end & 0xFF); + via_write_reg(VIACR, 0x58, raw.ver_total & 0xFF); + via_write_reg(VIACR, 0x59, raw.ver_addr & 0xFF); + via_write_reg(VIACR, 0x5A, raw.ver_blank_start & 0xFF); + via_write_reg(VIACR, 0x5B, raw.ver_blank_end & 0xFF); + via_write_reg(VIACR, 0x5C, (raw.ver_blank_start >> 8 & 0x07) + | (raw.ver_blank_end >> (8 - 3) & 0x38) + | (raw.hor_sync_end >> (8 - 6) & 0x40) + | (raw.hor_sync_start >> (10 - 7) & 0x80)); + via_write_reg(VIACR, 0x5D, (raw.ver_total >> 8 & 0x07) + | (raw.ver_addr >> (8 - 3) & 0x38) + | (raw.hor_blank_end >> (11 - 6) & 0x40) + | (raw.hor_sync_start >> (11 - 7) & 0x80)); + via_write_reg(VIACR, 0x5E, raw.ver_sync_start & 0xFF); + via_write_reg(VIACR, 0x5F, (raw.ver_sync_end & 0x1F) + | (raw.ver_sync_start >> (8 - 5) & 0xE0)); +} + void via_set_primary_address(u32 addr) { DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr); diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h index 013884543e91..06e09fe351ae 100644 --- a/drivers/video/via/via_modesetting.h +++ b/drivers/video/via/via_modesetting.h @@ -33,6 +33,24 @@ #define VIA_PITCH_MAX 0x3FF8 +struct display_timing { + u16 hor_total; + u16 hor_addr; + u16 hor_blank_start; + u16 hor_blank_end; + u16 hor_sync_start; + u16 hor_sync_end; + u16 ver_total; + u16 ver_addr; + u16 ver_blank_start; + u16 ver_blank_end; + u16 ver_sync_start; + u16 ver_sync_end; +}; + + +void via_set_primary_timing(const struct display_timing *timing); +void via_set_secondary_timing(const struct display_timing *timing); void via_set_primary_address(u32 addr); void via_set_secondary_address(u32 addr); void via_set_primary_pitch(u32 pitch); -- cgit v1.2.3 From f18e3e0ce0dacca497e3f1547095b3f9b111b0f7 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 22 May 2011 23:30:48 +0000 Subject: viafb: kill viafb_load_crtc_timing This patch replaces calls to viafb_load_crtc_timing with the code. This should make it easier to fix the oddity that in the modetable the blank and sync end entries contain the length and we need to add the start values to get those to be written to the hardware. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 30 ++++++++---------------------- drivers/video/via/lcd.c | 41 +++++++++++++++++++---------------------- drivers/video/via/lcd.h | 2 -- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 372ce4f071c2..52d41f011d85 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1467,20 +1467,6 @@ void viafb_set_vclock(u32 clk, int set_iga) via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ } -void viafb_load_crtc_timing(struct display_timing device_timing, - int set_iga) -{ - device_timing.hor_blank_end += device_timing.hor_blank_start; - device_timing.hor_sync_end += device_timing.hor_sync_start; - device_timing.ver_blank_end += device_timing.ver_blank_start; - device_timing.ver_sync_end += device_timing.ver_sync_start; - - if (set_iga == IGA1) - via_set_primary_timing(&device_timing); - else if (set_iga == IGA2) - via_set_secondary_timing(&device_timing); -} - void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, struct VideoModeTable *video_mode, int bpp_byte, int set_iga) { @@ -1515,6 +1501,10 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16; } + crt_reg.hor_blank_end += crt_reg.hor_blank_start; + crt_reg.hor_sync_end += crt_reg.hor_sync_start; + crt_reg.ver_blank_end += crt_reg.ver_blank_start; + crt_reg.ver_sync_end += crt_reg.ver_sync_start; h_addr = crt_reg.hor_addr; v_addr = crt_reg.ver_addr; if (set_iga == IGA1) { @@ -1522,14 +1512,10 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); } - switch (set_iga) { - case IGA1: - viafb_load_crtc_timing(crt_reg, IGA1); - break; - case IGA2: - viafb_load_crtc_timing(crt_reg, IGA2); - break; - } + if (set_iga == IGA1) + via_set_primary_timing(&crt_reg); + else if (set_iga == IGA2) + via_set_secondary_timing(&crt_reg); viafb_lock_crt(); viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 6e06981d638b..0a38e4de9979 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -559,7 +559,7 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, int panel_hres = plvds_setting_info->lcd_panel_hres; int panel_vres = plvds_setting_info->lcd_panel_vres; u32 clock; - struct display_timing mode_crt_reg, panel_crt_reg; + struct display_timing mode_crt_reg, panel_crt_reg, timing; struct crt_mode_table *panel_crt_table = NULL; struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres, panel_vres); @@ -576,31 +576,28 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, clock = panel_crt_reg.hor_total * panel_crt_reg.ver_total * panel_crt_table->refresh_rate; plvds_setting_info->vclk = clock; - if (set_iga == IGA1) { - /* IGA1 doesn't have LCD scaling, so set it as centering. */ - viafb_load_crtc_timing(lcd_centering_timging - (mode_crt_reg, panel_crt_reg), IGA1); + + if (set_iga == IGA2 && (set_hres < panel_hres || set_vres < panel_vres) + && plvds_setting_info->display_method == LCD_EXPANDSION) { + timing = panel_crt_reg; + load_lcd_scaling(set_hres, set_vres, panel_hres, panel_vres); } else { - /* Expansion */ - if (plvds_setting_info->display_method == LCD_EXPANDSION - && (set_hres < panel_hres || set_vres < panel_vres)) { - /* expansion timing IGA2 loaded panel set timing*/ - viafb_load_crtc_timing(panel_crt_reg, IGA2); - DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n"); - load_lcd_scaling(set_hres, set_vres, panel_hres, - panel_vres); - DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n"); - } else { /* Centering */ - /* centering timing IGA2 always loaded panel - and mode releative timing */ - viafb_load_crtc_timing(lcd_centering_timging - (mode_crt_reg, panel_crt_reg), IGA2); - viafb_write_reg_mask(CR79, VIACR, 0x00, + timing = lcd_centering_timging(mode_crt_reg, panel_crt_reg); + if (set_iga == IGA2) + /* disable scaling */ + via_write_reg_mask(VIACR, 0x79, 0x00, BIT0 + BIT1 + BIT2); - /* LCD scaling disabled */ - } } + timing.hor_blank_end += timing.hor_blank_start; + timing.hor_sync_end += timing.hor_sync_start; + timing.ver_blank_end += timing.ver_blank_start; + timing.ver_sync_end += timing.ver_sync_start; + if (set_iga == IGA1) + via_set_primary_timing(&timing); + else if (set_iga == IGA2) + via_set_secondary_timing(&timing); + /* Fetch count for IGA2 only */ viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga); diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index 75f60a655b0e..3b9e5397aa69 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -85,7 +85,5 @@ void viafb_init_lvds_output_interface(struct lvds_chip_information struct lvds_setting_information *plvds_setting_info); bool viafb_lcd_get_mobile_state(bool *mobile); -void viafb_load_crtc_timing(struct display_timing device_timing, - int set_iga); #endif /* __LCD_H__ */ -- cgit v1.2.3 From c174e3a3cd0594958c9afc6cdb8fbe20780d9c76 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 22 May 2011 23:40:46 +0000 Subject: viafb: remove superfluous register unlocking/locking The locking is done within the viafb_set_*_timing functions so there is no need to do it here. Move a missing hardware reset into the modesetting function. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 7 ------- drivers/video/via/via_modesetting.c | 4 ++++ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 52d41f011d85..8b4bdf53b95e 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1507,18 +1507,11 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, crt_reg.ver_sync_end += crt_reg.ver_sync_start; h_addr = crt_reg.hor_addr; v_addr = crt_reg.ver_addr; - if (set_iga == IGA1) { - viafb_unlock_crt(); - viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); - } - if (set_iga == IGA1) via_set_primary_timing(&crt_reg); else if (set_iga == IGA2) via_set_secondary_timing(&crt_reg); - viafb_lock_crt(); - viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); /* load FIFO */ diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c index 016d457b6681..0e431aee17bb 100644 --- a/drivers/video/via/via_modesetting.c +++ b/drivers/video/via/via_modesetting.c @@ -82,6 +82,10 @@ void via_set_primary_timing(const struct display_timing *timing) /* lock timing registers */ via_write_reg_mask(VIACR, 0x11, 0x80, 0x80); + + /* reset timing control */ + via_write_reg_mask(VIACR, 0x17, 0x00, 0x80); + via_write_reg_mask(VIACR, 0x17, 0x80, 0x80); } void via_set_secondary_timing(const struct display_timing *timing) -- cgit v1.2.3 From 9ee3ec49e268c7a01217d7865c53562fae1edf33 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 2 Jun 2011 12:56:39 +0000 Subject: viafb: remove superfluous mode lookup As the result is not used anywhere there is no need to perform the lookup at all. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/viafbdev.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index bddae58ecd8a..3eaf607bdf48 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -1735,7 +1735,6 @@ static struct viafb_pm_hooks viafb_fb_pm_hooks = { int __devinit via_fb_pci_probe(struct viafb_dev *vdev) { u32 default_xres, default_yres; - struct VideoModeTable *vmode_entry; struct fb_var_screeninfo default_var; int rc; u32 viafb_par_length; @@ -1808,7 +1807,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) } parse_mode(viafb_mode, &default_xres, &default_yres); - vmode_entry = viafb_get_mode(default_xres, default_yres); if (viafb_SAMM_ON == 1) parse_mode(viafb_mode1, &viafb_second_xres, &viafb_second_yres); -- cgit v1.2.3 From 92746c3c82135b13d7fb1bbdebbabb0faedd8433 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Thu, 2 Jun 2011 14:03:53 +0000 Subject: viafb: simplify viafb_fill_crtc_timing As the first argument is just part of the structure passed as the second argument there is no need for it at all. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/dvi.c | 6 ++---- drivers/video/via/hw.c | 12 ++++++------ drivers/video/via/hw.h | 4 ++-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index b1f364745ca0..c7ff5c0e9c7e 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -190,12 +190,10 @@ void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp, if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) { rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr, mode->crtc[0].crtc.ver_addr); - if (rb_mode) { + if (rb_mode) mode = rb_mode; - pDviTiming = rb_mode->crtc; - } } - viafb_fill_crtc_timing(pDviTiming, mode, mode_bpp / 8, set_iga); + viafb_fill_crtc_timing(mode, mode_bpp / 8, set_iga); } /* Sense DVI Connector */ diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 8b4bdf53b95e..2050fb81ef6e 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1467,9 +1467,10 @@ void viafb_set_vclock(u32 clk, int set_iga) via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ } -void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, - struct VideoModeTable *video_mode, int bpp_byte, int set_iga) +void viafb_fill_crtc_timing(struct VideoModeTable *video_mode, int bpp_byte, + int set_iga) { + struct crt_mode_table *crt_table = video_mode->crtc; struct display_timing crt_reg; int i; int index = 0; @@ -1911,11 +1912,10 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, if (viafb_CRT_ON) { if (viafb_SAMM_ON && viaparinfo->shared->iga2_devices & VIA_CRT) { - viafb_fill_crtc_timing(crt_timing1, vmode_tbl1, - video_bpp1 / 8, IGA2); + viafb_fill_crtc_timing(vmode_tbl1, video_bpp1 / 8, + IGA2); } else { - viafb_fill_crtc_timing(crt_timing, vmode_tbl, - video_bpp / 8, + viafb_fill_crtc_timing(vmode_tbl, video_bpp / 8, (viaparinfo->shared->iga1_devices & VIA_CRT) ? IGA1 : IGA2); } diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 267c669be736..1fd8d98f7395 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -637,8 +637,8 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, - struct VideoModeTable *video_mode, int bpp_byte, int set_iga); +void viafb_fill_crtc_timing(struct VideoModeTable *video_mode, int bpp_byte, + int set_iga); void viafb_set_vclock(u32 CLK, int set_iga); void viafb_load_reg(int timing_value, int viafb_load_reg_num, -- cgit v1.2.3 From 0492262281b82e71c6063e35ef73a33fad93cc6d Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 6 Jun 2011 15:39:20 +0000 Subject: viafb: remove 640x480-60 CRT special case The timing for 640x480-60 was handled different than all others. This patch changes this by changing the blanking start and end. The reason for this is that I can't find any reason for the old behaviour and it was not consistent anyway as the special case for LCD did not always trigger as the LCD code does not use this function and it did trigger regardless of whether the display set is CRT or LCD but only based whether any DVI/LCD device exists. There are no negative effects observed for CRT or DVI devices. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 14 -------------- drivers/video/via/viamode.c | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 2050fb81ef6e..c5e7833a5ae5 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1488,20 +1488,6 @@ void viafb_fill_crtc_timing(struct VideoModeTable *video_mode, int bpp_byte, } crt_reg = crt_table[index].crtc; - - /* Mode 640x480 has border, but LCD/DFP didn't have border. */ - /* So we would delete border. */ - if ((viafb_LCD_ON | viafb_DVI_ON) - && video_mode->crtc[0].crtc.hor_addr == 640 - && video_mode->crtc[0].crtc.ver_addr == 480 - && refresh == 60) { - /* The border is 8 pixels. */ - crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8; - - /* Blanking time should add left and right borders. */ - crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16; - } - crt_reg.hor_blank_end += crt_reg.hor_blank_start; crt_reg.hor_sync_end += crt_reg.hor_sync_start; crt_reg.ver_blank_end += crt_reg.ver_blank_start; diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 58df74e1417e..8a9f4fcb50e9 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -281,7 +281,7 @@ static struct crt_mode_table CRTM640x480[] = { /*r_rate,hsp,vsp */ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */ {REFRESH_60, M640X480_R60_HSP, M640X480_R60_VSP, - {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} }, + {800, 640, 640, 160, 656, 96, 525, 480, 480, 45, 490, 2} }, {REFRESH_75, M640X480_R75_HSP, M640X480_R75_VSP, {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} }, {REFRESH_85, M640X480_R85_HSP, M640X480_R85_VSP, -- cgit v1.2.3 From dfb09f9b7ab03fd367740e541a5caf830ed56726 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 5 Aug 2011 15:15:08 +0200 Subject: x86, amd: Avoid cache aliasing penalties on AMD family 15h This patch provides performance tuning for the "Bulldozer" CPU. With its shared instruction cache there is a chance of generating an excessive number of cache cross-invalidates when running specific workloads on the cores of a compute module. This excessive amount of cross-invalidations can be observed if cache lines backed by shared physical memory alias in bits [14:12] of their virtual addresses, as those bits are used for the index generation. This patch addresses the issue by clearing all the bits in the [14:12] slice of the file mapping's virtual address at generation time, thus forcing those bits the same for all mappings of a single shared library across processes and, in doing so, avoids instruction cache aliases. It also adds the command line option "align_va_addr=(32|64|on|off)" with which virtual address alignment can be enabled for 32-bit or 64-bit x86 individually, or both, or be completely disabled. This change leaves virtual region address allocation on other families and/or vendors unaffected. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1312550110-24160-2-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin --- Documentation/kernel-parameters.txt | 13 ++++++ arch/x86/include/asm/elf.h | 31 ++++++++++++++ arch/x86/kernel/cpu/amd.c | 13 ++++++ arch/x86/kernel/sys_x86_64.c | 81 +++++++++++++++++++++++++++++++++++-- arch/x86/mm/mmap.c | 15 ------- arch/x86/vdso/vma.c | 9 +++++ 6 files changed, 144 insertions(+), 18 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index aa47be71df4c..af73c036b7e6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -299,6 +299,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted. behaviour to be specified. Bit 0 enables warnings, bit 1 enables fixups, and bit 2 sends a segfault. + align_va_addr= [X86-64] + Align virtual addresses by clearing slice [14:12] when + allocating a VMA at process creation time. This option + gives you up to 3% performance improvement on AMD F15h + machines (where it is enabled by default) for a + CPU-intensive style benchmark, and it can vary highly in + a microbenchmark depending on workload and compiler. + + 1: only for 32-bit processes + 2: only for 64-bit processes + on: enable for both 32- and 64-bit processes + off: disable for both 32- and 64-bit processes + amd_iommu= [HW,X86-84] Pass parameters to the AMD IOMMU driver in the system. Possible values are: diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h index f2ad2163109d..5f962df30d0f 100644 --- a/arch/x86/include/asm/elf.h +++ b/arch/x86/include/asm/elf.h @@ -4,6 +4,7 @@ /* * ELF register definitions.. */ +#include #include #include @@ -320,4 +321,34 @@ extern int syscall32_setup_pages(struct linux_binprm *, int exstack); extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +/* + * True on X86_32 or when emulating IA32 on X86_64 + */ +static inline int mmap_is_ia32(void) +{ +#ifdef CONFIG_X86_32 + return 1; +#endif +#ifdef CONFIG_IA32_EMULATION + if (test_thread_flag(TIF_IA32)) + return 1; +#endif + return 0; +} + +/* The first two values are special, do not change. See align_addr() */ +enum align_flags { + ALIGN_VA_32 = BIT(0), + ALIGN_VA_64 = BIT(1), + ALIGN_VDSO = BIT(2), + ALIGN_TOPDOWN = BIT(3), +}; + +struct va_alignment { + int flags; + unsigned long mask; +} ____cacheline_aligned; + +extern struct va_alignment va_align; +extern unsigned long align_addr(unsigned long, struct file *, enum align_flags); #endif /* _ASM_X86_ELF_H */ diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index b13ed393dfce..b0234bcbd32a 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -458,6 +458,19 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) "with P0 frequency!\n"); } } + + if (c->x86 == 0x15) { + unsigned long upperbit; + u32 cpuid, assoc; + + cpuid = cpuid_edx(0x80000005); + assoc = cpuid >> 16 & 0xff; + upperbit = ((cpuid >> 24) << 10) / assoc; + + va_align.mask = (upperbit - 1) & PAGE_MASK; + va_align.flags = ALIGN_VA_32 | ALIGN_VA_64; + + } } static void __cpuinit init_amd(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index ff14a5044ce6..aaa8d09c7195 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -18,6 +18,72 @@ #include #include +struct __read_mostly va_alignment va_align = { + .flags = -1, +}; + +/* + * Align a virtual address to avoid aliasing in the I$ on AMD F15h. + * + * @flags denotes the allocation direction - bottomup or topdown - + * or vDSO; see call sites below. + */ +unsigned long align_addr(unsigned long addr, struct file *filp, + enum align_flags flags) +{ + unsigned long tmp_addr; + + /* handle 32- and 64-bit case with a single conditional */ + if (va_align.flags < 0 || !(va_align.flags & (2 - mmap_is_ia32()))) + return addr; + + if (!(current->flags & PF_RANDOMIZE)) + return addr; + + if (!((flags & ALIGN_VDSO) || filp)) + return addr; + + tmp_addr = addr; + + /* + * We need an address which is <= than the original + * one only when in topdown direction. + */ + if (!(flags & ALIGN_TOPDOWN)) + tmp_addr += va_align.mask; + + tmp_addr &= ~va_align.mask; + + return tmp_addr; +} + +static int __init control_va_addr_alignment(char *str) +{ + /* guard against enabling this on other CPU families */ + if (va_align.flags < 0) + return 1; + + if (*str == 0) + return 1; + + if (*str == '=') + str++; + + if (!strcmp(str, "32")) + va_align.flags = ALIGN_VA_32; + else if (!strcmp(str, "64")) + va_align.flags = ALIGN_VA_64; + else if (!strcmp(str, "off")) + va_align.flags = 0; + else if (!strcmp(str, "on")) + va_align.flags = ALIGN_VA_32 | ALIGN_VA_64; + else + return 0; + + return 1; +} +__setup("align_va_addr", control_va_addr_alignment); + SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, unsigned long, prot, unsigned long, flags, unsigned long, fd, unsigned long, off) @@ -92,6 +158,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, start_addr = addr; full_search: + + addr = align_addr(addr, filp, 0); + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ if (end - len < addr) { @@ -117,6 +186,7 @@ full_search: mm->cached_hole_size = vma->vm_start - addr; addr = vma->vm_end; + addr = align_addr(addr, filp, 0); } } @@ -161,10 +231,13 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, /* make sure it can fit in the remaining address space */ if (addr > len) { - vma = find_vma(mm, addr-len); - if (!vma || addr <= vma->vm_start) + unsigned long tmp_addr = align_addr(addr - len, filp, + ALIGN_TOPDOWN); + + vma = find_vma(mm, tmp_addr); + if (!vma || tmp_addr + len <= vma->vm_start) /* remember the address as a hint for next time */ - return mm->free_area_cache = addr-len; + return mm->free_area_cache = tmp_addr; } if (mm->mmap_base < len) @@ -173,6 +246,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, addr = mm->mmap_base-len; do { + addr = align_addr(addr, filp, ALIGN_TOPDOWN); + /* * Lookup failure means no vma is above this address, * else if new region fits below vma->vm_start, diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index 1dab5194fd9d..d4c073630175 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -51,21 +51,6 @@ static unsigned int stack_maxrandom_size(void) #define MIN_GAP (128*1024*1024UL + stack_maxrandom_size()) #define MAX_GAP (TASK_SIZE/6*5) -/* - * True on X86_32 or when emulating IA32 on X86_64 - */ -static int mmap_is_ia32(void) -{ -#ifdef CONFIG_X86_32 - return 1; -#endif -#ifdef CONFIG_IA32_EMULATION - if (test_thread_flag(TIF_IA32)) - return 1; -#endif - return 0; -} - static int mmap_is_legacy(void) { if (current->personality & ADDR_COMPAT_LAYOUT) diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c index 7abd2be0f9b9..caa42ce17577 100644 --- a/arch/x86/vdso/vma.c +++ b/arch/x86/vdso/vma.c @@ -69,6 +69,15 @@ static unsigned long vdso_addr(unsigned long start, unsigned len) addr = start + (offset << PAGE_SHIFT); if (addr >= end) addr = end; + + /* + * page-align it here so that get_unmapped_area doesn't + * align it wrongfully again to the next page. addr can come in 4K + * unaligned here as a result of stack start randomization. + */ + addr = PAGE_ALIGN(addr); + addr = align_addr(addr, NULL, ALIGN_VDSO); + return addr; } -- cgit v1.2.3 From a110b5ec7371592eac856ac5c22dc7b518952d44 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 5 Aug 2011 20:01:16 +0200 Subject: x86: Add a BSP cpu_dev helper Add a function ptr to struct cpu_dev which is destined to be run only once on the BSP during boot. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/20110805180116.GB26217@aftab Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/common.c | 3 +++ arch/x86/kernel/cpu/cpu.h | 1 + 2 files changed, 4 insertions(+) diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 22a073d7fbff..8ed394a8eb6e 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -681,6 +681,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) filter_cpuid_features(c, false); setup_smep(c); + + if (this_cpu->c_bsp_init) + this_cpu->c_bsp_init(c); } void __init early_cpu_init(void) diff --git a/arch/x86/kernel/cpu/cpu.h b/arch/x86/kernel/cpu/cpu.h index e765633f210e..1b22dcc51af4 100644 --- a/arch/x86/kernel/cpu/cpu.h +++ b/arch/x86/kernel/cpu/cpu.h @@ -18,6 +18,7 @@ struct cpu_dev { struct cpu_model_info c_models[4]; void (*c_early_init)(struct cpuinfo_x86 *); + void (*c_bsp_init)(struct cpuinfo_x86 *); void (*c_init)(struct cpuinfo_x86 *); void (*c_identify)(struct cpuinfo_x86 *); unsigned int (*c_size_cache)(struct cpuinfo_x86 *, unsigned int); -- cgit v1.2.3 From 8fa8b035085e7320c15875c1f6b03b290ca2dd66 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 5 Aug 2011 20:04:09 +0200 Subject: x86, amd: Move BSP code to cpu_dev helper Move code which is run once on the BSP during boot into the cpu_dev helper. [ hpa: removed bogus cpu_has -> static_cpu_has conversion ] Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/20110805180409.GC26217@aftab Signed-off-by: H. Peter Anvin --- arch/x86/kernel/cpu/amd.c | 59 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c index b0234bcbd32a..b6e3e87d25fb 100644 --- a/arch/x86/kernel/cpu/amd.c +++ b/arch/x86/kernel/cpu/amd.c @@ -410,6 +410,34 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c) #endif } +static void __cpuinit bsp_init_amd(struct cpuinfo_x86 *c) +{ + if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { + + if (c->x86 > 0x10 || + (c->x86 == 0x10 && c->x86_model >= 0x2)) { + u64 val; + + rdmsrl(MSR_K7_HWCR, val); + if (!(val & BIT(24))) + printk(KERN_WARNING FW_BUG "TSC doesn't count " + "with P0 frequency!\n"); + } + } + + if (c->x86 == 0x15) { + unsigned long upperbit; + u32 cpuid, assoc; + + cpuid = cpuid_edx(0x80000005); + assoc = cpuid >> 16 & 0xff; + upperbit = ((cpuid >> 24) << 10) / assoc; + + va_align.mask = (upperbit - 1) & PAGE_MASK; + va_align.flags = ALIGN_VA_32 | ALIGN_VA_64; + } +} + static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) { early_init_amd_mc(c); @@ -441,36 +469,6 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) set_cpu_cap(c, X86_FEATURE_EXTD_APICID); } #endif - - /* We need to do the following only once */ - if (c != &boot_cpu_data) - return; - - if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) { - - if (c->x86 > 0x10 || - (c->x86 == 0x10 && c->x86_model >= 0x2)) { - u64 val; - - rdmsrl(MSR_K7_HWCR, val); - if (!(val & BIT(24))) - printk(KERN_WARNING FW_BUG "TSC doesn't count " - "with P0 frequency!\n"); - } - } - - if (c->x86 == 0x15) { - unsigned long upperbit; - u32 cpuid, assoc; - - cpuid = cpuid_edx(0x80000005); - assoc = cpuid >> 16 & 0xff; - upperbit = ((cpuid >> 24) << 10) / assoc; - - va_align.mask = (upperbit - 1) & PAGE_MASK; - va_align.flags = ALIGN_VA_32 | ALIGN_VA_64; - - } } static void __cpuinit init_amd(struct cpuinfo_x86 *c) @@ -692,6 +690,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = { .c_size_cache = amd_size_cache, #endif .c_early_init = early_init_amd, + .c_bsp_init = bsp_init_amd, .c_init = init_amd, .c_x86_vendor = X86_VENDOR_AMD, }; -- cgit v1.2.3 From 79fcce3230b140f7675f8529ee53fe2f9644f902 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Wed, 3 Aug 2011 12:08:21 -0300 Subject: [media] DiBcom: protect the I2C bufer access This patch protects the I2C buffer access in order to manage concurrent access. This protection is done using mutex. Furthermore, for the dib9000, if a pid filtering command is received during the tuning, this pid filtering command is delayed to avoid any concurrent access issue. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Cc: stable@kernel.org Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/frontends/dib0070.c | 37 ++++-- drivers/media/dvb/frontends/dib0090.c | 70 ++++++++++-- drivers/media/dvb/frontends/dib7000m.c | 27 ++++- drivers/media/dvb/frontends/dib7000p.c | 32 +++++- drivers/media/dvb/frontends/dib8000.c | 72 ++++++++++-- drivers/media/dvb/frontends/dib9000.c | 164 +++++++++++++++++++++++---- drivers/media/dvb/frontends/dibx000_common.c | 76 +++++++++++-- drivers/media/dvb/frontends/dibx000_common.h | 1 + 8 files changed, 412 insertions(+), 67 deletions(-) diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 1d47d4da7d4c..dc1cb17a6ea7 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -78,10 +79,18 @@ struct dib0070_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; -static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0070 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } state->i2c_write_buffer[0] = reg; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0070 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { \ @@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter state->cfg = cfg; state->i2c = i2c; state->fe = fe; + mutex_init(&state->i2c_buffer_lock); fe->tuner_priv = state; if (dib0070_reset(fe) != 0) diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index c9c935ae41e4..b174d1c78583 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -196,6 +197,7 @@ struct dib0090_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; struct dib0090_fw_state { @@ -208,10 +210,18 @@ struct dib0090_fw_state { struct i2c_msg msg; u8 i2c_write_buffer[2]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = reg & 0xff; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(&state->msg, 0, sizeof(struct i2c_msg)); @@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = val >> 8; state->i2c_write_buffer[1] = val & 0xff; @@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) @@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (config->wbd == NULL) @@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (dib0090_fw_reset_digital(fe, st->config) != 0) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 79cb1c20df24..dbb76d75c932 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -55,6 +56,7 @@ struct dib7000m_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000m_power_mode { @@ -69,6 +71,13 @@ enum dib7000m_power_mode { static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = (reg >> 8) | 0x80; state->i2c_write_buffer[1] = reg & 0xff; @@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d",reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -101,7 +120,10 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) { @@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); st->timf_default = cfg->bw->timf; diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index a64a538ba364..4eb9c2b49cd5 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "dvb_math.h" #include "dvb_frontend.h" @@ -68,6 +69,7 @@ struct dib7000p_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000p_power_mode { @@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -113,7 +131,10 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) @@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau return -ENOMEM; dpst->i2c_adap = i2c; + mutex_init(&dpst->i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { dpst->cfg = cfg[k]; @@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ @@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, st->version = dib7000p_read_word(st, 897); /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; /* FIXME: make sure the dev.parent field is initialized, or else request_firmware() will hit an OOPS (this should be moved somewhere diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 7d2ea112ae2b..fe284d5292f5 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -10,6 +10,8 @@ #include #include #include +#include + #include "dvb_math.h" #include "dvb_frontend.h" @@ -37,6 +39,7 @@ struct i2c_device { u8 addr; u8 *i2c_write_buffer; u8 *i2c_read_buffer; + struct mutex *i2c_buffer_lock; }; struct dib8000_state { @@ -77,6 +80,7 @@ struct dib8000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib8000_power_mode { @@ -86,24 +90,39 @@ enum dib8000_power_mode { static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) { + u16 ret; struct i2c_msg msg[2] = { - {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 2}, - {.addr = i2c->addr >> 1, .flags = I2C_M_RD, - .buf = i2c->i2c_read_buffer, .len = 2}, + {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, + {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, }; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + msg[0].buf = i2c->i2c_write_buffer; msg[0].buf[0] = reg >> 8; msg[0].buf[1] = reg & 0xff; + msg[1].buf = i2c->i2c_read_buffer; if (i2c_transfer(i2c->adap, msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (msg[1].buf[0] << 8) | msg[1].buf[1]; + ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; + mutex_unlock(i2c->i2c_buffer_lock); + return ret; } static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static u32 dib8000_read32(struct dib8000_state *state, u16 reg) @@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) { - struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 4}; + struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; int ret = 0; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + msg.buf = i2c->i2c_write_buffer; msg.buf[0] = (reg >> 8) & 0xff; msg.buf[1] = reg & 0xff; msg.buf[2] = (val >> 8) & 0xff; msg.buf[3] = val & 0xff; ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(i2c->i2c_buffer_lock); return ret; } static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static const s16 coeff_2k_sb_1seg_dqpsk[8] = { @@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau if (!client.i2c_read_buffer) { dprintk("%s: not enough memory", __func__); ret = -ENOMEM; - goto error_memory; + goto error_memory_read; + } + client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!client.i2c_buffer_lock) { + dprintk("%s: not enough memory", __func__); + ret = -ENOMEM; + goto error_memory_lock; } + mutex_init(client.i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { /* designated i2c address */ @@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau } error: + kfree(client.i2c_buffer_lock); +error_memory_lock: kfree(client.i2c_read_buffer); -error_memory: +error_memory_read: kfree(client.i2c_write_buffer); return ret; @@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s state->i2c.addr = i2c_addr; state->i2c.i2c_write_buffer = state->i2c_write_buffer; state->i2c.i2c_read_buffer = state->i2c_read_buffer; + mutex_init(&state->i2c_buffer_lock); + state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; state->gpio_val = cfg->gpio_val; state->gpio_dir = cfg->gpio_dir; diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index a0855883b5ce..b931074a9521 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -38,6 +38,15 @@ struct i2c_device { #define DibInitLock(lock) mutex_init(lock) #define DibFreeLock(lock) +struct dib9000_pid_ctrl { +#define DIB9000_PID_FILTER_CTRL 0 +#define DIB9000_PID_FILTER 1 + u8 cmd; + u8 id; + u16 pid; + u8 onoff; +}; + struct dib9000_state { struct i2c_device i2c; @@ -99,6 +108,10 @@ struct dib9000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[255]; u8 i2c_read_buffer[255]; + DIB_LOCK demod_lock; + u8 get_frontend_internal; + struct dib9000_pid_ctrl pid_ctrl[10]; + s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ }; static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio); int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; - u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; + u16 val; + int ret; + + if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { + /* postpone the pid filtering cmd */ + dprintk("pid filter cmd postpone"); + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + return 0; + } + + DibAcquireLock(&state->demod_lock); + + val = dib9000_read_word(state, 294 + 1) & 0xffef; val |= (onoff & 0x1) << 4; dprintk("PID filter enabled %d", onoff); - return dib9000_write_word(state, 294 + 1, val); + ret = dib9000_write_word(state, 294 + 1, val); + DibReleaseLock(&state->demod_lock); + return ret; + } EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; + int ret; + + if (state->pid_ctrl_index != -2) { + /* postpone the pid filtering cmd */ + dprintk("pid filter postpone"); + if (state->pid_ctrl_index < 9) { + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; + state->pid_ctrl[state->pid_ctrl_index].id = id; + state->pid_ctrl[state->pid_ctrl_index].pid = pid; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + } else + dprintk("can not add any more pid ctrl cmd"); + return 0; + } + + DibAcquireLock(&state->demod_lock); dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); + ret = dib9000_write_word(state, 300 + 1 + id, + onoff ? (1 << 13) | pid : 0); + DibReleaseLock(&state->demod_lock); + return ret; } EXPORT_SYMBOL(dib9000_fw_pid_filter); @@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_frontend *demod) DibFreeLock(&state->platform.risc.mbx_lock); DibFreeLock(&state->platform.risc.mem_lock); DibFreeLock(&state->platform.risc.mem_mbx_lock); + DibFreeLock(&state->demod_lock); dibx000_exit_i2c_master(&st->i2c_master); i2c_del_adapter(&st->tuner_adap); @@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend; - int ret; + int ret = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); if (ret < 0) - return ret; + goto error; } - return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) @@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; fe_status_t stat; - int ret; + int ret = 0; + + if (state->get_frontend_internal == 0) + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); @@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.rolloff; } } - return 0; + ret = 0; + goto return_value; } } /* get the channel from master chip */ ret = dib9000_fw_get_channel(fe, fep); if (ret != 0) - return ret; + goto return_value; /* synchronize the cache with the other frontends */ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { @@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; } + ret = 0; - return 0; +return_value: + if (state->get_frontend_internal == 0) + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) @@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("dib9000: must specify bandwidth "); return 0; } + + state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ + DibAcquireLock(&state->demod_lock); + fe->dtv_property_cache.delivery_system = SYS_DVBT; /* set the master status */ @@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* check the tune result */ if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); + DibReleaseLock(&state->demod_lock); + /* tune failed; put all the pid filtering cmd to junk */ + state->pid_ctrl_index = -1; return 0; } dprintk("tune success on frontend%i", index_frontend_success); /* synchronize all the channel cache */ + state->get_frontend_internal = 1; dib9000_get_frontend(state->fe[0], fep); + state->get_frontend_internal = 0; /* retune the other frontends with the found channel */ channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; @@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* turn off the diversity for the last frontend */ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); + DibReleaseLock(&state->demod_lock); + if (state->pid_ctrl_index >= 0) { + u8 index_pid_filter_cmd; + u8 pid_ctrl_index = state->pid_ctrl_index; + + state->pid_ctrl_index = -2; + for (index_pid_filter_cmd = 0; + index_pid_filter_cmd <= pid_ctrl_index; + index_pid_filter_cmd++) { + if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL) + dib9000_fw_pid_filter_ctrl(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].onoff); + else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER) + dib9000_fw_pid_filter(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].id, + state->pid_ctrl[index_pid_filter_cmd].pid, + state->pid_ctrl[index_pid_filter_cmd].onoff); + } + } + /* do not postpone any more the pid filtering */ + state->pid_ctrl_index = -2; + return 0; } @@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib9000_read_lock(state->fe[index_frontend]); @@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) if ((lock & 0x0008) || (lock_slave & 0x0008)) *stat |= FE_HAS_LOCK; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib9000_state *state = fe->demodulator_priv; u16 *c; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, state->i2c_read_buffer, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) c = (u16 *)state->i2c_read_buffer; *ber = c[10] << 16 | c[11]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) @@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u8 index_frontend; u16 *c = (u16 *)state->i2c_read_buffer; u16 val; + int ret = 0; + DibAcquireLock(&state->demod_lock); *strength = 0; for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); @@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) } DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength = 65535; else *strength += val; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static u32 dib9000_get_snr(struct dvb_frontend *fe) @@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u8 index_frontend; u32 snr_master; + DibAcquireLock(&state->demod_lock); snr_master = dib9000_get_snr(fe); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib9000_get_snr(state->fe[index_frontend]); @@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) } else *snr = 0; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib9000_state *state = fe->demodulator_priv; u16 *c = (u16 *)state->i2c_read_buffer; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); *unc = c[12]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) @@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c DibInitLock(&st->platform.risc.mbx_lock); DibInitLock(&st->platform.risc.mem_lock); DibInitLock(&st->platform.risc.mem_mbx_lock); + DibInitLock(&st->demod_lock); + st->get_frontend_internal = 0; + + st->pid_ctrl_index = -2; st->fe[0] = fe; fe->demodulator_priv = st; diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index dc5d17a67579..774d507b66cc 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -1,4 +1,5 @@ #include +#include #include "dibx000_common.h" @@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; mst->i2c_write_buffer[1] = reg & 0xff; mst->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -21,11 +29,21 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) mst->msg[0].buf = mst->i2c_write_buffer; mst->msg[0].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + mst->i2c_write_buffer[0] = reg >> 8; mst->i2c_write_buffer[1] = reg & 0xff; @@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) @@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { @@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { @@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr) { - u8 tx[4]; - struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; + int ret; + + mutex_init(&mst->i2c_buffer_lock); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg)); + mst->msg[0].addr = i2c_addr >> 1; + mst->msg[0].flags = 0; + mst->msg[0].buf = mst->i2c_write_buffer; + mst->msg[0].len = 4; mst->device_rev = device_rev; mst->i2c_adap = i2c_adap; @@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, "DiBX000: could not initialize the master i2c_adapter\n"); /* initialize the i2c-master by closing the gate */ - dibx000_i2c_gate_ctrl(mst, tx, 0, 0); + dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); + + ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1); + mutex_unlock(&mst->i2c_buffer_lock); - return i2c_transfer(i2c_adap, &m, 1) == 1; + return ret; } EXPORT_SYMBOL(dibx000_init_i2c_master); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index f031165c0459..5e011474be43 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -33,6 +33,7 @@ struct dibx000_i2c_master { struct i2c_msg msg[34]; u8 i2c_write_buffer[8]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, -- cgit v1.2.3 From bff469f4167fdabfe15294f375577d7eadbaa1bb Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 1 Aug 2011 12:45:58 -0300 Subject: [media] dib0700: protect the dib0700 buffer access This patch protects the common buffer access inside the dib0700 in order to manage concurrent access. This protection is done using mutex. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Cc: stable@kernel.org Signed-off-by: Javier Marcet Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher [mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 81 ++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 5eb91b4f8fd0..a224e94325b7 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, struct dib0700_state *st = d->priv; int ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, @@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, if (fwtype != NULL) *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | (st->buf[14] << 8) | st->buf[15]; + mutex_unlock(&d->usb_mutex); return ret; } @@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_GPIO; st->buf[1] = gpio; @@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); return ret; } @@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) int ret; if (st->fw_version >= 0x10201) { + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_USB_XFER_LEN; st->buf[1] = (nb_ts_packets >> 8) & 0xff; st->buf[2] = nb_ts_packets & 0xff; @@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); } else { deb_info("this firmware does not allow to change the USB xfer len\n"); ret = -EIO; @@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, } else { /* Write request */ + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_NEW_I2C_WRITE; st->buf[1] = msg[i].addr << 1; st->buf[2] = (en_start << 7) | (en_stop << 6) | @@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, st->buf, msg[i].len + 4, USB_CTRL_GET_TIMEOUT); + mutex_unlock(&d->usb_mutex); if (result < 0) { deb_info("i2c write error (status = %d)\n", result); break; @@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } for (i = 0; i < num; i++) { /* fill in the address */ @@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, break; } } + mutex_unlock(&d->usb_mutex); mutex_unlock(&d->i2c_mutex); return i; @@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, u16 pll_loopdiv, u16 free_div, u16 dsuScaler) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_CLOCK; st->buf[1] = (en_pll << 7) | (pll_src << 6) | @@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, st->buf[9] = dsuScaler & 0xff; /* LSB */ ret = dib0700_ctrl_wr(d, st->buf, 10); + mutex_unlock(&d->usb_mutex); return ret; } @@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) { struct dib0700_state *st = d->priv; u16 divider; + int ret; if (scl_kHz == 0) return -EINVAL; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_I2C_PARAM; divider = (u16) (30000 / scl_kHz); st->buf[1] = 0; @@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); - return dib0700_ctrl_wr(d, st->buf, 8); + + ret = dib0700_ctrl_wr(d, st->buf, 8); + mutex_unlock(&d->usb_mutex); + + return ret; } @@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } } + if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_ENABLE_VIDEO; /* this bit gives a kind of command, * rather than enabling something or not */ @@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); - return dib0700_ctrl_wr(adap->dev, st->buf, 4); + ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); + mutex_unlock(&adap->dev->usb_mutex); + + return ret; } int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) @@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) struct dib0700_state *st = d->priv; int new_proto, ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_RC; st->buf[1] = 0; st->buf[2] = 0; @@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) else if (rc_type == RC_TYPE_NEC) new_proto = 0; else if (rc_type == RC_TYPE_RC6) { - if (st->fw_version < 0x10200) - return -EINVAL; + if (st->fw_version < 0x10200) { + ret = -EINVAL; + goto out; + } new_proto = 2; - } else - return -EINVAL; + } else { + ret = -EINVAL; + goto out; + } st->buf[1] = new_proto; ret = dib0700_ctrl_wr(d, st->buf, 3); if (ret < 0) { err("ir protocol setup failed"); - return ret; + goto out; } d->props.rc.core.protocol = rc_type; +out: + mutex_unlock(&d->usb_mutex); return ret; } -- cgit v1.2.3 From 680417bb318adc5f1f8f392730776176fbcdedd8 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Thu, 4 Aug 2011 13:10:03 -0300 Subject: [media] dib0700: correct error message The goal of this patch is to correct a previous patch. In case of error, the err() function should be used instead of dprintk() function. [mchehab@redhat.com: as I've replaced dprintk by deb_info, on the the previous patch, to avoid breaking bisect, I had to fix a merge conflict on this one] Signed-off-by: Olivier Grenie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb/dvb-usb/dib0700_core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index a224e94325b7..b693ed13602d 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -31,7 +31,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -117,7 +117,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -138,7 +138,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) if (st->fw_version >= 0x10201) { if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -227,7 +227,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, } else { /* Write request */ if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } st->buf[0] = REQUEST_NEW_I2C_WRITE; @@ -273,7 +273,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -368,7 +368,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, int ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -400,7 +400,7 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) return -EINVAL; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -560,7 +560,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } @@ -610,7 +610,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) int new_proto, ret; if (mutex_lock_interruptible(&d->usb_mutex) < 0) { - deb_info("could not acquire lock"); + err("could not acquire lock"); return 0; } -- cgit v1.2.3 From 572064280ecc9dc89227cf3797bc2144896a34f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Jul 2011 11:16:41 -0300 Subject: [media] adp1653: check platform_data before usage The driver requires platform_data to be present. That's why we need to check and fail in case of the absence of necessary data. Signed-off-by: Andy Shevchenko Cc: Mauro Carvalho Chehab Cc: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/adp1653.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index be7befd60947..8ad89ffe2cc3 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -413,6 +413,10 @@ static int adp1653_probe(struct i2c_client *client, struct adp1653_flash *flash; int ret; + /* we couldn't work without platform data */ + if (client->dev.platform_data == NULL) + return -ENODEV; + flash = kzalloc(sizeof(*flash), GFP_KERNEL); if (flash == NULL) return -ENOMEM; -- cgit v1.2.3 From 31ee95ec2d3dd3b6f68d7fa0f410045652895af2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 28 Jul 2011 04:59:38 -0300 Subject: [media] adp1653: check error code of adp1653_init_controls Potentially the adp1653_init_controls could return an error. In our case the error was ignored, meanwhile it means incorrect initialization of V4L2 controls. Additionally we have to free control handler structures in case of apd1653_init_controls or media_entity_init failure. Signed-off-by: Andy Shevchenko Cc: Sakari Ailus Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/adp1653.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c index 8ad89ffe2cc3..279d75d38188 100644 --- a/drivers/media/video/adp1653.c +++ b/drivers/media/video/adp1653.c @@ -429,12 +429,19 @@ static int adp1653_probe(struct i2c_client *client, flash->subdev.internal_ops = &adp1653_internal_ops; flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - adp1653_init_controls(flash); + ret = adp1653_init_controls(flash); + if (ret) + goto free_and_quit; ret = media_entity_init(&flash->subdev.entity, 0, NULL, 0); if (ret < 0) - kfree(flash); + goto free_and_quit; + return 0; + +free_and_quit: + v4l2_ctrl_handler_free(&flash->ctrls); + kfree(flash); return ret; } -- cgit v1.2.3 From ffd638e0e613578fbe82d5f2d9c1e5ec503a3a2b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 18 Jul 2011 11:03:05 -0300 Subject: [media] v4l: Move event documentation from SUBSCRIBE_EVENT to DQEVENT Move documentation of structures used in DQEVENT from SUBSCRIBE_EVENT to DQEVENT. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-dqevent.xml | 107 +++++++++++++++++++++ .../DocBook/media/v4l/vidioc-subscribe-event.xml | 107 --------------------- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index 7769642ee431..5200b6874654 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -135,6 +135,113 @@ + + struct <structname>v4l2_event_vsync</structname> + + &cs-str; + + + __u8 + field + The upcoming field. See &v4l2-field;. + + + +
+ + + struct <structname>v4l2_event_ctrl</structname> + + &cs-str; + + + __u32 + changes + + A bitmask that tells what has changed. See . + + + __u32 + type + + The type of the control. See &v4l2-ctrl-type;. + + + union (anonymous) + + + + + + + __s32 + value + The 32-bit value of the control for 32-bit control types. + This is 0 for string controls since the value of a string + cannot be passed using &VIDIOC-DQEVENT;. + + + + __s64 + value64 + The 64-bit value of the control for 64-bit control types. + + + __u32 + flags + + The control flags. See . + + + __s32 + minimum + + The minimum value of the control. See &v4l2-queryctrl;. + + + __s32 + maximum + + The maximum value of the control. See &v4l2-queryctrl;. + + + __s32 + step + + The step value of the control. See &v4l2-queryctrl;. + + + __s32 + default_value + + The default value value of the control. See &v4l2-queryctrl;. + + + +
+ + + Changes + + &cs-def; + + + V4L2_EVENT_CTRL_CH_VALUE + 0x0001 + This control event was triggered because the value of the control + changed. Special case: if a button control is pressed, then this + event is sent as well, even though there is not explicit value + associated with a button control. + + + V4L2_EVENT_CTRL_CH_FLAGS + 0x0002 + This control event was triggered because the control flags + changed. + + + +
&return-value; diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 69c0d8a2a3d2..275be9689d88 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -183,113 +183,6 @@ - - struct <structname>v4l2_event_vsync</structname> - - &cs-str; - - - __u8 - field - The upcoming field. See &v4l2-field;. - - - -
- - - struct <structname>v4l2_event_ctrl</structname> - - &cs-str; - - - __u32 - changes - - A bitmask that tells what has changed. See . - - - __u32 - type - - The type of the control. See &v4l2-ctrl-type;. - - - union (anonymous) - - - - - - - __s32 - value - The 32-bit value of the control for 32-bit control types. - This is 0 for string controls since the value of a string - cannot be passed using &VIDIOC-DQEVENT;. - - - - __s64 - value64 - The 64-bit value of the control for 64-bit control types. - - - __u32 - flags - - The control flags. See . - - - __s32 - minimum - - The minimum value of the control. See &v4l2-queryctrl;. - - - __s32 - maximum - - The maximum value of the control. See &v4l2-queryctrl;. - - - __s32 - step - - The step value of the control. See &v4l2-queryctrl;. - - - __s32 - default_value - - The default value value of the control. See &v4l2-queryctrl;. - - - -
- - - Changes - - &cs-def; - - - V4L2_EVENT_CTRL_CH_VALUE - 0x0001 - This control event was triggered because the value of the control - changed. Special case: if a button control is pressed, then this - event is sent as well, even though there is not explicit value - associated with a button control. - - - V4L2_EVENT_CTRL_CH_FLAGS - 0x0002 - This control event was triggered because the control flags - changed. - - - -
&return-value; -- cgit v1.2.3 From 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Jul 2011 16:38:54 -0300 Subject: [media] tuner_xc2028: Allow selection of the frequency adjustment code for XC3028 This device is not using the proper demod IF. Instead of using the IF macro, it is specifying a IF frequency. This doesn't work, as xc3028 needs to load an specific SCODE for the tuner. In this case, there's no IF table for 5 MHz. Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index aa83f07b1b0f..bcb45be44bb2 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -844,7 +844,7 @@ static int dvb_register(struct cx23885_tsport *port) static struct xc2028_ctrl ctl = { .fname = XC3028L_DEFAULT_FIRMWARE, .max_len = 64, - .demod = 5000, + .demod = XC3028_FE_DIBCOM52, /* This is true for all demods with v36 firmware? */ .type = XC2028_D2633, -- cgit v1.2.3 From d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 16 Jul 2011 00:51:00 -0300 Subject: [media] uvcvideo: Set alternate setting 0 on resume if the bus has been reset If the bus has been reset on resume, set the alternate setting to 0. This should be the default value, but some devices crash or otherwise misbehave if they don't receive a SET_INTERFACE request before any other video control request. Microdia's 0c45:6437 camera has been found to require this change or it will stop sending video data after resume. uvc_video.c] Signed-off-by: Ming Lei Signed-off-by: Laurent Pinchart Cc: stable@kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/uvc/uvc_driver.c | 2 +- drivers/media/video/uvc/uvc_video.c | 10 +++++++++- drivers/media/video/uvc/uvcvideo.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index d29f9c2d0854..e4100b1f68df 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1961,7 +1961,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) - return uvc_video_resume(stream); + return uvc_video_resume(stream, reset); } uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 8244167c8915..ffd1158628b6 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream) * buffers, making sure userspace applications are notified of the problem * instead of waiting forever. */ -int uvc_video_resume(struct uvc_streaming *stream) +int uvc_video_resume(struct uvc_streaming *stream, int reset) { int ret; + /* If the bus has been reset on resume, set the alternate setting to 0. + * This should be the default value, but some devices crash or otherwise + * misbehave if they don't receive a SET_INTERFACE request before any + * other video control request. + */ + if (reset) + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + stream->frozen = 0; ret = uvc_commit_video(stream, &stream->ctrl); diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index df32a43ca86a..cbdd49bf8b67 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -638,7 +638,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ extern int uvc_video_init(struct uvc_streaming *stream); extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream); +extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); -- cgit v1.2.3 From 47a09b082f70502195ee800bb0cd6f311b125c8f Mon Sep 17 00:00:00 2001 From: Jarod Wilson Date: Thu, 14 Jul 2011 14:20:46 -0300 Subject: [media] imon: rate-limit send_packet spew There are folks with flaky imon hardware out there that doesn't always respond to requests to write to their displays for some reason, which can flood logs quickly when something like lcdproc is trying to constantly update the display, so lets rate-limit all that error spew. Signed-off-by: Jarod Wilson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 6bc35eeb653b..caa3e3ac41cb 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -516,19 +517,19 @@ static int send_packet(struct imon_context *ictx) if (retval) { ictx->tx.busy = false; smp_rmb(); /* ensure later readers know we're not busy */ - pr_err("error submitting urb(%d)\n", retval); + pr_err_ratelimited("error submitting urb(%d)\n", retval); } else { /* Wait for transmission to complete (or abort) */ mutex_unlock(&ictx->lock); retval = wait_for_completion_interruptible( &ictx->tx.finished); if (retval) - pr_err("task interrupted\n"); + pr_err_ratelimited("task interrupted\n"); mutex_lock(&ictx->lock); retval = ictx->tx.status; if (retval) - pr_err("packet tx failed (%d)\n", retval); + pr_err_ratelimited("packet tx failed (%d)\n", retval); } kfree(control_req); @@ -830,20 +831,20 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->dev_present_intf0) { - pr_err("no iMON device present\n"); + pr_err_ratelimited("no iMON device present\n"); retval = -ENODEV; goto exit; } if (n_bytes <= 0 || n_bytes > 32) { - pr_err("invalid payload size\n"); + pr_err_ratelimited("invalid payload size\n"); retval = -EINVAL; goto exit; } @@ -869,7 +870,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); goto exit; } else { seq += 2; @@ -883,7 +884,7 @@ static ssize_t vfd_write(struct file *file, const char *buf, ictx->usb_tx_buf[7] = (unsigned char) seq; retval = send_packet(ictx); if (retval) - pr_err("send packet failed for packet #%d\n", seq / 2); + pr_err_ratelimited("send packet #%d failed\n", seq / 2); exit: mutex_unlock(&ictx->lock); @@ -912,20 +913,21 @@ static ssize_t lcd_write(struct file *file, const char *buf, ictx = file->private_data; if (!ictx) { - pr_err("no context for device\n"); + pr_err_ratelimited("no context for device\n"); return -ENODEV; } mutex_lock(&ictx->lock); if (!ictx->display_supported) { - pr_err("no iMON display present\n"); + pr_err_ratelimited("no iMON display present\n"); retval = -ENODEV; goto exit; } if (n_bytes != 8) { - pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes); + pr_err_ratelimited("invalid payload size: %d (expected 8)\n", + (int)n_bytes); retval = -EINVAL; goto exit; } @@ -937,7 +939,7 @@ static ssize_t lcd_write(struct file *file, const char *buf, retval = send_packet(ictx); if (retval) { - pr_err("send packet failed!\n"); + pr_err_ratelimited("send packet failed!\n"); goto exit; } else { dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n", -- cgit v1.2.3 From 9387f774d61b01ab71bade85e6d0bfab0b3419bd Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 6 Aug 2011 14:31:38 +0200 Subject: x86-32, amd: Move va_align definition to unbreak 32-bit build hpa reported that dfb09f9b7ab03fd367740e541a5caf830ed56726 breaks 32-bit builds with the following error message: /home/hpa/kernel/linux-tip.cpu/arch/x86/kernel/cpu/amd.c:437: undefined reference to `va_align' /home/hpa/kernel/linux-tip.cpu/arch/x86/kernel/cpu/amd.c:436: undefined reference to `va_align' This is due to the fact that va_align is a global in a 64-bit only compilation unit. Move it to mmap.c where it is visible to both subarches. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/1312633899-1131-1-git-send-email-bp@amd64.org Signed-off-by: H. Peter Anvin --- arch/x86/kernel/sys_x86_64.c | 4 ---- arch/x86/mm/mmap.c | 5 ++++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index aaa8d09c7195..fe7d2dac7fa3 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -18,10 +18,6 @@ #include #include -struct __read_mostly va_alignment va_align = { - .flags = -1, -}; - /* * Align a virtual address to avoid aliasing in the I$ on AMD F15h. * diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index d4c073630175..4b5ba85eb5c9 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -31,6 +31,10 @@ #include #include +struct __read_mostly va_alignment va_align = { + .flags = -1, +}; + static unsigned int stack_maxrandom_size(void) { unsigned int max = 0; @@ -42,7 +46,6 @@ static unsigned int stack_maxrandom_size(void) return max; } - /* * Top of mmap area (just below the process stack). * -- cgit v1.2.3 From 363699722a2a6801d098693fa15bc3b68d6b4f31 Mon Sep 17 00:00:00 2001 From: Wang Shaoyan Date: Sat, 6 Aug 2011 21:26:20 +0800 Subject: viafb: fix pointer type missmatch drivers/video/via/via-core.c: In function 'via_pci_probe': drivers/video/via/via-core.c:691: warning: assignment discards qualifiers from pointer target type Signed-off-by: Wang Shaoyan Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/via-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index eb112b621735..dd58b530c0df 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c @@ -35,7 +35,7 @@ static struct via_port_cfg adap_configs[] = { * The OLPC XO-1.5 puts the camera power and reset lines onto * GPIO 2C. */ -static const struct via_port_cfg olpc_adap_configs[] = { +static struct via_port_cfg olpc_adap_configs[] = { [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 }, [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, -- cgit v1.2.3 From 94715ba97508dd42919a7525e362efb00dde1271 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 6 Aug 2011 23:04:43 +0000 Subject: viafb: add new funcions to select a single mode This patch introduces 2 new functions for selecting a single mode based on hres, vres and refresh rate and changes some uses to use those. The advantage is that it is less error prone than doing the selection based on refresh rate everywhere and allows replacing the modetable structure. This includes a little change that users may notice: If a refresh rate was given as module parameters but does not exist in the modetable prior to this patch a refresh rate of 60 was assumed and after this patch the closest supported refresh rate to the one provided by the user is used. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 45 +++++++++-------------------------- drivers/video/via/hw.h | 4 ++-- drivers/video/via/viafbdev.c | 24 +++++++++---------- drivers/video/via/viamode.c | 56 ++++++++++++++++++++++++++++++++++---------- drivers/video/via/viamode.h | 2 ++ 5 files changed, 70 insertions(+), 61 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index c5e7833a5ae5..5e69c203163c 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2035,40 +2035,24 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, int viafb_get_pixclock(int hres, int vres, int vmode_refresh) { - int i; struct crt_mode_table *best; - struct VideoModeTable *vmode = viafb_get_mode(hres, vres); - if (!vmode) + best = viafb_get_best_mode(hres, vres, vmode_refresh); + if (!best) return RES_640X480_60HZ_PIXCLOCK; - best = &vmode->crtc[0]; - for (i = 1; i < vmode->mode_array; i++) { - if (abs(vmode->crtc[i].refresh_rate - vmode_refresh) - < abs(best->refresh_rate - vmode_refresh)) - best = &vmode->crtc[i]; - } - return 1000000000 / (best->crtc.hor_total * best->crtc.ver_total) * 1000 / best->refresh_rate; } int viafb_get_refresh(int hres, int vres, u32 long_refresh) { - int i; struct crt_mode_table *best; - struct VideoModeTable *vmode = viafb_get_mode(hres, vres); - if (!vmode) + best = viafb_get_best_mode(hres, vres, long_refresh); + if (!best) return 60; - best = &vmode->crtc[0]; - for (i = 1; i < vmode->mode_array; i++) { - if (abs(vmode->crtc[i].refresh_rate - long_refresh) - < abs(best->refresh_rate - long_refresh)) - best = &vmode->crtc[i]; - } - if (abs(best->refresh_rate - long_refresh) > 3) { if (hres == 1200 && vres == 900) return 49; /* OLPC DCON only supports 50 Hz */ @@ -2170,21 +2154,14 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ } /*According var's xres, yres fill var's other timing information*/ -void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, - struct VideoModeTable *vmode_tbl) +void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, + struct crt_mode_table *mode) { - struct crt_mode_table *crt_timing = NULL; struct display_timing crt_reg; - int i = 0, index = 0; - crt_timing = vmode_tbl->crtc; - for (i = 0; i < vmode_tbl->mode_array; i++) { - index = i; - if (crt_timing[i].refresh_rate == refresh) - break; - } - crt_reg = crt_timing[index].crtc; - var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh); + crt_reg = mode->crtc; + var->pixclock = viafb_get_pixclock(var->xres, var->yres, + mode->refresh_rate); var->left_margin = crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end); var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr; @@ -2194,8 +2171,8 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr; var->vsync_len = crt_reg.ver_sync_end; var->sync = 0; - if (crt_timing[index].h_sync_polarity == POSITIVE) + if (mode->h_sync_polarity == POSITIVE) var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (crt_timing[index].v_sync_polarity == POSITIVE) + if (mode->v_sync_polarity == POSITIVE) var->sync |= FB_SYNC_VERT_HIGH_ACT; } diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 1fd8d98f7395..3b7e1496657b 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -661,8 +661,8 @@ void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, struct VideoModeTable *vmode_tbl1, int video_bpp1); -void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh, - struct VideoModeTable *vmode_tbl); +void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, + struct crt_mode_table *mode); void __devinit viafb_init_chip_info(int chip_type); void __devinit viafb_init_dac(int set_iga); int viafb_get_pixclock(int hres, int vres, int vmode_refresh); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 3eaf607bdf48..0c0ef9568cf3 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -201,7 +201,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { int depth, refresh; - struct VideoModeTable *vmode_entry; struct viafb_par *ppar = info->par; u32 line; @@ -211,8 +210,10 @@ static int viafb_check_var(struct fb_var_screeninfo *var, if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE) return -EINVAL; - vmode_entry = viafb_get_mode(var->xres, var->yres); - if (!vmode_entry) { + /* the refresh rate is not important here, as we only want to know + * whether the resolution exists + */ + if (!viafb_get_best_mode(var->xres, var->yres, 60)) { DEBUG_MSG(KERN_INFO "viafb: Mode %dx%dx%d not supported!!\n", var->xres, var->yres, var->bits_per_pixel); @@ -254,7 +255,8 @@ static int viafb_check_var(struct fb_var_screeninfo *var, get_var_refresh(var)); /* Adjust var according to our driver's own table */ - viafb_fill_var_timing_info(var, refresh, vmode_entry); + viafb_fill_var_timing_info(var, + viafb_get_best_mode(var->xres, var->yres, refresh)); if (var->accel_flags & FB_ACCELF_TEXT && !ppar->shared->vdev->engine_mmio) var->accel_flags = 0; @@ -1816,9 +1818,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.xres_virtual = default_xres; default_var.yres_virtual = default_yres; default_var.bits_per_pixel = viafb_bpp; - viafb_fill_var_timing_info(&default_var, viafb_get_refresh( - default_var.xres, default_var.yres, viafb_refresh), - viafb_get_mode(default_var.xres, default_var.yres)); + viafb_fill_var_timing_info(&default_var, viafb_get_best_mode( + default_var.xres, default_var.yres, viafb_refresh)); viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo); viafbinfo->var = default_var; @@ -1857,9 +1858,8 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) default_var.xres_virtual = viafb_second_xres; default_var.yres_virtual = viafb_second_yres; default_var.bits_per_pixel = viafb_bpp1; - viafb_fill_var_timing_info(&default_var, viafb_get_refresh( - default_var.xres, default_var.yres, viafb_refresh1), - viafb_get_mode(default_var.xres, default_var.yres)); + viafb_fill_var_timing_info(&default_var, viafb_get_best_mode( + default_var.xres, default_var.yres, viafb_refresh1)); viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1); viafb_check_var(&default_var, viafbinfo1); @@ -2032,9 +2032,9 @@ int __init viafb_init(void) return r; #endif if (parse_mode(viafb_mode, &dummy_x, &dummy_y) - || !viafb_get_mode(dummy_x, dummy_y) + || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh) || parse_mode(viafb_mode1, &dummy_x, &dummy_y) - || !viafb_get_mode(dummy_x, dummy_y) + || !viafb_get_best_mode(dummy_x, dummy_y, viafb_refresh1) || viafb_bpp < 0 || viafb_bpp > 32 || viafb_bpp1 < 0 || viafb_bpp1 > 32 || parse_active_dev()) diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 8a9f4fcb50e9..88096e5fa077 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -863,26 +863,56 @@ int NUM_TOTAL_CLE266_ModeXregs = ARRAY_SIZE(CLE266_ModeXregs); int NUM_TOTAL_PATCH_MODE = ARRAY_SIZE(res_patch_table); -struct VideoModeTable *viafb_get_mode(int hres, int vres) +static struct VideoModeTable *get_modes(struct VideoModeTable *vmt, int n, + int hres, int vres) { - u32 i; - for (i = 0; i < ARRAY_SIZE(viafb_modes); i++) - if (viafb_modes[i].mode_array && - viafb_modes[i].crtc[0].crtc.hor_addr == hres && - viafb_modes[i].crtc[0].crtc.ver_addr == vres) + int i; + + for (i = 0; i < n; i++) + if (vmt[i].mode_array && + vmt[i].crtc[0].crtc.hor_addr == hres && + vmt[i].crtc[0].crtc.ver_addr == vres) return &viafb_modes[i]; return NULL; } +static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt, + int refresh) +{ + struct crt_mode_table *best; + int i; + + if (!vmt) + return NULL; + + best = &vmt->crtc[0]; + for (i = 1; i < vmt->mode_array; i++) { + if (abs(vmt->crtc[i].refresh_rate - refresh) + < abs(best->refresh_rate - refresh)) + best = &vmt->crtc[i]; + } + + return best; +} + +struct VideoModeTable *viafb_get_mode(int hres, int vres) +{ + return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres); +} + +struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh) +{ + return get_best_mode(viafb_get_mode(hres, vres), refresh); +} + struct VideoModeTable *viafb_get_rb_mode(int hres, int vres) { - u32 i; - for (i = 0; i < ARRAY_SIZE(viafb_rb_modes); i++) - if (viafb_rb_modes[i].mode_array && - viafb_rb_modes[i].crtc[0].crtc.hor_addr == hres && - viafb_rb_modes[i].crtc[0].crtc.ver_addr == vres) - return &viafb_rb_modes[i]; + return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres, + vres); +} - return NULL; +struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh) +{ + return get_best_mode(viafb_get_rb_mode(hres, vres), refresh); } diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h index 3751289eb450..0396581b9775 100644 --- a/drivers/video/via/viamode.h +++ b/drivers/video/via/viamode.h @@ -61,6 +61,8 @@ extern struct patch_table res_patch_table[]; extern struct VPITTable VPIT; struct VideoModeTable *viafb_get_mode(int hres, int vres); +struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh); struct VideoModeTable *viafb_get_rb_mode(int hres, int vres); +struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh); #endif /* __VIAMODE_H__ */ -- cgit v1.2.3 From 42edcb162d67e8a88c7b873941c19eab689db272 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sat, 6 Aug 2011 23:35:25 +0000 Subject: viafb: eliminate viafb_get_pixclock As there is only one user we can just insert the formula where needed. Avoids one lookup in the modetable and viafb_fill_var_timing_info does no longer depend on the modetable. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 16 ++-------------- drivers/video/via/hw.h | 1 - drivers/video/via/share.h | 4 ---- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 5e69c203163c..d7b9a9f32dee 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -2033,18 +2033,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, return 1; } -int viafb_get_pixclock(int hres, int vres, int vmode_refresh) -{ - struct crt_mode_table *best; - - best = viafb_get_best_mode(hres, vres, vmode_refresh); - if (!best) - return RES_640X480_60HZ_PIXCLOCK; - - return 1000000000 / (best->crtc.hor_total * best->crtc.ver_total) - * 1000 / best->refresh_rate; -} - int viafb_get_refresh(int hres, int vres, u32 long_refresh) { struct crt_mode_table *best; @@ -2160,8 +2148,8 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, struct display_timing crt_reg; crt_reg = mode->crtc; - var->pixclock = viafb_get_pixclock(var->xres, var->yres, - mode->refresh_rate); + var->pixclock = 1000000000 / (crt_reg.hor_total * crt_reg.ver_total) + * 1000 / mode->refresh_rate; var->left_margin = crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end); var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr; diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 3b7e1496657b..5516b025926b 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -665,7 +665,6 @@ void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, struct crt_mode_table *mode); void __devinit viafb_init_chip_info(int chip_type); void __devinit viafb_init_dac(int set_iga); -int viafb_get_pixclock(int hres, int vres, int vmode_refresh); int viafb_get_refresh(int hres, int vres, u32 float_refresh); void viafb_update_device_setting(int hres, int vres, int bpp, int flag); diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 2906b2d23434..69d882cbe709 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -636,10 +636,6 @@ #define V_SYNC_SATRT_SHADOW_INDEX 18 #define V_SYNC_END_SHADOW_INDEX 19 -/* Definition Video Mode Pixel Clock (picoseconds) -*/ -#define RES_640X480_60HZ_PIXCLOCK 39722 - /* LCD display method */ #define LCD_EXPANDSION 0x00 -- cgit v1.2.3 From ebb29fb47e198787b8b47a74cb10334cd9647a9d Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 7 Aug 2011 01:51:41 +0000 Subject: viafb: use information in var for modesetting This patch starts to use the information in var for modesetting for CRT and DVI devices. This is the right thing as it allows us to use more generic modes than the ones predefined by VIA. We do not yet allow more generic modes as check_var still limits them to the predefined ones but with this patch applied it would be really easy to do so. A problem was VIAs SAMM mode as it has 2 different modes but just one frame buffer device. This is solved by creating a pseudo var which contains enough information to use it for modesetting. Hopefully one day we can use information in var for all modes that do not involve hardware scaling. Well I'd like to say that the chance of regressions is low but it is quite likely that the behaviour in some cases changed especially when SAMM is involved. I hope we made it better than before in particular the DVI frequency check was probably broken before and hopefully works better now. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/dvi.c | 30 +++++--------- drivers/video/via/dvi.h | 3 +- drivers/video/via/hw.c | 107 ++++++++++++++++++++++-------------------------- drivers/video/via/hw.h | 4 +- 4 files changed, 61 insertions(+), 83 deletions(-) diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c index c7ff5c0e9c7e..9138e517267c 100644 --- a/drivers/video/via/dvi.c +++ b/drivers/video/via/dvi.c @@ -172,28 +172,20 @@ static int tmds_register_read_bytes(int index, u8 *buff, int buff_len) } /* DVI Set Mode */ -void viafb_dvi_set_mode(struct VideoModeTable *mode, int mode_bpp, - int set_iga) +void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga) { - struct VideoModeTable *rb_mode; - struct crt_mode_table *pDviTiming; - unsigned long desirePixelClock, maxPixelClock; - pDviTiming = mode->crtc; - desirePixelClock = pDviTiming->refresh_rate - * pDviTiming->crtc.hor_total * pDviTiming->crtc.ver_total - / 1000000; - maxPixelClock = (unsigned long)viaparinfo-> - tmds_setting_info->max_pixel_clock; - - DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n"); - - if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) { - rb_mode = viafb_get_rb_mode(mode->crtc[0].crtc.hor_addr, - mode->crtc[0].crtc.ver_addr); + struct fb_var_screeninfo dvi_var = *var; + struct crt_mode_table *rb_mode; + int maxPixelClock; + + maxPixelClock = viaparinfo->shared->tmds_setting_info.max_pixel_clock; + if (maxPixelClock && PICOS2KHZ(var->pixclock) / 1000 > maxPixelClock) { + rb_mode = viafb_get_best_rb_mode(var->xres, var->yres, 60); if (rb_mode) - mode = rb_mode; + viafb_fill_var_timing_info(&dvi_var, rb_mode); } - viafb_fill_crtc_timing(mode, mode_bpp / 8, set_iga); + + viafb_fill_crtc_timing(&dvi_var, iga); } /* Sense DVI Connector */ diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h index f473dd010977..e2116aaf797a 100644 --- a/drivers/video/via/dvi.h +++ b/drivers/video/via/dvi.h @@ -59,7 +59,6 @@ void viafb_dvi_enable(void); bool __devinit viafb_tmds_trasmitter_identify(void); void __devinit viafb_init_dvi_size(struct tmds_chip_information *tmds_chip, struct tmds_setting_information *tmds_setting); -void viafb_dvi_set_mode(struct VideoModeTable *videoMode, int mode_bpp, - int set_iga); +void viafb_dvi_set_mode(const struct fb_var_screeninfo *var, int iga); #endif /* __DVI_H__ */ diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index d7b9a9f32dee..6845c82db3cb 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1467,49 +1467,40 @@ void viafb_set_vclock(u32 clk, int set_iga) via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ } -void viafb_fill_crtc_timing(struct VideoModeTable *video_mode, int bpp_byte, - int set_iga) +static struct display_timing var_to_timing(const struct fb_var_screeninfo *var) { - struct crt_mode_table *crt_table = video_mode->crtc; - struct display_timing crt_reg; - int i; - int index = 0; - int h_addr, v_addr; - u32 clock, refresh = viafb_refresh; - - if (viafb_SAMM_ON && set_iga == IGA2) - refresh = viafb_refresh1; - - for (i = 0; i < video_mode->mode_array; i++) { - index = i; + struct display_timing timing; + + timing.hor_addr = var->xres; + timing.hor_sync_start = timing.hor_addr + var->right_margin; + timing.hor_sync_end = timing.hor_sync_start + var->hsync_len; + timing.hor_total = timing.hor_sync_end + var->left_margin; + timing.hor_blank_start = timing.hor_addr; + timing.hor_blank_end = timing.hor_total; + timing.ver_addr = var->yres; + timing.ver_sync_start = timing.ver_addr + var->lower_margin; + timing.ver_sync_end = timing.ver_sync_start + var->vsync_len; + timing.ver_total = timing.ver_sync_end + var->upper_margin; + timing.ver_blank_start = timing.ver_addr; + timing.ver_blank_end = timing.ver_total; + return timing; +} - if (crt_table[i].refresh_rate == refresh) - break; - } +void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga) +{ + struct display_timing crt_reg = var_to_timing(var); - crt_reg = crt_table[index].crtc; - crt_reg.hor_blank_end += crt_reg.hor_blank_start; - crt_reg.hor_sync_end += crt_reg.hor_sync_start; - crt_reg.ver_blank_end += crt_reg.ver_blank_start; - crt_reg.ver_sync_end += crt_reg.ver_sync_start; - h_addr = crt_reg.hor_addr; - v_addr = crt_reg.ver_addr; - if (set_iga == IGA1) + if (iga == IGA1) via_set_primary_timing(&crt_reg); - else if (set_iga == IGA2) + else if (iga == IGA2) via_set_secondary_timing(&crt_reg); - viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); - - /* load FIFO */ - if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) - && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400)) - viafb_load_FIFO_reg(set_iga, h_addr, v_addr); - - clock = crt_reg.hor_total * crt_reg.ver_total - * crt_table[index].refresh_rate; - viafb_set_vclock(clock, set_iga); + viafb_load_fetch_count_reg(var->xres, var->bits_per_pixel / 8, iga); + if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266 + && viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400) + viafb_load_FIFO_reg(iga, var->xres, var->yres); + viafb_set_vclock(PICOS2KHZ(var->pixclock) * 1000, iga); } void __devinit viafb_init_chip_info(int chip_type) @@ -1788,6 +1779,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, u8 value, index, mask; struct crt_mode_table *crt_timing; struct crt_mode_table *crt_timing1 = NULL; + struct fb_var_screeninfo var2; device_screen_off(); crt_timing = vmode_tbl->crtc; @@ -1894,17 +1886,24 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* Clear On Screen */ + if (viafb_dual_fb) { + var2 = viafbinfo1->var; + } else if (viafb_SAMM_ON) { + viafb_fill_var_timing_info(&var2, viafb_get_best_mode( + vmode_tbl1->crtc->crtc.hor_addr, + vmode_tbl1->crtc->crtc.ver_addr, viafb_refresh1)); + var2.bits_per_pixel = viafbinfo->var.bits_per_pixel; + } + /* CRT set mode */ if (viafb_CRT_ON) { - if (viafb_SAMM_ON && - viaparinfo->shared->iga2_devices & VIA_CRT) { - viafb_fill_crtc_timing(vmode_tbl1, video_bpp1 / 8, - IGA2); - } else { - viafb_fill_crtc_timing(vmode_tbl, video_bpp / 8, + if (viaparinfo->shared->iga2_devices & VIA_CRT + && viafb_SAMM_ON) + viafb_fill_crtc_timing(&var2, IGA2); + else + viafb_fill_crtc_timing(&viafbinfo->var, (viaparinfo->shared->iga1_devices & VIA_CRT) ? IGA1 : IGA2); - } /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode to 8 alignment (1368),there is several pixels (2 pixels) @@ -1918,22 +1917,12 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, } if (viafb_DVI_ON) { - if (viafb_SAMM_ON && - (viaparinfo->tmds_setting_info->iga_path == IGA2)) { - viafb_dvi_set_mode(viafb_get_mode - (viaparinfo->tmds_setting_info->h_active, - viaparinfo->tmds_setting_info-> - v_active), - video_bpp1, viaparinfo-> - tmds_setting_info->iga_path); - } else { - viafb_dvi_set_mode(viafb_get_mode - (viaparinfo->tmds_setting_info->h_active, - viaparinfo-> - tmds_setting_info->v_active), - video_bpp, viaparinfo-> - tmds_setting_info->iga_path); - } + if (viaparinfo->shared->tmds_setting_info.iga_path == IGA2 + && viafb_SAMM_ON) + viafb_dvi_set_mode(&var2, IGA2); + else + viafb_dvi_set_mode(&viafbinfo->var, + viaparinfo->tmds_setting_info->iga_path); } if (viafb_LCD_ON) { diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 5516b025926b..46f65da11e77 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -637,9 +637,7 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -void viafb_fill_crtc_timing(struct VideoModeTable *video_mode, int bpp_byte, - int set_iga); - +void viafb_fill_crtc_timing(const struct fb_var_screeninfo *var, int iga); void viafb_set_vclock(u32 CLK, int set_iga); void viafb_load_reg(int timing_value, int viafb_load_reg_num, struct io_register *reg, -- cgit v1.2.3 From 4fbf4bfe6fb5460bfd4a18ca7c7f21ffec941b07 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 7 Aug 2011 11:13:39 +0000 Subject: viafb: seperate hardware initialization This patch splits the hardware initialization out of the modesetting function which will make it easier to make it conditional and not require starting from scratch for every mode change, which is especially annoying in dual framebuffer mode. This required some minor reordering but it should not influence its functionality. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 6845c82db3cb..76fad92600f0 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1769,24 +1769,9 @@ static u8 get_sync(struct fb_info *info) return polarity; } -int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, - struct VideoModeTable *vmode_tbl1, int video_bpp1) +static void hw_init(void) { - int i, j; - int port; - u32 devices = viaparinfo->shared->iga1_devices - | viaparinfo->shared->iga2_devices; - u8 value, index, mask; - struct crt_mode_table *crt_timing; - struct crt_mode_table *crt_timing1 = NULL; - struct fb_var_screeninfo var2; - - device_screen_off(); - crt_timing = vmode_tbl->crtc; - - if (viafb_SAMM_ON == 1) { - crt_timing1 = vmode_tbl1->crtc; - } + int i; inb(VIAStatus); outb(0x00, VIAAR); @@ -1825,9 +1810,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, break; } + /* probably this should go to the scaling code one day */ viafb_write_regx(scaling_parameters, ARRAY_SIZE(scaling_parameters)); - device_off(); - via_set_state(devices, VIA_STATE_OFF); /* Fill VPIT Parameters */ /* Write Misc Register */ @@ -1853,6 +1837,31 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, inb(VIAStatus); outb(0x20, VIAAR); + load_fix_bit_crtc_reg(); +} + +int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, + struct VideoModeTable *vmode_tbl1, int video_bpp1) +{ + int j; + int port; + u32 devices = viaparinfo->shared->iga1_devices + | viaparinfo->shared->iga2_devices; + u8 value, index, mask; + struct crt_mode_table *crt_timing; + struct crt_mode_table *crt_timing1 = NULL; + struct fb_var_screeninfo var2; + + device_screen_off(); + crt_timing = vmode_tbl->crtc; + if (viafb_SAMM_ON == 1) + crt_timing1 = vmode_tbl1->crtc; + + device_off(); + via_set_state(devices, VIA_STATE_OFF); + + hw_init(); + /* Update Patch Register */ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266 @@ -1868,7 +1877,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, } } - load_fix_bit_crtc_reg(); via_set_primary_pitch(viafbinfo->fix.line_length); via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length : viafbinfo->fix.line_length); -- cgit v1.2.3 From d1520c58eb84ad1ec973a257cd835c948215aab5 Mon Sep 17 00:00:00 2001 From: Luiz Ramos Date: Thu, 14 Jul 2011 23:08:39 -0300 Subject: [media] Fix wrong register mask in gspca/sonixj.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hello, When migrating from Slackware 13.1 to 13.37 (kernel 2.6.33.x to 2.6.37.6), there was some sort of regression with the external webcam installed at the notebook (0x45:6128, SN9C325+OM6802). In the version 2.6.37.6, the images got *very* dark, making the webcam almost unusable, unless if used with direct sunlight. Tracing back what happened, I concluded that changeset 0e4d413af caused some sort of odd effects - including this - to this specific model. Signed-off-by: Luiz Carlos Ramos Acked-by: Jean-François Moine Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/gspca/sonixj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 81b8a600783b..2ad757dc2e1c 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2386,7 +2386,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x01, 0x22); msleep(100); reg01 = SCL_SEL_OD | S_PDN_INV; - reg17 &= MCK_SIZE_MASK; + reg17 &= ~MCK_SIZE_MASK; reg17 |= 0x04; /* clock / 4 */ break; } -- cgit v1.2.3 From 2d84ca215f6d67f9ba7b3d4ab32265e085229662 Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Sat, 16 Jul 2011 08:38:13 -0300 Subject: [media] tda827x: improve recection with limit frequencies tda827x is currently taking the demod IF frequency into account while seeking for the proper tuner range. This is wrong, as the demod IF frequency has nothing to do with the tuner PLL. Signed-off-by: Jose Alberto Reguero Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tuners/tda827x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/common/tuners/tda827x.c b/drivers/media/common/tuners/tda827x.c index b21b6ea68b25..e0d5b43772b8 100644 --- a/drivers/media/common/tuners/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c @@ -176,7 +176,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe, if_freq = 5000000; break; } - tuner_freq = params->frequency + if_freq; + tuner_freq = params->frequency; i = 0; while (tda827x_table[i].lomax < tuner_freq) { @@ -185,6 +185,8 @@ static int tda827xo_set_params(struct dvb_frontend *fe, i++; } + tuner_freq += if_freq; + N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); buf[0] = 0; buf[1] = (N>>8) | 0x40; @@ -540,7 +542,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe, if_freq = 5000000; break; } - tuner_freq = params->frequency + if_freq; + tuner_freq = params->frequency; if (fe->ops.info.type == FE_QAM) { dprintk("%s select tda827xa_dvbc\n", __func__); @@ -554,6 +556,8 @@ static int tda827xa_set_params(struct dvb_frontend *fe, i++; } + tuner_freq += if_freq; + N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; buf[0] = 0; // subaddress buf[1] = N >> 8; -- cgit v1.2.3 From bfe7d5f9396d5f2607454fd9ff89397fa3ba9a32 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 7 Aug 2011 13:08:45 +0000 Subject: viafb: eliminate modetable dependancy of LCD modesetting This patch removes the need for knowing the modetable structure within the LCD modesetting function. The magic 60Hz refresh rate was already there as always the first entry for a resolution was choosen based on the ascending refresh rate ordering in the modetable. For all but one this is at least 60Hz, if only higher frequencies available we choose those like the code before did. The exception is OLPC but that resolution has only one frequency so we get the same behaviour there as well. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/hw.c | 20 ++++++++------------ drivers/video/via/lcd.c | 12 +++++------- drivers/video/via/lcd.h | 5 ++--- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 76fad92600f0..30668bd17875 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1937,9 +1937,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, if (viafb_SAMM_ON && (viaparinfo->lvds_setting_info->iga_path == IGA2)) { viaparinfo->lvds_setting_info->bpp = video_bpp1; - viafb_lcd_set_mode(crt_timing1, viaparinfo-> - lvds_setting_info, - &viaparinfo->chip_info->lvds_chip_info); + viafb_lcd_set_mode(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); } else { /* IGA1 doesn't have LCD scaling, so set it center. */ if (viaparinfo->lvds_setting_info->iga_path == IGA1) { @@ -1947,18 +1946,16 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, LCD_CENTERING; } viaparinfo->lvds_setting_info->bpp = video_bpp; - viafb_lcd_set_mode(crt_timing, viaparinfo-> - lvds_setting_info, - &viaparinfo->chip_info->lvds_chip_info); + viafb_lcd_set_mode(viaparinfo->lvds_setting_info, + &viaparinfo->chip_info->lvds_chip_info); } } if (viafb_LCD2_ON) { if (viafb_SAMM_ON && (viaparinfo->lvds_setting_info2->iga_path == IGA2)) { viaparinfo->lvds_setting_info2->bpp = video_bpp1; - viafb_lcd_set_mode(crt_timing1, viaparinfo-> - lvds_setting_info2, - &viaparinfo->chip_info->lvds_chip_info2); + viafb_lcd_set_mode(viaparinfo->lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2); } else { /* IGA1 doesn't have LCD scaling, so set it center. */ if (viaparinfo->lvds_setting_info2->iga_path == IGA1) { @@ -1966,9 +1963,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, LCD_CENTERING; } viaparinfo->lvds_setting_info2->bpp = video_bpp; - viafb_lcd_set_mode(crt_timing, viaparinfo-> - lvds_setting_info2, - &viaparinfo->chip_info->lvds_chip_info2); + viafb_lcd_set_mode(viaparinfo->lvds_setting_info2, + &viaparinfo->chip_info->lvds_chip_info2); } } diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c index 0a38e4de9979..5f3b4e394e82 100644 --- a/drivers/video/via/lcd.c +++ b/drivers/video/via/lcd.c @@ -548,9 +548,8 @@ static void lcd_patch_skew(struct lvds_setting_information } /* LCD Set Mode */ -void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, - struct lvds_setting_information *plvds_setting_info, - struct lvds_chip_information *plvds_chip_info) +void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info) { int set_iga = plvds_setting_info->iga_path; int mode_bpp = plvds_setting_info->bpp; @@ -560,15 +559,14 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, int panel_vres = plvds_setting_info->lcd_panel_vres; u32 clock; struct display_timing mode_crt_reg, panel_crt_reg, timing; - struct crt_mode_table *panel_crt_table = NULL; - struct VideoModeTable *vmode_tbl = viafb_get_mode(panel_hres, - panel_vres); + struct crt_mode_table *mode_crt_table, *panel_crt_table; DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n"); /* Get mode table */ + mode_crt_table = viafb_get_best_mode(set_hres, set_vres, 60); mode_crt_reg = mode_crt_table->crtc; /* Get panel table Pointer */ - panel_crt_table = vmode_tbl->crtc; + panel_crt_table = viafb_get_best_mode(panel_hres, panel_vres, 60); panel_crt_reg = panel_crt_table->crtc; DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n"); if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h index 3b9e5397aa69..77ca7b862e68 100644 --- a/drivers/video/via/lcd.h +++ b/drivers/video/via/lcd.h @@ -76,9 +76,8 @@ void __devinit viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, struct lvds_setting_information *plvds_setting_info); -void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table, - struct lvds_setting_information *plvds_setting_info, - struct lvds_chip_information *plvds_chip_info); +void viafb_lcd_set_mode(struct lvds_setting_information *plvds_setting_info, + struct lvds_chip_information *plvds_chip_info); bool __devinit viafb_lvds_trasmitter_identify(void); void viafb_init_lvds_output_interface(struct lvds_chip_information *plvds_chip_info, -- cgit v1.2.3 From 5dd72f12df00cbabc16de770b79b17ced63138be Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Sun, 7 Aug 2011 13:34:35 +0000 Subject: viafb: get rid of the remaining modetable structure assumptions This patch removes the remaining places where assumptions about the structure of the modetable were made. Aside from some places where assumptions are made that certain modes are in the modetable the only code dealing with the modetable and not just a single mode is in viamode. This will allow chaniging the modetable and use other sources for videomodes like the subsystem or EDID. Signed-off-by: Florian Tobias Schandinat --- drivers/video/via/global.c | 2 ++ drivers/video/via/global.h | 2 ++ drivers/video/via/hw.c | 23 +++++++---------------- drivers/video/via/hw.h | 3 +-- drivers/video/via/viafbdev.c | 14 +++----------- drivers/video/via/viamode.c | 4 ++-- drivers/video/via/viamode.h | 2 -- 7 files changed, 17 insertions(+), 33 deletions(-) diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c index e10d8249534c..3102171c1674 100644 --- a/drivers/video/via/global.c +++ b/drivers/video/via/global.c @@ -35,6 +35,8 @@ int viafb_LCD_ON ; int viafb_LCD2_ON; int viafb_SAMM_ON; int viafb_dual_fb; +unsigned int viafb_second_xres = 640; +unsigned int viafb_second_yres = 480; int viafb_hotplug_Xres = 640; int viafb_hotplug_Yres = 480; int viafb_hotplug_bpp = 32; diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h index ff969dc34593..275dbbbd6b81 100644 --- a/drivers/video/via/global.h +++ b/drivers/video/via/global.h @@ -67,6 +67,8 @@ extern int viafb_lcd_dsp_method; extern int viafb_lcd_mode; extern int viafb_CRT_ON; +extern unsigned int viafb_second_xres; +extern unsigned int viafb_second_yres; extern int viafb_hotplug_Xres; extern int viafb_hotplug_Yres; extern int viafb_hotplug_bpp; diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 30668bd17875..d5aaca9cfa7e 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c @@ -1840,23 +1840,16 @@ static void hw_init(void) load_fix_bit_crtc_reg(); } -int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, - struct VideoModeTable *vmode_tbl1, int video_bpp1) +int viafb_setmode(int video_bpp, int video_bpp1) { int j; int port; u32 devices = viaparinfo->shared->iga1_devices | viaparinfo->shared->iga2_devices; u8 value, index, mask; - struct crt_mode_table *crt_timing; - struct crt_mode_table *crt_timing1 = NULL; struct fb_var_screeninfo var2; device_screen_off(); - crt_timing = vmode_tbl->crtc; - if (viafb_SAMM_ON == 1) - crt_timing1 = vmode_tbl1->crtc; - device_off(); via_set_state(devices, VIA_STATE_OFF); @@ -1865,9 +1858,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* Update Patch Register */ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266 - || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400) - && vmode_tbl->crtc[0].crtc.hor_addr == 1024 - && vmode_tbl->crtc[0].crtc.ver_addr == 768) { + || viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400) + && viafbinfo->var.xres == 1024 && viafbinfo->var.yres == 768) { for (j = 0; j < res_patch_table[0].table_length; j++) { index = res_patch_table[0].io_reg_table[j].index; port = res_patch_table[0].io_reg_table[j].port; @@ -1898,8 +1890,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, var2 = viafbinfo1->var; } else if (viafb_SAMM_ON) { viafb_fill_var_timing_info(&var2, viafb_get_best_mode( - vmode_tbl1->crtc->crtc.hor_addr, - vmode_tbl1->crtc->crtc.ver_addr, viafb_refresh1)); + viafb_second_xres, viafb_second_yres, viafb_refresh1)); var2.bits_per_pixel = viafbinfo->var.bits_per_pixel; } @@ -1916,7 +1907,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode to 8 alignment (1368),there is several pixels (2 pixels) on right side of screen. */ - if (vmode_tbl->crtc[0].crtc.hor_addr % 8) { + if (viafbinfo->var.xres % 8) { viafb_unlock_crt(); viafb_write_reg(CR02, VIACR, viafb_read_reg(VIACR, CR02) - 1); @@ -1974,8 +1965,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, /* If set mode normally, save resolution information for hot-plug . */ if (!viafb_hotplug) { - viafb_hotplug_Xres = vmode_tbl->crtc[0].crtc.hor_addr; - viafb_hotplug_Yres = vmode_tbl->crtc[0].crtc.ver_addr; + viafb_hotplug_Xres = viafbinfo->var.xres; + viafb_hotplug_Yres = viafbinfo->var.yres; viafb_hotplug_bpp = video_bpp; viafb_hotplug_refresh = viafb_refresh; diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 46f65da11e77..4db5b6e8d8d0 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h @@ -657,8 +657,7 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active); void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\ *p_gfx_dpa_setting); -int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, - struct VideoModeTable *vmode_tbl1, int video_bpp1); +int viafb_setmode(int video_bpp, int video_bpp1); void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, struct crt_mode_table *mode); void __devinit viafb_init_chip_info(int chip_type); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 0c0ef9568cf3..38567849a9d6 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -38,8 +38,6 @@ static char *viafb_mode1; static int viafb_bpp = 32; static int viafb_bpp1 = 32; -static unsigned int viafb_second_xres = 640; -static unsigned int viafb_second_yres = 480; static unsigned int viafb_second_offset; static int viafb_second_size; @@ -267,7 +265,6 @@ static int viafb_check_var(struct fb_var_screeninfo *var, static int viafb_set_par(struct fb_info *info) { struct viafb_par *viapar = info->par; - struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL; int refresh; DEBUG_MSG(KERN_INFO "viafb_set_par!\n"); @@ -276,10 +273,7 @@ static int viafb_set_par(struct fb_info *info) viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres, viafbinfo->var.bits_per_pixel, 0); - vmode_entry = viafb_get_mode(viafbinfo->var.xres, viafbinfo->var.yres); if (viafb_dual_fb) { - vmode_entry1 = viafb_get_mode(viafbinfo1->var.xres, - viafbinfo1->var.yres); viafb_update_device_setting(viafbinfo1->var.xres, viafbinfo1->var.yres, viafbinfo1->var.bits_per_pixel, 1); @@ -287,8 +281,6 @@ static int viafb_set_par(struct fb_info *info) DEBUG_MSG(KERN_INFO "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n", viafb_second_xres, viafb_second_yres, viafb_bpp1); - vmode_entry1 = viafb_get_mode(viafb_second_xres, - viafb_second_yres); viafb_update_device_setting(viafb_second_xres, viafb_second_yres, viafb_bpp1, 1); @@ -296,7 +288,8 @@ static int viafb_set_par(struct fb_info *info) refresh = viafb_get_refresh(info->var.xres, info->var.yres, get_var_refresh(&info->var)); - if (vmode_entry) { + if (viafb_get_best_mode(viafbinfo->var.xres, viafbinfo->var.yres, + refresh)) { if (viafb_dual_fb && viapar->iga_path == IGA2) { viafb_bpp1 = info->var.bits_per_pixel; viafb_refresh1 = refresh; @@ -309,8 +302,7 @@ static int viafb_set_par(struct fb_info *info) info->flags &= ~FBINFO_HWACCEL_DISABLED; else info->flags |= FBINFO_HWACCEL_DISABLED; - viafb_setmode(vmode_entry, info->var.bits_per_pixel, - vmode_entry1, viafb_bpp1); + viafb_setmode(info->var.bits_per_pixel, viafb_bpp1); viafb_pan_display(&info->var, info); } diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c index 88096e5fa077..0911cac1b2ff 100644 --- a/drivers/video/via/viamode.c +++ b/drivers/video/via/viamode.c @@ -896,7 +896,7 @@ static struct crt_mode_table *get_best_mode(struct VideoModeTable *vmt, return best; } -struct VideoModeTable *viafb_get_mode(int hres, int vres) +static struct VideoModeTable *viafb_get_mode(int hres, int vres) { return get_modes(viafb_modes, ARRAY_SIZE(viafb_modes), hres, vres); } @@ -906,7 +906,7 @@ struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh) return get_best_mode(viafb_get_mode(hres, vres), refresh); } -struct VideoModeTable *viafb_get_rb_mode(int hres, int vres) +static struct VideoModeTable *viafb_get_rb_mode(int hres, int vres) { return get_modes(viafb_rb_modes, ARRAY_SIZE(viafb_rb_modes), hres, vres); diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h index 0396581b9775..5917a2b00e1b 100644 --- a/drivers/video/via/viamode.h +++ b/drivers/video/via/viamode.h @@ -60,9 +60,7 @@ extern struct io_reg PM1024x768[]; extern struct patch_table res_patch_table[]; extern struct VPITTable VPIT; -struct VideoModeTable *viafb_get_mode(int hres, int vres); struct crt_mode_table *viafb_get_best_mode(int hres, int vres, int refresh); -struct VideoModeTable *viafb_get_rb_mode(int hres, int vres); struct crt_mode_table *viafb_get_best_rb_mode(int hres, int vres, int refresh); #endif /* __VIAMODE_H__ */ -- cgit v1.2.3 From f597a718296eef9622ebc1d13f4f8324fa169cef Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Fri, 1 Jul 2011 17:45:31 -0400 Subject: kconfig/streamline_config.pl: directly access LSMOD from the environment Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 12 ++---------- scripts/kconfig/streamline_config.pl | 8 ++++++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 82d2eb285b70..bd41ab29e680 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -33,17 +33,9 @@ silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< --$@ $(Kconfig) -# if no path is given, then use src directory to find file -ifdef LSMOD -LSMOD_F := $(LSMOD) -ifeq ($(findstring /,$(LSMOD)),) - LSMOD_F := $(objtree)/$(LSMOD) -endif -endif - localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -58,7 +50,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf localyesconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) $(LSMOD_F) > .tmp.config + $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index a4fe923c0131..ae34d2007f57 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -115,7 +115,7 @@ find_config; # Get the build source and top level Kconfig file (passed in) my $ksource = $ARGV[0]; my $kconfig = $ARGV[1]; -my $lsmod_file = $ARGV[2]; +my $lsmod_file = $ENV{'LSMOD'}; my @makefiles = `find $ksource -name Makefile 2>/dev/null`; chomp @makefiles; @@ -296,7 +296,11 @@ my %modules; if (defined($lsmod_file)) { if ( ! -f $lsmod_file) { - die "$lsmod_file not found"; + if ( -f $ENV{'objtree'}."/".$lsmod_file) { + $lsmod_file = $ENV{'objtree'}."/".$lsmod_file; + } else { + die "$lsmod_file not found"; + } } if ( -x $lsmod_file) { # the file is executable, run it -- cgit v1.2.3 From 22d550ae83603aa8d64d72dd1e2309cd7a96ac89 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Wed, 20 Jul 2011 00:40:09 -0400 Subject: kconfig/streamline_config.pl: use options to determine operating mode The options introduced are --localmodconfig (default) and --localyesconfig. They match the Makefile target behavior. Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 4 ++-- scripts/kconfig/streamline_config.pl | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index bd41ab29e680..4de89738827c 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -35,7 +35,7 @@ silentoldconfig: $(obj)/conf localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ (mv -f .config .config.old.1; \ @@ -50,7 +50,7 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf localyesconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated - $(Q)perl $< $(srctree) $(Kconfig) > .tmp.config + $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)sed -i s/=m/=y/ .tmp.config $(Q)if [ -f .config ]; then \ cmp -s .tmp.config .config || \ diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index ae34d2007f57..ec7afce4c88d 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -43,6 +43,7 @@ # make oldconfig # use strict; +use Getopt::Long; my $config = ".config"; @@ -112,6 +113,13 @@ sub find_config { find_config; +# Parse options +my $localmodconfig = 0; +my $localyesconfig = 0; + +GetOptions("localmodconfig" => \$localmodconfig, + "localyesconfig" => \$localyesconfig); + # Get the build source and top level Kconfig file (passed in) my $ksource = $ARGV[0]; my $kconfig = $ARGV[1]; @@ -425,7 +433,11 @@ while() { if (/^(CONFIG.*)=(m|y)/) { if (defined($configs{$1})) { - $setconfigs{$1} = $2; + if ($localyesconfig) { + $setconfigs{$1} = 'y'; + } else { + $setconfigs{$1} = $2; + } } elsif ($2 eq "m") { print "# $1 is not set\n"; next; -- cgit v1.2.3 From 50bce3e80773e06316fcb92796ff26b42348d30b Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Fri, 1 Jul 2011 18:13:03 -0400 Subject: kconfig/streamline_config.pl: merge local{mod,yes}config The two targets `localmodconfig' and `localyesconfig' only differs from the sed(1) ran on the result of `streamline_config.pl' to convert symbols set to `modules' to `yes'. This conversion can be made directly from the perl script, and thus avoid duplicating the command to generate the configuration. Cc: Steven Rostedt Signed-off-by: Arnaud Lacombe --- scripts/kconfig/Makefile | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 4de89738827c..ba573fe7c74d 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -33,7 +33,7 @@ silentoldconfig: $(obj)/conf $(Q)mkdir -p include/generated $< --$@ $(Kconfig) -localmodconfig: $(obj)/streamline_config.pl $(obj)/conf +localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf $(Q)mkdir -p include/generated $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config $(Q)if [ -f .config ]; then \ @@ -48,22 +48,6 @@ localmodconfig: $(obj)/streamline_config.pl $(obj)/conf fi $(Q)rm -f .tmp.config -localyesconfig: $(obj)/streamline_config.pl $(obj)/conf - $(Q)mkdir -p include/generated - $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config - $(Q)sed -i s/=m/=y/ .tmp.config - $(Q)if [ -f .config ]; then \ - cmp -s .tmp.config .config || \ - (mv -f .config .config.old.1; \ - mv -f .tmp.config .config; \ - $(obj)/conf --silentoldconfig $(Kconfig); \ - mv -f .config.old.1 .config.old) \ - else \ - mv -f .tmp.config .config; \ - $(obj)/conf --silentoldconfig $(Kconfig); \ - fi - $(Q)rm -f .tmp.config - # Create new linux.pot file # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files # The symlink is used to repair a deficiency in arch/um -- cgit v1.2.3 From be3ea3b9e8df64acb3606055c01291f0b58876a6 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jun 2011 19:35:29 +0100 Subject: ASoC: Use new register map API for ASoC generic physical I/O Remove all the ASoC specific physical I/O code and replace it with calls into the regmap API. The bulk write code can only be used safely if all regmap calls are locked with the CODEC lock, we need to add bulk support to the regmap API or replace the code with an open coded loop (though currently it has no users...). Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 2 + sound/soc/Kconfig | 2 + sound/soc/soc-io.c | 319 ++++++---------------------------------------------- 3 files changed, 38 insertions(+), 285 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index aa19f5a32ba8..4d04b4b86aa1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -576,6 +577,7 @@ struct snd_soc_codec { const void *reg_def_copy; const struct snd_soc_cache_ops *cache_ops; struct mutex cache_rw_mutex; + int val_bytes; /* dapm */ struct snd_soc_dapm_context dapm; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 8224db5f0434..f9054f7c1d52 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -7,6 +7,8 @@ menuconfig SND_SOC select SND_PCM select AC97_BUS if SND_SOC_AC97_BUS select SND_JACK if INPUT=y || INPUT=SND + select REGMAP_I2C if I2C + select REGMAP_SPI if SPI_MASTER ---help--- If you want ASoC support, you should say Y here and also to the diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index cca490c80589..b56e1c4bb9e6 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -13,26 +13,13 @@ #include #include +#include #include #include -#ifdef CONFIG_SPI_MASTER -static int do_spi_write(void *control, const char *data, int len) -{ - struct spi_device *spi = control; - int ret; - - ret = spi_write(spi, data, len); - if (ret < 0) - return ret; - - return len; -} -#endif - -static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value, const void *data, int len) +static int hw_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) { int ret; @@ -49,13 +36,7 @@ static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, return 0; } - ret = codec->hw_write(codec->control_data, data, len); - if (ret == len) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return regmap_write(codec->control_data, reg, value); } static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) @@ -69,8 +50,11 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) if (codec->cache_only) return -1; - BUG_ON(!codec->hw_read); - return codec->hw_read(codec, reg); + ret = regmap_read(codec->control_data, reg, &val); + if (ret == 0) + return val; + else + return ret; } ret = snd_soc_cache_read(codec, reg, &val); @@ -79,183 +63,18 @@ static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) return val; } -static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data; - - data = cpu_to_be16((reg << 12) | (value & 0xffffff)); - - return do_hw_write(codec, reg, value, &data, 2); -} - -static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data; - - data = cpu_to_be16((reg << 9) | (value & 0x1ff)); - - return do_hw_write(codec, reg, value, &data, 2); -} - -static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[2]; - - reg &= 0xff; - data[0] = reg; - data[1] = value & 0xff; - - return do_hw_write(codec, reg, value, data, 2); -} - -static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - u16 val = cpu_to_be16(value); - - data[0] = reg; - memcpy(&data[1], &val, sizeof(val)); - - return do_hw_write(codec, reg, value, data, 3); -} - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int do_i2c_read(struct snd_soc_codec *codec, - void *reg, int reglen, - void *data, int datalen) -{ - struct i2c_msg xfer[2]; - int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = reglen; - xfer[0].buf = reg; - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = datalen; - xfer[1].buf = data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret == 2) - return 0; - else if (ret < 0) - return ret; - else - return -EIO; -} -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u8 reg = r; - u8 data; - int ret; - - ret = do_i2c_read(codec, ®, 1, &data, 1); - if (ret < 0) - return 0; - return data; -} -#else -#define snd_soc_8_8_read_i2c NULL -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u8 reg = r; - u16 data; - int ret; - - ret = do_i2c_read(codec, ®, 1, &data, 2); - if (ret < 0) - return 0; - return (data >> 8) | ((data & 0xff) << 8); -} -#else -#define snd_soc_8_16_read_i2c NULL -#endif - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u16 reg = r; - u8 data; - int ret; - - ret = do_i2c_read(codec, ®, 2, &data, 1); - if (ret < 0) - return 0; - return data; -} -#else -#define snd_soc_16_8_read_i2c NULL -#endif - -static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u8 data[3]; - u16 rval = cpu_to_be16(reg); - - memcpy(data, &rval, sizeof(rval)); - data[2] = value; - - return do_hw_write(codec, reg, value, data, 3); -} - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - u16 reg = cpu_to_be16(r); - u16 data; - int ret; - - ret = do_i2c_read(codec, ®, 2, &data, 2); - if (ret < 0) - return 0; - return be16_to_cpu(data); -} -#else -#define snd_soc_16_16_read_i2c NULL -#endif - -static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 data[2]; - - data[0] = cpu_to_be16(reg); - data[1] = cpu_to_be16(value); - - return do_hw_write(codec, reg, value, data, sizeof(data)); -} - /* Primitive bulk write support for soc-cache. The data pointed to by - * `data' needs to already be in the form the hardware expects - * including any leading register specific data. Any data written - * through this function will not go through the cache as it only - * handles writing to volatile or out of bounds registers. + * `data' needs to already be in the form the hardware expects. Any + * data written through this function will not go through the cache as + * it only handles writing to volatile or out of bounds registers. + * + * This is currently only supported for devices using the regmap API + * wrappers. */ -static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, +static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, + unsigned int reg, const void *data, size_t len) { - int ret; - /* To ensure that we don't get out of sync with the cache, check * whether the base register is volatile or if we've directly asked * to bypass the cache. Out of bounds registers are considered @@ -266,66 +85,9 @@ static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int r && reg < codec->driver->reg_cache_size) return -EINVAL; - switch (codec->control_type) { -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - case SND_SOC_I2C: - ret = i2c_master_send(to_i2c_client(codec->dev), data, len); - break; -#endif -#if defined(CONFIG_SPI_MASTER) - case SND_SOC_SPI: - ret = spi_write(to_spi_device(codec->dev), data, len); - break; -#endif - default: - BUG(); - } - - if (ret == len) - return 0; - if (ret < 0) - return ret; - else - return -EIO; + return regmap_raw_write(codec->control_data, reg, data, len); } -static struct { - int addr_bits; - int data_bits; - int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); -} io_types[] = { - { - .addr_bits = 4, .data_bits = 12, - .write = snd_soc_4_12_write, - }, - { - .addr_bits = 7, .data_bits = 9, - .write = snd_soc_7_9_write, - }, - { - .addr_bits = 8, .data_bits = 8, - .write = snd_soc_8_8_write, - .i2c_read = snd_soc_8_8_read_i2c, - }, - { - .addr_bits = 8, .data_bits = 16, - .write = snd_soc_8_16_write, - .i2c_read = snd_soc_8_16_read_i2c, - }, - { - .addr_bits = 16, .data_bits = 8, - .write = snd_soc_16_8_write, - .i2c_read = snd_soc_16_8_read_i2c, - }, - { - .addr_bits = 16, .data_bits = 16, - .write = snd_soc_16_16_write, - .i2c_read = snd_soc_16_16_read_i2c, - }, -}; - /** * snd_soc_codec_set_cache_io: Set up standard I/O functions. * @@ -349,47 +111,34 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, int addr_bits, int data_bits, enum snd_soc_control_type control) { - int i; - - for (i = 0; i < ARRAY_SIZE(io_types); i++) - if (io_types[i].addr_bits == addr_bits && - io_types[i].data_bits == data_bits) - break; - if (i == ARRAY_SIZE(io_types)) { - printk(KERN_ERR - "No I/O functions for %d bit address %d bit data\n", - addr_bits, data_bits); - return -EINVAL; - } + struct regmap_config config; - codec->write = io_types[i].write; + memset(&config, 0, sizeof(config)); + codec->write = hw_write; codec->read = hw_read; codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; + config.reg_bits = addr_bits; + config.val_bits = data_bits; + switch (control) { case SND_SOC_I2C: -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - codec->hw_write = (hw_write_t)i2c_master_send; -#endif - if (io_types[i].i2c_read) - codec->hw_read = io_types[i].i2c_read; - - codec->control_data = container_of(codec->dev, - struct i2c_client, - dev); + codec->control_data = regmap_init_i2c(to_i2c_client(codec->dev), + &config); break; case SND_SOC_SPI: -#ifdef CONFIG_SPI_MASTER - codec->hw_write = do_spi_write; -#endif - - codec->control_data = container_of(codec->dev, - struct spi_device, - dev); + codec->control_data = regmap_init_spi(to_spi_device(codec->dev), + &config); break; + + default: + return -EINVAL; } + if (IS_ERR(codec->control_data)) + return PTR_ERR(codec->control_data); + return 0; } EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); -- cgit v1.2.3 From 0671da189c1d75eec5f6aba786d57d25209dd2bc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 24 Jul 2011 12:23:37 +0100 Subject: ASoC: Add regmap as a control type Allow drivers to set up their own regmap API structures. This is mainly useful with MFDs where the core driver will have set up regmap at the minute, though it may make sense to push the existing regmap setup out of the core into the drivers. Signed-off-by: Mark Brown Acked-by: Liam Girdwood --- include/sound/soc.h | 1 + sound/soc/soc-io.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 4d04b4b86aa1..d02269437de3 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -261,6 +261,7 @@ extern struct snd_ac97_bus_ops soc_ac97_ops; enum snd_soc_control_type { SND_SOC_I2C = 1, SND_SOC_SPI, + SND_SOC_REGMAP, }; enum snd_soc_compress_type { diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index b56e1c4bb9e6..e471ed667fe9 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c @@ -132,6 +132,10 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, &config); break; + case SND_SOC_REGMAP: + /* Device has made its own regmap arrangements */ + break; + default: return -EINVAL; } -- cgit v1.2.3 From 9f0fa7991af382bfa8c9575d2457a0b6ad03ac4c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jun 2011 06:08:32 +0000 Subject: sh: ecovec: add renesas_usbhs DMAEngine support Signed-off-by: Kuninori Morimoto Signed-off-by: Paul Mundt --- arch/sh/boards/mach-ecovec24/setup.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index b24d69d509e7..22faf2a2d8fc 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -248,6 +248,10 @@ static struct renesas_usbhs_platform_info usbhs_info = { .driver_param = { .buswait_bwait = 4, .detection_delay = 5, + .d0_tx_id = SHDMA_SLAVE_USB1D0_TX, + .d0_rx_id = SHDMA_SLAVE_USB1D0_RX, + .d1_tx_id = SHDMA_SLAVE_USB1D1_TX, + .d1_rx_id = SHDMA_SLAVE_USB1D1_RX, }, }; -- cgit v1.2.3 From 13049537007dee73a76f0a30fcbc24d02c6fa9e4 Mon Sep 17 00:00:00 2001 From: Joseph Handzik Date: Mon, 8 Aug 2011 11:40:15 +0200 Subject: cciss: Adds simple mode functionality Signed-off-by: Joseph Handzik Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- Documentation/blockdev/cciss.txt | 10 +++++++ drivers/block/cciss.c | 56 ++++++++++++++++++++++++++++++++-------- drivers/block/cciss.h | 1 + 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Documentation/blockdev/cciss.txt b/Documentation/blockdev/cciss.txt index c00c6a5ab21f..71464e09ec18 100644 --- a/Documentation/blockdev/cciss.txt +++ b/Documentation/blockdev/cciss.txt @@ -78,6 +78,16 @@ The device naming scheme is: /dev/cciss/c1d1p2 Controller 1, disk 1, partition 2 /dev/cciss/c1d1p3 Controller 1, disk 1, partition 3 +CCISS simple mode support +------------------------- + +The "cciss_simple_mode=1" boot parameter may be used to prevent the driver +from putting the controller into "performant" mode. The difference is that +with simple mode, each command completion requires an interrupt, while with +"performant mode" (the default, and ordinarily better performing) it is +possible to have multiple command completions indicated by a single +interrupt. + SCSI tape drive and medium changer support ------------------------------------------ diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8f4ef656a1af..61f0b5b6a415 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -68,6 +68,10 @@ static int cciss_tape_cmds = 6; module_param(cciss_tape_cmds, int, 0644); MODULE_PARM_DESC(cciss_tape_cmds, "number of commands to allocate for tape devices (default: 6)"); +static int cciss_simple_mode; +module_param(cciss_simple_mode, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(cciss_simple_mode, + "Use 'simple mode' rather than 'performant mode'"); static DEFINE_MUTEX(cciss_mutex); static struct proc_dir_entry *proc_cciss; @@ -176,6 +180,7 @@ static void cciss_geometry_inquiry(ctlr_info_t *h, int logvol, unsigned int block_size, InquiryData_struct *inq_buff, drive_info_struct *drv); static void __devinit cciss_interrupt_mode(ctlr_info_t *); +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h); static void start_io(ctlr_info_t *h); static int sendcmd_withirq(ctlr_info_t *h, __u8 cmd, void *buff, size_t size, __u8 page_code, unsigned char scsi3addr[], @@ -388,7 +393,7 @@ static void cciss_seq_show_header(struct seq_file *seq) h->product_name, (unsigned long)h->board_id, h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], - h->firm_ver[3], (unsigned int)h->intr[PERF_MODE_INT], + h->firm_ver[3], (unsigned int)h->intr[h->intr_mode], h->num_luns, h->Qdepth, h->commands_outstanding, h->maxQsinceinit, h->max_outstanding, h->maxSG); @@ -3984,6 +3989,9 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) { __u32 trans_support; + if (cciss_simple_mode) + return; + dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); /* Attempt to put controller into performant mode if supported */ /* Does board support performant mode? */ @@ -4081,7 +4089,7 @@ static void __devinit cciss_interrupt_mode(ctlr_info_t *h) default_int_mode: #endif /* CONFIG_PCI_MSI */ /* if we get here we're going to use the default interrupt mode */ - h->intr[PERF_MODE_INT] = h->pdev->irq; + h->intr[h->intr_mode] = h->pdev->irq; return; } @@ -4341,6 +4349,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) } cciss_enable_scsi_prefetch(h); cciss_p600_dma_prefetch_quirk(h); + err = cciss_enter_simple_mode(h); + if (err) + goto err_out_free_res; cciss_put_controller_into_performant_mode(h); return 0; @@ -4843,20 +4854,20 @@ static int cciss_request_irq(ctlr_info_t *h, irqreturn_t (*intxhandler)(int, void *)) { if (h->msix_vector || h->msi_vector) { - if (!request_irq(h->intr[PERF_MODE_INT], msixhandler, + if (!request_irq(h->intr[h->intr_mode], msixhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get msi irq %d" - " for %s\n", h->intr[PERF_MODE_INT], + " for %s\n", h->intr[h->intr_mode], h->devname); return -1; } - if (!request_irq(h->intr[PERF_MODE_INT], intxhandler, + if (!request_irq(h->intr[h->intr_mode], intxhandler, IRQF_DISABLED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", - h->intr[PERF_MODE_INT], h->devname); + h->intr[h->intr_mode], h->devname); return -1; } @@ -4887,7 +4898,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h) { int ctlr = h->ctlr; - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); #ifdef CONFIG_PCI_MSI if (h->msix_vector) pci_disable_msix(h->pdev); @@ -4953,6 +4964,7 @@ reinit_after_soft_reset: h = hba[i]; h->pdev = pdev; h->busy_initializing = 1; + h->intr_mode = cciss_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; INIT_LIST_HEAD(&h->cmpQ); INIT_LIST_HEAD(&h->reqQ); mutex_init(&h->busy_shutting_down); @@ -5009,7 +5021,7 @@ reinit_after_soft_reset: dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n", h->devname, pdev->device, pci_name(pdev), - h->intr[PERF_MODE_INT], dac ? "" : " not"); + h->intr[h->intr_mode], dac ? "" : " not"); if (cciss_allocate_cmd_pool(h)) goto clean4; @@ -5056,7 +5068,7 @@ reinit_after_soft_reset: spin_lock_irqsave(&h->lock, flags); h->access.set_intr_mask(h, CCISS_INTR_OFF); spin_unlock_irqrestore(&h->lock, flags); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); rc = cciss_request_irq(h, cciss_msix_discard_completions, cciss_intx_discard_completions); if (rc) { @@ -5133,7 +5145,7 @@ clean4: cciss_free_cmd_pool(h); cciss_free_scatterlists(h); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); clean2: unregister_blkdev(h->major, h->devname); clean1: @@ -5172,9 +5184,31 @@ static void cciss_shutdown(struct pci_dev *pdev) if (return_code != IO_OK) dev_warn(&h->pdev->dev, "Error flushing cache\n"); h->access.set_intr_mask(h, CCISS_INTR_OFF); - free_irq(h->intr[PERF_MODE_INT], h); + free_irq(h->intr[h->intr_mode], h); } +static int __devinit cciss_enter_simple_mode(struct ctlr_info *h) +{ + u32 trans_support; + + trans_support = readl(&(h->cfgtable->TransportSupport)); + if (!(trans_support & SIMPLE_MODE)) + return -ENOTSUPP; + + h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); + writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); + writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); + cciss_wait_for_mode_change_ack(h); + print_cfg_table(h); + if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { + dev_warn(&h->pdev->dev, "unable to get board into simple mode\n"); + return -ENODEV; + } + h->transMethod = CFGTBL_Trans_Simple; + return 0; +} + + static void __devexit cciss_remove_one(struct pci_dev *pdev) { ctlr_info_t *h; diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index c049548e68b7..7fda30e4a241 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -92,6 +92,7 @@ struct ctlr_info unsigned int intr[4]; unsigned int msix_vector; unsigned int msi_vector; + int intr_mode; int cciss_max_sectors; BYTE cciss_read; BYTE cciss_write; -- cgit v1.2.3 From f963d270cb7bbb8eeb57901d02b22a493e664fd2 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Mon, 8 Aug 2011 11:40:17 +0200 Subject: cciss: add transport mode attribute to sys Signed-off-by: Joseph Handzik Acked-by: Stephen M. Cameron Signed-off-by: Jens Axboe --- Documentation/ABI/testing/sysfs-bus-pci-devices-cciss | 7 +++++++ drivers/block/cciss.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss index f5bb0a3bb8c0..53d99edd1d75 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss +++ b/Documentation/ABI/testing/sysfs-bus-pci-devices-cciss @@ -71,3 +71,10 @@ Description: Value of 1 indicates the controller can honor the reset_devices a dump device, as kdump requires resetting the device in order to work reliably. +Where: /sys/bus/pci/devices//ccissX/transport_mode +Date: July 2011 +Kernel Version: 3.0 +Contact: iss_storagedev@hp.com +Description: Value of "simple" indicates that the controller has been placed + in "simple mode". Value of "performant" indicates that the + controller has been placed in "performant mode". diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 61f0b5b6a415..6da7edea700a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -641,6 +641,18 @@ static ssize_t host_store_rescan(struct device *dev, } static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); +static ssize_t host_show_transport_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ctlr_info *h = to_hba(dev); + + return snprintf(buf, 20, "%s\n", + h->transMethod & CFGTBL_Trans_Performant ? + "performant" : "simple"); +} +static DEVICE_ATTR(transport_mode, S_IRUGO, host_show_transport_mode, NULL); + static ssize_t dev_show_unique_id(struct device *dev, struct device_attribute *attr, char *buf) @@ -813,6 +825,7 @@ static DEVICE_ATTR(usage_count, S_IRUGO, cciss_show_usage_count, NULL); static struct attribute *cciss_host_attrs[] = { &dev_attr_rescan.attr, &dev_attr_resettable.attr, + &dev_attr_transport_mode.attr, NULL }; -- cgit v1.2.3 From 90b44f8ffdf6c66d190ee71b330009bf7f11a208 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 25 Jul 2011 19:57:52 +0530 Subject: dmaengine: add helper function for slave_single For clients which require a single slave transfer and dont want to be bothered about the scatterlist api, this helper gives simple API for this transfer and creates single scatterlist for DMA API Idea from Russell King Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 8fbf40e0713c..0d738c95fe4e 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -24,6 +24,7 @@ #include #include #include +#include struct scatterlist; @@ -519,6 +520,16 @@ static inline int dmaengine_slave_config(struct dma_chan *chan, (unsigned long)config); } +static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( + struct dma_chan *chan, void *buf, size_t len, + enum dma_data_direction dir, unsigned long flags) +{ + struct scatterlist sg; + sg_init_one(&sg, buf, len); + + return chan->device->device_prep_slave_sg(chan, &sg, 1, dir, flags); +} + static inline int dmaengine_terminate_all(struct dma_chan *chan) { return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0); -- cgit v1.2.3 From 4920e05c79417f9a8d236a044502e10729af91b3 Mon Sep 17 00:00:00 2001 From: Arnaud Lacombe Date: Wed, 3 Aug 2011 21:52:06 -0400 Subject: kconfig/nconf: nuke unreferenced `nohelp_text' After commit 5416857867c9cc94aba641898c567d9707de30f1, nohelp_text' is no longer referenced, nuke it. Signed-off-by: Arnaud Lacombe Signed-off-by: Michal Marek --- scripts/kconfig/nconf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index 39ca1f1640ea..b113c50209e3 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -182,8 +182,6 @@ setmod_text[] = N_( "This feature depends on another which\n" "has been configured as a module.\n" "As a result, this feature will be built as a module."), -nohelp_text[] = N_( -"There is no help available for this option.\n"), load_config_text[] = N_( "Enter the name of the configuration file you wish to load.\n" "Accept the name shown to restore the configuration you\n" -- cgit v1.2.3 From b7a949549de42e4cf8af301c63ee8af13a06a956 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jul 2011 10:45:38 +0100 Subject: ARM: gpio: at91: remove redundant include of mach/gpio.h asm/gpio.h already directly includes mach/gpio.h. Signed-off-by: Russell King --- arch/arm/mach-at91/gpio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 4615528205c8..22250420ceeb 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -22,7 +22,6 @@ #include #include -#include #include -- cgit v1.2.3 From 2f8163baada3dbd0ce891c35bc59ae46e773487a Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jul 2011 10:53:52 +0100 Subject: ARM: gpio: convert includes of mach/gpio.h and asm/gpio.h to linux/gpio.h Convert arch/arm includes of mach/gpio.h and asm/gpio.h to linux/gpio.h before we start consolidating the individual platform implementations of the gpio header files. Signed-off-by: Russell King --- arch/arm/common/scoop.c | 2 +- arch/arm/mach-at91/at91cap9_devices.c | 2 +- arch/arm/mach-at91/at91rm9200_devices.c | 2 +- arch/arm/mach-at91/at91sam9260_devices.c | 2 +- arch/arm/mach-at91/at91sam9261_devices.c | 2 +- arch/arm/mach-at91/at91sam9263_devices.c | 2 +- arch/arm/mach-at91/at91sam9g45_devices.c | 2 +- arch/arm/mach-at91/at91sam9rl_devices.c | 2 +- arch/arm/mach-at91/board-1arm.c | 2 +- arch/arm/mach-at91/board-afeb-9260v1.c | 2 +- arch/arm/mach-at91/board-cam60.c | 2 +- arch/arm/mach-at91/board-cap9adk.c | 2 +- arch/arm/mach-at91/board-carmeva.c | 2 +- arch/arm/mach-at91/board-cpu9krea.c | 2 +- arch/arm/mach-at91/board-cpuat91.c | 2 +- arch/arm/mach-at91/board-csb337.c | 2 +- arch/arm/mach-at91/board-csb637.c | 2 +- arch/arm/mach-at91/board-eb9200.c | 2 +- arch/arm/mach-at91/board-ecbat91.c | 2 +- arch/arm/mach-at91/board-kafa.c | 2 +- arch/arm/mach-at91/board-kb9202.c | 2 +- arch/arm/mach-at91/board-neocore926.c | 2 +- arch/arm/mach-at91/board-picotux200.c | 2 +- arch/arm/mach-at91/board-qil-a9260.c | 2 +- arch/arm/mach-at91/board-rm9200dk.c | 2 +- arch/arm/mach-at91/board-rm9200ek.c | 2 +- arch/arm/mach-at91/board-sam9-l9260.c | 2 +- arch/arm/mach-at91/board-sam9260ek.c | 2 +- arch/arm/mach-at91/board-sam9261ek.c | 2 +- arch/arm/mach-at91/board-sam9263ek.c | 2 +- arch/arm/mach-at91/board-sam9g20ek.c | 2 +- arch/arm/mach-at91/board-sam9m10g45ek.c | 2 +- arch/arm/mach-at91/board-sam9rlek.c | 2 +- arch/arm/mach-at91/board-usb-a9260.c | 2 +- arch/arm/mach-at91/board-usb-a9263.c | 2 +- arch/arm/mach-at91/board-yl-9200.c | 2 +- arch/arm/mach-at91/gpio.c | 3 +-- arch/arm/mach-at91/leds.c | 2 +- arch/arm/mach-at91/pm.c | 2 +- arch/arm/mach-davinci/da830.c | 2 +- arch/arm/mach-davinci/da850.c | 2 +- arch/arm/mach-davinci/gpio.c | 4 +--- arch/arm/mach-davinci/tnetv107x.c | 2 +- arch/arm/mach-imx/iomux-imx31.c | 3 +-- arch/arm/mach-imx/mach-mx27ads.c | 3 +-- arch/arm/mach-ixp2000/core.c | 4 +--- arch/arm/mach-ixp2000/ixdp2x00.c | 3 +-- arch/arm/mach-ixp4xx/dsmg600-setup.c | 3 +-- arch/arm/mach-ixp4xx/fsg-setup.c | 3 +-- arch/arm/mach-ixp4xx/nas100d-setup.c | 3 +-- arch/arm/mach-ixp4xx/nslu2-setup.c | 3 +-- arch/arm/mach-kirkwood/irq.c | 3 +-- arch/arm/mach-kirkwood/mpp.c | 3 +-- arch/arm/mach-ks8695/board-acs5k.c | 3 +-- arch/arm/mach-ks8695/board-dsm320.c | 3 +-- arch/arm/mach-ks8695/board-micrel.c | 3 +-- arch/arm/mach-ks8695/gpio.c | 3 +-- arch/arm/mach-ks8695/leds.c | 3 +-- arch/arm/mach-mmp/aspenite.c | 3 +-- arch/arm/mach-mmp/mmp2.c | 3 +-- arch/arm/mach-mmp/pxa168.c | 3 +-- arch/arm/mach-mmp/pxa910.c | 3 +-- arch/arm/mach-mmp/tavorevb.c | 3 +-- arch/arm/mach-msm/board-msm7x27.c | 3 +-- arch/arm/mach-msm/board-msm7x30.c | 3 +-- arch/arm/mach-msm/board-qsd8x50.c | 3 +-- arch/arm/mach-msm/board-sapphire.c | 3 +-- arch/arm/mach-msm/board-trout-mmc.c | 3 +-- arch/arm/mach-msm/board-trout-panel.c | 3 +-- arch/arm/mach-mv78xx0/irq.c | 3 +-- arch/arm/mach-mv78xx0/mpp.c | 3 +-- arch/arm/mach-omap1/board-ams-delta.c | 3 +-- arch/arm/mach-omap1/board-fsample.c | 3 +-- arch/arm/mach-omap1/board-generic.c | 3 +-- arch/arm/mach-omap1/board-h2-mmc.c | 3 +-- arch/arm/mach-omap1/board-h2.c | 3 +-- arch/arm/mach-omap1/board-h3-mmc.c | 3 +-- arch/arm/mach-omap1/board-h3.c | 3 +-- arch/arm/mach-omap1/board-htcherald.c | 1 - arch/arm/mach-omap1/board-innovator.c | 3 +-- arch/arm/mach-omap1/board-nokia770.c | 3 +-- arch/arm/mach-omap1/board-osk.c | 3 +-- arch/arm/mach-omap1/board-palmte.c | 3 +-- arch/arm/mach-omap1/board-palmtt.c | 2 +- arch/arm/mach-omap1/board-palmz71.c | 2 +- arch/arm/mach-omap1/board-perseus2.c | 3 +-- arch/arm/mach-omap1/board-sx1-mmc.c | 2 +- arch/arm/mach-omap1/board-sx1.c | 3 +-- arch/arm/mach-omap1/board-voiceblue.c | 2 +- arch/arm/mach-omap1/devices.c | 2 +- arch/arm/mach-omap1/fpga.c | 2 +- arch/arm/mach-omap1/irq.c | 3 +-- arch/arm/mach-omap1/leds-h2p2-debug.c | 2 +- arch/arm/mach-omap1/leds-osk.c | 3 +-- arch/arm/mach-omap1/leds.c | 2 +- arch/arm/mach-omap1/serial.c | 3 +-- arch/arm/mach-omap2/board-generic.c | 3 +-- arch/arm/mach-omap2/board-h4.c | 3 +-- arch/arm/mach-omap2/board-ldp.c | 3 +-- arch/arm/mach-omap2/devices.c | 3 +-- arch/arm/mach-orion5x/db88f5281-setup.c | 3 +-- arch/arm/mach-orion5x/dns323-setup.c | 3 +-- arch/arm/mach-orion5x/irq.c | 3 +-- arch/arm/mach-orion5x/kurobox_pro-setup.c | 3 +-- arch/arm/mach-orion5x/mv2120-setup.c | 3 +-- arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c | 3 +-- arch/arm/mach-orion5x/rd88f5181l-ge-setup.c | 3 +-- arch/arm/mach-orion5x/rd88f5182-setup.c | 3 +-- arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c | 3 +-- arch/arm/mach-orion5x/terastation_pro2-setup.c | 3 +-- arch/arm/mach-orion5x/ts209-setup.c | 3 +-- arch/arm/mach-orion5x/ts409-setup.c | 3 +-- arch/arm/mach-orion5x/wnr854t-setup.c | 3 +-- arch/arm/mach-orion5x/wrt350n-v2-setup.c | 3 +-- arch/arm/mach-pnx4008/gpio.c | 3 +-- arch/arm/mach-pnx4008/serial.c | 3 +-- arch/arm/mach-pxa/generic.c | 2 +- arch/arm/mach-pxa/include/mach/littleton.h | 2 +- arch/arm/mach-pxa/irq.c | 3 +-- arch/arm/mach-pxa/lpd270.c | 3 +-- arch/arm/mach-pxa/lubbock.c | 2 +- arch/arm/mach-pxa/mainstone.c | 3 +-- arch/arm/mach-pxa/mfp-pxa2xx.c | 3 +-- arch/arm/mach-pxa/pcm990-baseboard.c | 3 +-- arch/arm/mach-pxa/pxa25x.c | 2 +- arch/arm/mach-pxa/pxa27x.c | 2 +- arch/arm/mach-pxa/pxa3xx.c | 3 +-- arch/arm/mach-pxa/pxa95x.c | 3 +-- arch/arm/mach-pxa/saarb.c | 3 +-- arch/arm/mach-s3c2410/include/mach/h1940-latch.h | 2 +- arch/arm/mach-sa1100/generic.c | 2 +- arch/arm/mach-sa1100/gpio.c | 3 +-- arch/arm/mach-tegra/board-trimslice-pinmux.c | 3 +-- arch/arm/mach-ux500/board-mop500-u8500uib.c | 3 +-- arch/arm/plat-omap/debug-devices.c | 3 +-- arch/arm/plat-omap/debug-leds.c | 3 +-- arch/arm/plat-omap/devices.c | 3 +-- arch/arm/plat-pxa/gpio.c | 4 +--- 138 files changed, 137 insertions(+), 222 deletions(-) diff --git a/arch/arm/common/scoop.c b/arch/arm/common/scoop.c index a07b0e763a80..1cde34a080d7 100644 --- a/arch/arm/common/scoop.c +++ b/arch/arm/common/scoop.c @@ -12,11 +12,11 @@ */ #include +#include #include #include #include #include -#include #include /* PCMCIA to Scoop linkage diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c index dba0d8d8a4bd..f87f5040e78e 100644 --- a/arch/arm/mach-at91/at91cap9_devices.c +++ b/arch/arm/mach-at91/at91cap9_devices.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -23,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 7227755ffec6..978be950035a 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -14,11 +14,11 @@ #include #include +#include #include #include #include -#include #include #include diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 39f81f47b4ba..a53b3de9daa2 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -13,11 +13,11 @@ #include #include +#include #include #include #include -#include #include #include #include diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 0f917928eeb7..4e647b653339 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -21,7 +22,6 @@ #include