mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: include/asm-x86/statfs.h
This commit is contained in:
commit
e758936e02
4459 changed files with 220086 additions and 116784 deletions
|
|
@ -172,11 +172,6 @@ config FB_DEFERRED_IO
|
|||
bool
|
||||
depends on FB
|
||||
|
||||
config FB_METRONOME
|
||||
tristate
|
||||
depends on FB
|
||||
depends on FB_DEFERRED_IO
|
||||
|
||||
config FB_HECUBA
|
||||
tristate
|
||||
depends on FB
|
||||
|
|
@ -678,7 +673,6 @@ config FB_VESA
|
|||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select VIDEO_SELECT
|
||||
help
|
||||
This is the frame buffer device driver for generic VESA 2.0
|
||||
compliant graphic cards. The older VESA 1.2 cards are not supported.
|
||||
|
|
@ -1583,7 +1577,6 @@ config FB_CYBLA
|
|||
tristate "Cyberblade/i1 support"
|
||||
depends on FB && PCI && X86_32 && !64BIT
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select VIDEO_SELECT
|
||||
---help---
|
||||
This driver is supposed to support the Trident Cyberblade/i1
|
||||
graphics core integrated in the VIA VT8601A North Bridge,
|
||||
|
|
@ -1974,19 +1967,6 @@ config FB_XILINX
|
|||
framebuffer. ML300 carries a 640*480 LCD display on the board,
|
||||
ML403 uses a standard DB15 VGA connector.
|
||||
|
||||
config FB_AM200EPD
|
||||
tristate "AM-200 E-Ink EPD devkit support"
|
||||
depends on FB && ARCH_PXA && MMU
|
||||
select FB_SYS_FILLRECT
|
||||
select FB_SYS_COPYAREA
|
||||
select FB_SYS_IMAGEBLIT
|
||||
select FB_SYS_FOPS
|
||||
select FB_DEFERRED_IO
|
||||
select FB_METRONOME
|
||||
help
|
||||
This enables support for the Metronome display controller used on
|
||||
the E-Ink AM-200 EPD devkit.
|
||||
|
||||
config FB_COBALT
|
||||
tristate "Cobalt server LCD frame buffer support"
|
||||
depends on FB && MIPS_COBALT
|
||||
|
|
@ -2041,6 +2021,19 @@ config XEN_FBDEV_FRONTEND
|
|||
frame buffer driver. It communicates with a back-end
|
||||
in another domain.
|
||||
|
||||
config FB_METRONOME
|
||||
tristate "E-Ink Metronome/8track controller support"
|
||||
depends on FB
|
||||
select FB_SYS_FILLRECT
|
||||
select FB_SYS_COPYAREA
|
||||
select FB_SYS_IMAGEBLIT
|
||||
select FB_SYS_FOPS
|
||||
select FB_DEFERRED_IO
|
||||
help
|
||||
This driver implements support for the E-Ink Metronome
|
||||
controller. The pre-release name for this device was 8track
|
||||
and could also have been called by some vendors as PVI-nnnn.
|
||||
|
||||
source "drivers/video/omap/Kconfig"
|
||||
|
||||
source "drivers/video/backlight/Kconfig"
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
|
|||
|
||||
# Hardware specific drivers go first
|
||||
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
|
||||
obj-$(CONFIG_FB_AM200EPD) += am200epd.o
|
||||
obj-$(CONFIG_FB_ARC) += arcfb.o
|
||||
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
|
||||
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
|
||||
|
|
|
|||
|
|
@ -1,295 +0,0 @@
|
|||
/*
|
||||
* linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit
|
||||
*
|
||||
* Copyright (C) 2008, Jaya Kumar
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
* more details.
|
||||
*
|
||||
* Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
|
||||
*
|
||||
* This work was made possible by help and equipment support from E-Ink
|
||||
* Corporation. http://support.eink.com/community
|
||||
*
|
||||
* This driver is written to be used with the Metronome display controller.
|
||||
* on the AM200 EPD prototype kit/development kit with an E-Ink 800x600
|
||||
* Vizplex EPD on a Gumstix board using the Lyre interface board.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#include <video/metronomefb.h>
|
||||
|
||||
#include <mach/pxa-regs.h>
|
||||
|
||||
/* register offsets for gpio control */
|
||||
#define LED_GPIO_PIN 51
|
||||
#define STDBY_GPIO_PIN 48
|
||||
#define RST_GPIO_PIN 49
|
||||
#define RDY_GPIO_PIN 32
|
||||
#define ERR_GPIO_PIN 17
|
||||
#define PCBPWR_GPIO_PIN 16
|
||||
|
||||
#define AF_SEL_GPIO_N 0x3
|
||||
#define GAFR0_U_OFFSET(pin) ((pin - 16) * 2)
|
||||
#define GAFR1_L_OFFSET(pin) ((pin - 32) * 2)
|
||||
#define GAFR1_U_OFFSET(pin) ((pin - 48) * 2)
|
||||
#define GPDR1_OFFSET(pin) (pin - 32)
|
||||
#define GPCR1_OFFSET(pin) (pin - 32)
|
||||
#define GPSR1_OFFSET(pin) (pin - 32)
|
||||
#define GPCR0_OFFSET(pin) (pin)
|
||||
#define GPSR0_OFFSET(pin) (pin)
|
||||
|
||||
static void am200_set_gpio_output(int pin, int val)
|
||||
{
|
||||
u8 index;
|
||||
|
||||
index = pin >> 4;
|
||||
|
||||
switch (index) {
|
||||
case 1:
|
||||
if (val)
|
||||
GPSR0 |= (1 << GPSR0_OFFSET(pin));
|
||||
else
|
||||
GPCR0 |= (1 << GPCR0_OFFSET(pin));
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
if (val)
|
||||
GPSR1 |= (1 << GPSR1_OFFSET(pin));
|
||||
else
|
||||
GPCR1 |= (1 << GPCR1_OFFSET(pin));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "unimplemented\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void __devinit am200_init_gpio_pin(int pin, int dir)
|
||||
{
|
||||
u8 index;
|
||||
/* dir 0 is output, 1 is input
|
||||
- do 2 things here:
|
||||
- set gpio alternate function to standard gpio
|
||||
- set gpio direction to input or output */
|
||||
|
||||
index = pin >> 4;
|
||||
switch (index) {
|
||||
case 1:
|
||||
GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin));
|
||||
|
||||
if (dir)
|
||||
GPDR0 &= ~(1 << pin);
|
||||
else
|
||||
GPDR0 |= (1 << pin);
|
||||
break;
|
||||
case 2:
|
||||
GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin));
|
||||
|
||||
if (dir)
|
||||
GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
|
||||
else
|
||||
GPDR1 |= (1 << GPDR1_OFFSET(pin));
|
||||
break;
|
||||
case 3:
|
||||
GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin));
|
||||
|
||||
if (dir)
|
||||
GPDR1 &= ~(1 << GPDR1_OFFSET(pin));
|
||||
else
|
||||
GPDR1 |= (1 << GPDR1_OFFSET(pin));
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "unimplemented\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void am200_init_gpio_regs(struct metronomefb_par *par)
|
||||
{
|
||||
am200_init_gpio_pin(LED_GPIO_PIN, 0);
|
||||
am200_set_gpio_output(LED_GPIO_PIN, 0);
|
||||
|
||||
am200_init_gpio_pin(STDBY_GPIO_PIN, 0);
|
||||
am200_set_gpio_output(STDBY_GPIO_PIN, 0);
|
||||
|
||||
am200_init_gpio_pin(RST_GPIO_PIN, 0);
|
||||
am200_set_gpio_output(RST_GPIO_PIN, 0);
|
||||
|
||||
am200_init_gpio_pin(RDY_GPIO_PIN, 1);
|
||||
|
||||
am200_init_gpio_pin(ERR_GPIO_PIN, 1);
|
||||
|
||||
am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0);
|
||||
am200_set_gpio_output(PCBPWR_GPIO_PIN, 0);
|
||||
}
|
||||
|
||||
static void am200_disable_lcd_controller(struct metronomefb_par *par)
|
||||
{
|
||||
LCSR = 0xffffffff; /* Clear LCD Status Register */
|
||||
LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
|
||||
|
||||
/* we reset and just wait for things to settle */
|
||||
msleep(200);
|
||||
}
|
||||
|
||||
static void am200_enable_lcd_controller(struct metronomefb_par *par)
|
||||
{
|
||||
LCSR = 0xffffffff;
|
||||
FDADR0 = par->metromem_desc_dma;
|
||||
LCCR0 |= LCCR0_ENB;
|
||||
}
|
||||
|
||||
static void am200_init_lcdc_regs(struct metronomefb_par *par)
|
||||
{
|
||||
/* here we do:
|
||||
- disable the lcd controller
|
||||
- setup lcd control registers
|
||||
- setup dma descriptor
|
||||
- reenable lcd controller
|
||||
*/
|
||||
|
||||
/* disable the lcd controller */
|
||||
am200_disable_lcd_controller(par);
|
||||
|
||||
/* setup lcd control registers */
|
||||
LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS
|
||||
| LCCR0_QDM | LCCR0_BM | LCCR0_OUM;
|
||||
|
||||
LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */
|
||||
| (27 << 10) /* hsync pulse width - 1 */
|
||||
| (33 << 16) /* eol pixel count */
|
||||
| (33 << 24); /* bol pixel count */
|
||||
|
||||
LCCR2 = (par->info->var.yres - 1) /* lines per panel */
|
||||
| (24 << 10) /* vsync pulse width - 1 */
|
||||
| (2 << 16) /* eof pixel count */
|
||||
| (0 << 24); /* bof pixel count */
|
||||
|
||||
LCCR3 = 2 /* pixel clock divisor */
|
||||
| (24 << 8) /* AC Bias pin freq */
|
||||
| LCCR3_16BPP /* BPP */
|
||||
| LCCR3_PCP; /* PCP falling edge */
|
||||
|
||||
}
|
||||
|
||||
static void am200_post_dma_setup(struct metronomefb_par *par)
|
||||
{
|
||||
par->metromem_desc->mFDADR0 = par->metromem_desc_dma;
|
||||
par->metromem_desc->mFSADR0 = par->metromem_dma;
|
||||
par->metromem_desc->mFIDR0 = 0;
|
||||
par->metromem_desc->mLDCMD0 = par->info->var.xres
|
||||
* par->info->var.yres;
|
||||
am200_enable_lcd_controller(par);
|
||||
}
|
||||
|
||||
static void am200_free_irq(struct fb_info *info)
|
||||
{
|
||||
free_irq(IRQ_GPIO(RDY_GPIO_PIN), info);
|
||||
}
|
||||
|
||||
static irqreturn_t am200_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct fb_info *info = dev_id;
|
||||
struct metronomefb_par *par = info->par;
|
||||
|
||||
wake_up_interruptible(&par->waitq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int am200_setup_irq(struct fb_info *info)
|
||||
{
|
||||
int retval;
|
||||
|
||||
retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq,
|
||||
IRQF_DISABLED, "AM200", info);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQ_TYPE_EDGE_FALLING);
|
||||
}
|
||||
|
||||
static void am200_set_rst(struct metronomefb_par *par, int state)
|
||||
{
|
||||
am200_set_gpio_output(RST_GPIO_PIN, state);
|
||||
}
|
||||
|
||||
static void am200_set_stdby(struct metronomefb_par *par, int state)
|
||||
{
|
||||
am200_set_gpio_output(STDBY_GPIO_PIN, state);
|
||||
}
|
||||
|
||||
static int am200_wait_event(struct metronomefb_par *par)
|
||||
{
|
||||
return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ);
|
||||
}
|
||||
|
||||
static int am200_wait_event_intr(struct metronomefb_par *par)
|
||||
{
|
||||
return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ);
|
||||
}
|
||||
|
||||
static struct metronome_board am200_board = {
|
||||
.owner = THIS_MODULE,
|
||||
.free_irq = am200_free_irq,
|
||||
.setup_irq = am200_setup_irq,
|
||||
.init_gpio_regs = am200_init_gpio_regs,
|
||||
.init_lcdc_regs = am200_init_lcdc_regs,
|
||||
.post_dma_setup = am200_post_dma_setup,
|
||||
.set_rst = am200_set_rst,
|
||||
.set_stdby = am200_set_stdby,
|
||||
.met_wait_event = am200_wait_event,
|
||||
.met_wait_event_intr = am200_wait_event_intr,
|
||||
};
|
||||
|
||||
static struct platform_device *am200_device;
|
||||
|
||||
static int __init am200_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* request our platform independent driver */
|
||||
request_module("metronomefb");
|
||||
|
||||
am200_device = platform_device_alloc("metronomefb", -1);
|
||||
if (!am200_device)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_device_add_data(am200_device, &am200_board,
|
||||
sizeof(am200_board));
|
||||
|
||||
/* this _add binds metronomefb to am200. metronomefb refcounts am200 */
|
||||
ret = platform_device_add(am200_device);
|
||||
|
||||
if (ret)
|
||||
platform_device_put(am200_device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit am200_exit(void)
|
||||
{
|
||||
platform_device_unregister(am200_device);
|
||||
}
|
||||
|
||||
module_init(am200_init);
|
||||
module_exit(am200_exit);
|
||||
|
||||
MODULE_DESCRIPTION("board driver for am200 metronome epd kit");
|
||||
MODULE_AUTHOR("Jaya Kumar");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -208,6 +208,36 @@ static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
|
|||
return value;
|
||||
}
|
||||
|
||||
static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo)
|
||||
{
|
||||
/* Turn off the LCD controller and the DMA controller */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
|
||||
sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
|
||||
|
||||
/* Wait for the LCDC core to become idle */
|
||||
while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
|
||||
msleep(10);
|
||||
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
|
||||
}
|
||||
|
||||
static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo)
|
||||
{
|
||||
atmel_lcdfb_stop_nowait(sinfo);
|
||||
|
||||
/* Wait for DMA engine to become idle... */
|
||||
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo)
|
||||
{
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
|
||||
(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET)
|
||||
| ATMEL_LCDC_PWR);
|
||||
}
|
||||
|
||||
static void atmel_lcdfb_update_dma(struct fb_info *info,
|
||||
struct fb_var_screeninfo *var)
|
||||
{
|
||||
|
|
@ -378,6 +408,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
|
|||
var->red.offset = 11;
|
||||
var->blue.offset = 0;
|
||||
var->green.length = 6;
|
||||
} else if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB555) {
|
||||
var->red.offset = 10;
|
||||
var->blue.offset = 0;
|
||||
var->green.length = 5;
|
||||
} else {
|
||||
/* BGR:555 mode */
|
||||
var->red.offset = 0;
|
||||
|
|
@ -420,26 +454,8 @@ static void atmel_lcdfb_reset(struct atmel_lcdfb_info *sinfo)
|
|||
{
|
||||
might_sleep();
|
||||
|
||||
/* LCD power off */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
|
||||
|
||||
/* wait for the LCDC core to become idle */
|
||||
while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
|
||||
msleep(10);
|
||||
|
||||
/* DMA disable */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
|
||||
|
||||
/* wait for DMA engine to become idle */
|
||||
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
|
||||
msleep(10);
|
||||
|
||||
/* LCD power on */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
|
||||
(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
|
||||
|
||||
/* DMA enable */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
|
||||
atmel_lcdfb_stop(sinfo);
|
||||
atmel_lcdfb_start(sinfo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -471,14 +487,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
|
|||
info->var.xres, info->var.yres,
|
||||
info->var.xres_virtual, info->var.yres_virtual);
|
||||
|
||||
/* Turn off the LCD controller and the DMA controller */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
|
||||
|
||||
/* Wait for the LCDC core to become idle */
|
||||
while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
|
||||
msleep(10);
|
||||
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
|
||||
atmel_lcdfb_stop_nowait(sinfo);
|
||||
|
||||
if (info->var.bits_per_pixel == 1)
|
||||
info->fix.visual = FB_VISUAL_MONO01;
|
||||
|
|
@ -583,13 +592,7 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
|
|||
while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
|
||||
msleep(10);
|
||||
|
||||
dev_dbg(info->device, " * re-enable DMA engine\n");
|
||||
/* ...and enable it with updated configuration */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
|
||||
|
||||
dev_dbg(info->device, " * re-enable LCDC core\n");
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
|
||||
(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
|
||||
atmel_lcdfb_start(sinfo);
|
||||
|
||||
dev_dbg(info->device, " * DONE\n");
|
||||
|
||||
|
|
@ -939,7 +942,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
|
|||
ret = register_framebuffer(info);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to register framebuffer device: %d\n", ret);
|
||||
goto free_cmap;
|
||||
goto reset_drvdata;
|
||||
}
|
||||
|
||||
/* add selected videomode to modelist */
|
||||
|
|
@ -955,7 +958,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
|
||||
reset_drvdata:
|
||||
dev_set_drvdata(dev, NULL);
|
||||
free_cmap:
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
unregister_irqs:
|
||||
|
|
@ -992,10 +996,11 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct fb_info *info = dev_get_drvdata(dev);
|
||||
struct atmel_lcdfb_info *sinfo = info->par;
|
||||
struct atmel_lcdfb_info *sinfo;
|
||||
|
||||
if (!sinfo)
|
||||
if (!info || !info->par)
|
||||
return 0;
|
||||
sinfo = info->par;
|
||||
|
||||
cancel_work_sync(&sinfo->task);
|
||||
exit_backlight(sinfo);
|
||||
|
|
@ -1030,11 +1035,20 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg)
|
|||
struct fb_info *info = platform_get_drvdata(pdev);
|
||||
struct atmel_lcdfb_info *sinfo = info->par;
|
||||
|
||||
/*
|
||||
* We don't want to handle interrupts while the clock is
|
||||
* stopped. It may take forever.
|
||||
*/
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
|
||||
|
||||
sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL);
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0);
|
||||
if (sinfo->atmel_lcdfb_power_control)
|
||||
sinfo->atmel_lcdfb_power_control(0);
|
||||
|
||||
atmel_lcdfb_stop(sinfo);
|
||||
atmel_lcdfb_stop_clock(sinfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1044,9 +1058,15 @@ static int atmel_lcdfb_resume(struct platform_device *pdev)
|
|||
struct atmel_lcdfb_info *sinfo = info->par;
|
||||
|
||||
atmel_lcdfb_start_clock(sinfo);
|
||||
atmel_lcdfb_start(sinfo);
|
||||
if (sinfo->atmel_lcdfb_power_control)
|
||||
sinfo->atmel_lcdfb_power_control(1);
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, sinfo->saved_lcdcon);
|
||||
|
||||
/* Enable FIFO & DMA errors */
|
||||
lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI
|
||||
| ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ config LCD_CLASS_DEVICE
|
|||
To have support for your specific LCD panel you will have to
|
||||
select the proper drivers which depend on this option.
|
||||
|
||||
config LCD_CORGI
|
||||
tristate "LCD Panel support for SHARP corgi/spitz model"
|
||||
depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL
|
||||
help
|
||||
Say y here to support the LCD panels usually found on SHARP
|
||||
corgi (C7x0) and spitz (Cxx00) models.
|
||||
|
||||
config LCD_LTV350QV
|
||||
tristate "Samsung LTV350QV LCD Panel"
|
||||
depends on LCD_CLASS_DEVICE && SPI_MASTER
|
||||
|
|
@ -44,6 +51,14 @@ config LCD_ILI9320
|
|||
If you have a panel based on the ILI9320 controller chip
|
||||
then say y to include a power driver for it.
|
||||
|
||||
config LCD_TDO24M
|
||||
tristate "Toppoly TDO24M LCD Panels support"
|
||||
depends on LCD_CLASS_DEVICE && SPI_MASTER
|
||||
default n
|
||||
help
|
||||
If you have a Toppoly TDO24M series LCD panel, say y here to
|
||||
include the support for it.
|
||||
|
||||
config LCD_VGG2432A4
|
||||
tristate "VGG2432A4 LCM device support"
|
||||
depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
# Backlight & LCD drivers
|
||||
|
||||
obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
|
||||
obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o
|
||||
obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o
|
||||
obj-$(CONFIG_LCD_ILI9320) += ili9320.o
|
||||
obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
|
||||
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
|
||||
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
|
||||
|
||||
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
|
||||
|
|
|
|||
641
drivers/video/backlight/corgi_lcd.c
Normal file
641
drivers/video/backlight/corgi_lcd.c
Normal file
|
|
@ -0,0 +1,641 @@
|
|||
/*
|
||||
* LCD/Backlight Driver for Sharp Zaurus Handhelds (various models)
|
||||
*
|
||||
* Copyright (c) 2004-2006 Richard Purdie
|
||||
*
|
||||
* Based on Sharp's 2.4 Backlight Driver
|
||||
*
|
||||
* Copyright (c) 2008 Marvell International Ltd.
|
||||
* Converted to SPI device based LCD/Backlight device driver
|
||||
* by Eric Miao <eric.miao@marvell.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/lcd.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/corgi_lcd.h>
|
||||
#include <asm/mach/sharpsl_param.h>
|
||||
|
||||
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
|
||||
|
||||
/* Register Addresses */
|
||||
#define RESCTL_ADRS 0x00
|
||||
#define PHACTRL_ADRS 0x01
|
||||
#define DUTYCTRL_ADRS 0x02
|
||||
#define POWERREG0_ADRS 0x03
|
||||
#define POWERREG1_ADRS 0x04
|
||||
#define GPOR3_ADRS 0x05
|
||||
#define PICTRL_ADRS 0x06
|
||||
#define POLCTRL_ADRS 0x07
|
||||
|
||||
/* Register Bit Definitions */
|
||||
#define RESCTL_QVGA 0x01
|
||||
#define RESCTL_VGA 0x00
|
||||
|
||||
#define POWER1_VW_ON 0x01 /* VW Supply FET ON */
|
||||
#define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */
|
||||
#define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */
|
||||
|
||||
#define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */
|
||||
#define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */
|
||||
#define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */
|
||||
|
||||
#define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */
|
||||
#define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */
|
||||
#define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */
|
||||
#define POWER0_COM_ON 0x08 /* COM Power Supply ON */
|
||||
#define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */
|
||||
|
||||
#define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */
|
||||
#define POWER0_COM_OFF 0x00 /* COM Power Supply OFF */
|
||||
#define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */
|
||||
|
||||
#define PICTRL_INIT_STATE 0x01
|
||||
#define PICTRL_INIOFF 0x02
|
||||
#define PICTRL_POWER_DOWN 0x04
|
||||
#define PICTRL_COM_SIGNAL_OFF 0x08
|
||||
#define PICTRL_DAC_SIGNAL_OFF 0x10
|
||||
|
||||
#define POLCTRL_SYNC_POL_FALL 0x01
|
||||
#define POLCTRL_EN_POL_FALL 0x02
|
||||
#define POLCTRL_DATA_POL_FALL 0x04
|
||||
#define POLCTRL_SYNC_ACT_H 0x08
|
||||
#define POLCTRL_EN_ACT_L 0x10
|
||||
|
||||
#define POLCTRL_SYNC_POL_RISE 0x00
|
||||
#define POLCTRL_EN_POL_RISE 0x00
|
||||
#define POLCTRL_DATA_POL_RISE 0x00
|
||||
#define POLCTRL_SYNC_ACT_L 0x00
|
||||
#define POLCTRL_EN_ACT_H 0x00
|
||||
|
||||
#define PHACTRL_PHASE_MANUAL 0x01
|
||||
#define DEFAULT_PHAD_QVGA (9)
|
||||
#define DEFAULT_COMADJ (125)
|
||||
|
||||
struct corgi_lcd {
|
||||
struct spi_device *spi_dev;
|
||||
struct lcd_device *lcd_dev;
|
||||
struct backlight_device *bl_dev;
|
||||
|
||||
int limit_mask;
|
||||
int intensity;
|
||||
int power;
|
||||
int mode;
|
||||
char buf[2];
|
||||
|
||||
int gpio_backlight_on;
|
||||
int gpio_backlight_cont;
|
||||
int gpio_backlight_cont_inverted;
|
||||
|
||||
void (*kick_battery)(void);
|
||||
};
|
||||
|
||||
static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val);
|
||||
|
||||
static struct corgi_lcd *the_corgi_lcd;
|
||||
static unsigned long corgibl_flags;
|
||||
#define CORGIBL_SUSPENDED 0x01
|
||||
#define CORGIBL_BATTLOW 0x02
|
||||
|
||||
/*
|
||||
* This is only a psuedo I2C interface. We can't use the standard kernel
|
||||
* routines as the interface is write only. We just assume the data is acked...
|
||||
*/
|
||||
static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data)
|
||||
{
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, data);
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
static void lcdtg_i2c_send_bit(struct corgi_lcd *lcd, uint8_t data)
|
||||
{
|
||||
lcdtg_ssp_i2c_send(lcd, data);
|
||||
lcdtg_ssp_i2c_send(lcd, data | POWER0_COM_DCLK);
|
||||
lcdtg_ssp_i2c_send(lcd, data);
|
||||
}
|
||||
|
||||
static void lcdtg_i2c_send_start(struct corgi_lcd *lcd, uint8_t base)
|
||||
{
|
||||
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
|
||||
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
|
||||
lcdtg_ssp_i2c_send(lcd, base);
|
||||
}
|
||||
|
||||
static void lcdtg_i2c_send_stop(struct corgi_lcd *lcd, uint8_t base)
|
||||
{
|
||||
lcdtg_ssp_i2c_send(lcd, base);
|
||||
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK);
|
||||
lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT);
|
||||
}
|
||||
|
||||
static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd,
|
||||
uint8_t base, uint8_t data)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (data & 0x80)
|
||||
lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT);
|
||||
else
|
||||
lcdtg_i2c_send_bit(lcd, base);
|
||||
data <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void lcdtg_i2c_wait_ack(struct corgi_lcd *lcd, uint8_t base)
|
||||
{
|
||||
lcdtg_i2c_send_bit(lcd, base);
|
||||
}
|
||||
|
||||
static void lcdtg_set_common_voltage(struct corgi_lcd *lcd,
|
||||
uint8_t base_data, uint8_t data)
|
||||
{
|
||||
/* Set Common Voltage to M62332FP via I2C */
|
||||
lcdtg_i2c_send_start(lcd, base_data);
|
||||
lcdtg_i2c_send_byte(lcd, base_data, 0x9c);
|
||||
lcdtg_i2c_wait_ack(lcd, base_data);
|
||||
lcdtg_i2c_send_byte(lcd, base_data, 0x00);
|
||||
lcdtg_i2c_wait_ack(lcd, base_data);
|
||||
lcdtg_i2c_send_byte(lcd, base_data, data);
|
||||
lcdtg_i2c_wait_ack(lcd, base_data);
|
||||
lcdtg_i2c_send_stop(lcd, base_data);
|
||||
}
|
||||
|
||||
static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data)
|
||||
{
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer = {
|
||||
.len = 1,
|
||||
.cs_change = 1,
|
||||
.tx_buf = lcd->buf,
|
||||
};
|
||||
|
||||
lcd->buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f);
|
||||
spi_message_init(&msg);
|
||||
spi_message_add_tail(&xfer, &msg);
|
||||
|
||||
return spi_sync(lcd->spi_dev, &msg);
|
||||
}
|
||||
|
||||
/* Set Phase Adjust */
|
||||
static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode)
|
||||
{
|
||||
int adj;
|
||||
|
||||
switch(mode) {
|
||||
case CORGI_LCD_MODE_VGA:
|
||||
/* Setting for VGA */
|
||||
adj = sharpsl_param.phadadj;
|
||||
adj = (adj < 0) ? PHACTRL_PHASE_MANUAL :
|
||||
PHACTRL_PHASE_MANUAL | ((adj & 0xf) << 1);
|
||||
break;
|
||||
case CORGI_LCD_MODE_QVGA:
|
||||
default:
|
||||
/* Setting for QVGA */
|
||||
adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL;
|
||||
break;
|
||||
}
|
||||
|
||||
corgi_ssp_lcdtg_send(lcd, PHACTRL_ADRS, adj);
|
||||
}
|
||||
|
||||
static void corgi_lcd_power_on(struct corgi_lcd *lcd)
|
||||
{
|
||||
int comadj;
|
||||
|
||||
/* Initialize Internal Logic & Port */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
|
||||
PICTRL_POWER_DOWN | PICTRL_INIOFF |
|
||||
PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF |
|
||||
PICTRL_DAC_SIGNAL_OFF);
|
||||
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF |
|
||||
POWER0_COM_OFF | POWER0_VCC5_OFF);
|
||||
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
|
||||
|
||||
/* VDD(+8V), SVSS(-4V) ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
|
||||
mdelay(3);
|
||||
|
||||
/* DAC ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
|
||||
POWER0_COM_OFF | POWER0_VCC5_OFF);
|
||||
|
||||
/* INIB = H, INI = L */
|
||||
/* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
|
||||
PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF);
|
||||
|
||||
/* Set Common Voltage */
|
||||
comadj = sharpsl_param.comadj;
|
||||
if (comadj < 0)
|
||||
comadj = DEFAULT_COMADJ;
|
||||
|
||||
lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
|
||||
POWER0_VCC5_OFF, comadj);
|
||||
|
||||
/* VCC5 ON, DAC ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
|
||||
POWER0_COM_OFF | POWER0_VCC5_ON);
|
||||
|
||||
/* GVSS(-8V) ON, VDD ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
|
||||
mdelay(2);
|
||||
|
||||
/* COM SIGNAL ON (PICTL[3] = L) */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_INIT_STATE);
|
||||
|
||||
/* COM ON, DAC ON, VCC5_ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON |
|
||||
POWER0_COM_ON | POWER0_VCC5_ON);
|
||||
|
||||
/* VW ON, GVSS ON, VDD ON */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON);
|
||||
|
||||
/* Signals output enable */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, 0);
|
||||
|
||||
/* Set Phase Adjust */
|
||||
lcdtg_set_phadadj(lcd, lcd->mode);
|
||||
|
||||
/* Initialize for Input Signals from ATI */
|
||||
corgi_ssp_lcdtg_send(lcd, POLCTRL_ADRS,
|
||||
POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE |
|
||||
POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L |
|
||||
POLCTRL_EN_ACT_H);
|
||||
udelay(1000);
|
||||
|
||||
switch (lcd->mode) {
|
||||
case CORGI_LCD_MODE_VGA:
|
||||
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
|
||||
break;
|
||||
case CORGI_LCD_MODE_QVGA:
|
||||
default:
|
||||
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void corgi_lcd_power_off(struct corgi_lcd *lcd)
|
||||
{
|
||||
/* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */
|
||||
msleep(34);
|
||||
|
||||
/* (1)VW OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON);
|
||||
|
||||
/* (2)COM OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF);
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON);
|
||||
|
||||
/* (3)Set Common Voltage Bias 0V */
|
||||
lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF |
|
||||
POWER0_VCC5_ON, 0);
|
||||
|
||||
/* (4)GVSS OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON);
|
||||
|
||||
/* (5)VCC5 OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF);
|
||||
|
||||
/* (6)Set PDWN, INIOFF, DACOFF */
|
||||
corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS,
|
||||
PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF |
|
||||
PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF);
|
||||
|
||||
/* (7)DAC OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS,
|
||||
POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF);
|
||||
|
||||
/* (8)VDD OFF */
|
||||
corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS,
|
||||
POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF);
|
||||
}
|
||||
|
||||
static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
|
||||
int mode = CORGI_LCD_MODE_QVGA;
|
||||
|
||||
if (m->xres == 640 || m->xres == 480)
|
||||
mode = CORGI_LCD_MODE_VGA;
|
||||
|
||||
if (lcd->mode == mode)
|
||||
return 0;
|
||||
|
||||
lcdtg_set_phadadj(lcd, mode);
|
||||
|
||||
switch (mode) {
|
||||
case CORGI_LCD_MODE_VGA:
|
||||
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA);
|
||||
break;
|
||||
case CORGI_LCD_MODE_QVGA:
|
||||
default:
|
||||
corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA);
|
||||
break;
|
||||
}
|
||||
|
||||
lcd->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int corgi_lcd_set_power(struct lcd_device *ld, int power)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
|
||||
|
||||
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
|
||||
corgi_lcd_power_on(lcd);
|
||||
|
||||
if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
|
||||
corgi_lcd_power_off(lcd);
|
||||
|
||||
lcd->power = power;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int corgi_lcd_get_power(struct lcd_device *ld)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
|
||||
|
||||
return lcd->power;
|
||||
}
|
||||
|
||||
static struct lcd_ops corgi_lcd_ops = {
|
||||
.get_power = corgi_lcd_get_power,
|
||||
.set_power = corgi_lcd_set_power,
|
||||
.set_mode = corgi_lcd_set_mode,
|
||||
};
|
||||
|
||||
static int corgi_bl_get_intensity(struct backlight_device *bd)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
|
||||
|
||||
return lcd->intensity;
|
||||
}
|
||||
|
||||
static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
|
||||
{
|
||||
int cont;
|
||||
|
||||
if (intensity > 0x10)
|
||||
intensity += 0x10;
|
||||
|
||||
corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity);
|
||||
|
||||
/* Bit 5 via GPIO_BACKLIGHT_CONT */
|
||||
cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted;
|
||||
|
||||
if (gpio_is_valid(lcd->gpio_backlight_cont))
|
||||
gpio_set_value(lcd->gpio_backlight_cont, cont);
|
||||
|
||||
if (gpio_is_valid(lcd->gpio_backlight_on))
|
||||
gpio_set_value(lcd->gpio_backlight_on, intensity);
|
||||
|
||||
if (lcd->kick_battery)
|
||||
lcd->kick_battery();
|
||||
|
||||
lcd->intensity = intensity;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int corgi_bl_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
|
||||
int intensity = bd->props.brightness;
|
||||
|
||||
if (bd->props.power != FB_BLANK_UNBLANK)
|
||||
intensity = 0;
|
||||
|
||||
if (bd->props.fb_blank != FB_BLANK_UNBLANK)
|
||||
intensity = 0;
|
||||
|
||||
if (corgibl_flags & CORGIBL_SUSPENDED)
|
||||
intensity = 0;
|
||||
if (corgibl_flags & CORGIBL_BATTLOW)
|
||||
intensity &= lcd->limit_mask;
|
||||
|
||||
return corgi_bl_set_intensity(lcd, intensity);
|
||||
}
|
||||
|
||||
void corgibl_limit_intensity(int limit)
|
||||
{
|
||||
if (limit)
|
||||
corgibl_flags |= CORGIBL_BATTLOW;
|
||||
else
|
||||
corgibl_flags &= ~CORGIBL_BATTLOW;
|
||||
|
||||
backlight_update_status(the_corgi_lcd->bl_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(corgibl_limit_intensity);
|
||||
|
||||
static struct backlight_ops corgi_bl_ops = {
|
||||
.get_brightness = corgi_bl_get_intensity,
|
||||
.update_status = corgi_bl_update_status,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
corgibl_flags |= CORGIBL_SUSPENDED;
|
||||
corgi_bl_set_intensity(lcd, 0);
|
||||
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int corgi_lcd_resume(struct spi_device *spi)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
corgibl_flags &= ~CORGIBL_SUSPENDED;
|
||||
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
|
||||
backlight_update_status(lcd->bl_dev);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define corgi_lcd_suspend NULL
|
||||
#define corgi_lcd_resume NULL
|
||||
#endif
|
||||
|
||||
static int setup_gpio_backlight(struct corgi_lcd *lcd,
|
||||
struct corgi_lcd_platform_data *pdata)
|
||||
{
|
||||
struct spi_device *spi = lcd->spi_dev;
|
||||
int err;
|
||||
|
||||
lcd->gpio_backlight_on = -1;
|
||||
lcd->gpio_backlight_cont = -1;
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_backlight_on)) {
|
||||
err = gpio_request(pdata->gpio_backlight_on, "BL_ON");
|
||||
if (err) {
|
||||
dev_err(&spi->dev, "failed to request GPIO%d for "
|
||||
"backlight_on\n", pdata->gpio_backlight_on);
|
||||
return err;
|
||||
}
|
||||
|
||||
lcd->gpio_backlight_on = pdata->gpio_backlight_on;
|
||||
gpio_direction_output(lcd->gpio_backlight_on, 0);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(pdata->gpio_backlight_cont)) {
|
||||
err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT");
|
||||
if (err) {
|
||||
dev_err(&spi->dev, "failed to request GPIO%d for "
|
||||
"backlight_cont\n", pdata->gpio_backlight_cont);
|
||||
goto err_free_backlight_on;
|
||||
}
|
||||
|
||||
lcd->gpio_backlight_cont = pdata->gpio_backlight_cont;
|
||||
|
||||
/* spitz and akita use both GPIOs for backlight, and
|
||||
* have inverted polarity of GPIO_BACKLIGHT_CONT
|
||||
*/
|
||||
if (gpio_is_valid(lcd->gpio_backlight_on)) {
|
||||
lcd->gpio_backlight_cont_inverted = 1;
|
||||
gpio_direction_output(lcd->gpio_backlight_cont, 1);
|
||||
} else {
|
||||
lcd->gpio_backlight_cont_inverted = 0;
|
||||
gpio_direction_output(lcd->gpio_backlight_cont, 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_free_backlight_on:
|
||||
if (gpio_is_valid(lcd->gpio_backlight_on))
|
||||
gpio_free(lcd->gpio_backlight_on);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit corgi_lcd_probe(struct spi_device *spi)
|
||||
{
|
||||
struct corgi_lcd_platform_data *pdata = spi->dev.platform_data;
|
||||
struct corgi_lcd *lcd;
|
||||
int ret = 0;
|
||||
|
||||
if (pdata == NULL) {
|
||||
dev_err(&spi->dev, "platform data not available\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lcd = kzalloc(sizeof(struct corgi_lcd), GFP_KERNEL);
|
||||
if (!lcd) {
|
||||
dev_err(&spi->dev, "failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
lcd->spi_dev = spi;
|
||||
|
||||
lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev,
|
||||
lcd, &corgi_lcd_ops);
|
||||
if (IS_ERR(lcd->lcd_dev)) {
|
||||
ret = PTR_ERR(lcd->lcd_dev);
|
||||
goto err_free_lcd;
|
||||
}
|
||||
lcd->power = FB_BLANK_POWERDOWN;
|
||||
lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA;
|
||||
|
||||
lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev,
|
||||
lcd, &corgi_bl_ops);
|
||||
if (IS_ERR(lcd->bl_dev)) {
|
||||
ret = PTR_ERR(lcd->bl_dev);
|
||||
goto err_unregister_lcd;
|
||||
}
|
||||
lcd->bl_dev->props.max_brightness = pdata->max_intensity;
|
||||
lcd->bl_dev->props.brightness = pdata->default_intensity;
|
||||
lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
|
||||
|
||||
ret = setup_gpio_backlight(lcd, pdata);
|
||||
if (ret)
|
||||
goto err_unregister_bl;
|
||||
|
||||
lcd->kick_battery = pdata->kick_battery;
|
||||
|
||||
dev_set_drvdata(&spi->dev, lcd);
|
||||
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
|
||||
backlight_update_status(lcd->bl_dev);
|
||||
|
||||
lcd->limit_mask = pdata->limit_mask;
|
||||
the_corgi_lcd = lcd;
|
||||
return 0;
|
||||
|
||||
err_unregister_bl:
|
||||
backlight_device_unregister(lcd->bl_dev);
|
||||
err_unregister_lcd:
|
||||
lcd_device_unregister(lcd->lcd_dev);
|
||||
err_free_lcd:
|
||||
kfree(lcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit corgi_lcd_remove(struct spi_device *spi)
|
||||
{
|
||||
struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
|
||||
lcd->bl_dev->props.brightness = 0;
|
||||
backlight_update_status(lcd->bl_dev);
|
||||
backlight_device_unregister(lcd->bl_dev);
|
||||
|
||||
if (gpio_is_valid(lcd->gpio_backlight_on))
|
||||
gpio_free(lcd->gpio_backlight_on);
|
||||
|
||||
if (gpio_is_valid(lcd->gpio_backlight_cont))
|
||||
gpio_free(lcd->gpio_backlight_cont);
|
||||
|
||||
corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN);
|
||||
lcd_device_unregister(lcd->lcd_dev);
|
||||
kfree(lcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver corgi_lcd_driver = {
|
||||
.driver = {
|
||||
.name = "corgi-lcd",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = corgi_lcd_probe,
|
||||
.remove = __devexit_p(corgi_lcd_remove),
|
||||
.suspend = corgi_lcd_suspend,
|
||||
.resume = corgi_lcd_resume,
|
||||
};
|
||||
|
||||
static int __init corgi_lcd_init(void)
|
||||
{
|
||||
return spi_register_driver(&corgi_lcd_driver);
|
||||
}
|
||||
module_init(corgi_lcd_init);
|
||||
|
||||
static void __exit corgi_lcd_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&corgi_lcd_driver);
|
||||
}
|
||||
module_exit(corgi_lcd_exit);
|
||||
|
||||
MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00");
|
||||
MODULE_AUTHOR("Eric Miao <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -27,14 +27,26 @@ static int fb_notifier_callback(struct notifier_block *self,
|
|||
struct fb_event *evdata = data;
|
||||
|
||||
/* If we aren't interested in this event, skip it immediately ... */
|
||||
if (event != FB_EVENT_BLANK)
|
||||
switch (event) {
|
||||
case FB_EVENT_BLANK:
|
||||
case FB_EVENT_MODE_CHANGE:
|
||||
case FB_EVENT_MODE_CHANGE_ALL:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ld = container_of(self, struct lcd_device, fb_notif);
|
||||
if (!ld->ops)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ld->ops_lock);
|
||||
if (ld->ops)
|
||||
if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info))
|
||||
if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) {
|
||||
if (event == FB_EVENT_BLANK)
|
||||
ld->ops->set_power(ld, *(int *)evdata->data);
|
||||
else
|
||||
ld->ops->set_mode(ld, evdata->data);
|
||||
}
|
||||
mutex_unlock(&ld->ops_lock);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
396
drivers/video/backlight/tdo24m.c
Normal file
396
drivers/video/backlight/tdo24m.c
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* tdo24m - SPI-based drivers for Toppoly TDO24M series LCD panels
|
||||
*
|
||||
* Copyright (C) 2008 Marvell International Ltd.
|
||||
* Eric Miao <eric.miao@marvell.com>
|
||||
*
|
||||
* 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
|
||||
* publishhed by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/lcd.h>
|
||||
|
||||
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
|
||||
|
||||
#define TDO24M_SPI_BUFF_SIZE (4)
|
||||
#define MODE_QVGA 0
|
||||
#define MODE_VGA 1
|
||||
|
||||
struct tdo24m {
|
||||
struct spi_device *spi_dev;
|
||||
struct lcd_device *lcd_dev;
|
||||
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer;
|
||||
uint8_t *buf;
|
||||
|
||||
int power;
|
||||
int mode;
|
||||
};
|
||||
|
||||
/* use bit 30, 31 as the indicator of command parameter number */
|
||||
#define CMD0(x) ((0 << 30) | (x))
|
||||
#define CMD1(x, x1) ((1 << 30) | ((x) << 9) | 0x100 | (x1))
|
||||
#define CMD2(x, x1, x2) ((2 << 30) | ((x) << 18) | 0x20000 |\
|
||||
((x1) << 9) | 0x100 | (x2))
|
||||
#define CMD_NULL (-1)
|
||||
|
||||
static uint32_t lcd_panel_reset[] = {
|
||||
CMD0(0x1), /* reset */
|
||||
CMD0(0x0), /* nop */
|
||||
CMD0(0x0), /* nop */
|
||||
CMD0(0x0), /* nop */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_panel_on[] = {
|
||||
CMD0(0x29), /* Display ON */
|
||||
CMD2(0xB8, 0xFF, 0xF9), /* Output Control */
|
||||
CMD0(0x11), /* Sleep out */
|
||||
CMD1(0xB0, 0x16), /* Wake */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_panel_off[] = {
|
||||
CMD0(0x28), /* Display OFF */
|
||||
CMD2(0xB8, 0x80, 0x02), /* Output Control */
|
||||
CMD0(0x10), /* Sleep in */
|
||||
CMD1(0xB0, 0x00), /* Deep stand by in */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_vga_pass_through[] = {
|
||||
CMD1(0xB0, 0x16),
|
||||
CMD1(0xBC, 0x80),
|
||||
CMD1(0xE1, 0x00),
|
||||
CMD1(0x36, 0x50),
|
||||
CMD1(0x3B, 0x00),
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_qvga_pass_through[] = {
|
||||
CMD1(0xB0, 0x16),
|
||||
CMD1(0xBC, 0x81),
|
||||
CMD1(0xE1, 0x00),
|
||||
CMD1(0x36, 0x50),
|
||||
CMD1(0x3B, 0x22),
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_vga_transfer[] = {
|
||||
CMD1(0xcf, 0x02), /* Blanking period control (1) */
|
||||
CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */
|
||||
CMD1(0xd1, 0x01), /* CKV timing control on/off */
|
||||
CMD2(0xd2, 0x14, 0x00), /* CKV 1,2 timing control */
|
||||
CMD2(0xd3, 0x1a, 0x0f), /* OEV timing control */
|
||||
CMD2(0xd4, 0x1f, 0xaf), /* ASW timing control (1) */
|
||||
CMD1(0xd5, 0x14), /* ASW timing control (2) */
|
||||
CMD0(0x21), /* Invert for normally black display */
|
||||
CMD0(0x29), /* Display on */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_qvga_transfer[] = {
|
||||
CMD1(0xd6, 0x02), /* Blanking period control (1) */
|
||||
CMD2(0xd7, 0x08, 0x04), /* Blanking period control (2) */
|
||||
CMD1(0xd8, 0x01), /* CKV timing control on/off */
|
||||
CMD2(0xd9, 0x00, 0x08), /* CKV 1,2 timing control */
|
||||
CMD2(0xde, 0x05, 0x0a), /* OEV timing control */
|
||||
CMD2(0xdf, 0x0a, 0x19), /* ASW timing control (1) */
|
||||
CMD1(0xe0, 0x0a), /* ASW timing control (2) */
|
||||
CMD0(0x21), /* Invert for normally black display */
|
||||
CMD0(0x29), /* Display on */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static uint32_t lcd_panel_config[] = {
|
||||
CMD2(0xb8, 0xff, 0xf9), /* Output control */
|
||||
CMD0(0x11), /* sleep out */
|
||||
CMD1(0xba, 0x01), /* Display mode (1) */
|
||||
CMD1(0xbb, 0x00), /* Display mode (2) */
|
||||
CMD1(0x3a, 0x60), /* Display mode 18-bit RGB */
|
||||
CMD1(0xbf, 0x10), /* Drive system change control */
|
||||
CMD1(0xb1, 0x56), /* Booster operation setup */
|
||||
CMD1(0xb2, 0x33), /* Booster mode setup */
|
||||
CMD1(0xb3, 0x11), /* Booster frequency setup */
|
||||
CMD1(0xb4, 0x02), /* Op amp/system clock */
|
||||
CMD1(0xb5, 0x35), /* VCS voltage */
|
||||
CMD1(0xb6, 0x40), /* VCOM voltage */
|
||||
CMD1(0xb7, 0x03), /* External display signal */
|
||||
CMD1(0xbd, 0x00), /* ASW slew rate */
|
||||
CMD1(0xbe, 0x00), /* Dummy data for QuadData operation */
|
||||
CMD1(0xc0, 0x11), /* Sleep out FR count (A) */
|
||||
CMD1(0xc1, 0x11), /* Sleep out FR count (B) */
|
||||
CMD1(0xc2, 0x11), /* Sleep out FR count (C) */
|
||||
CMD2(0xc3, 0x20, 0x40), /* Sleep out FR count (D) */
|
||||
CMD2(0xc4, 0x60, 0xc0), /* Sleep out FR count (E) */
|
||||
CMD2(0xc5, 0x10, 0x20), /* Sleep out FR count (F) */
|
||||
CMD1(0xc6, 0xc0), /* Sleep out FR count (G) */
|
||||
CMD2(0xc7, 0x33, 0x43), /* Gamma 1 fine tuning (1) */
|
||||
CMD1(0xc8, 0x44), /* Gamma 1 fine tuning (2) */
|
||||
CMD1(0xc9, 0x33), /* Gamma 1 inclination adjustment */
|
||||
CMD1(0xca, 0x00), /* Gamma 1 blue offset adjustment */
|
||||
CMD2(0xec, 0x01, 0xf0), /* Horizontal clock cycles */
|
||||
CMD_NULL,
|
||||
};
|
||||
|
||||
static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array)
|
||||
{
|
||||
struct spi_transfer *x = &lcd->xfer;
|
||||
uint32_t data, *p = array;
|
||||
int nparams, err = 0;
|
||||
|
||||
for (; *p != CMD_NULL; p++) {
|
||||
|
||||
nparams = (*p >> 30) & 0x3;
|
||||
|
||||
data = *p << (7 - nparams);
|
||||
switch (nparams) {
|
||||
case 0:
|
||||
lcd->buf[0] = (data >> 8) & 0xff;
|
||||
lcd->buf[1] = data & 0xff;
|
||||
break;
|
||||
case 1:
|
||||
lcd->buf[0] = (data >> 16) & 0xff;
|
||||
lcd->buf[1] = (data >> 8) & 0xff;
|
||||
lcd->buf[2] = data & 0xff;
|
||||
break;
|
||||
case 2:
|
||||
lcd->buf[0] = (data >> 24) & 0xff;
|
||||
lcd->buf[1] = (data >> 16) & 0xff;
|
||||
lcd->buf[2] = (data >> 8) & 0xff;
|
||||
lcd->buf[3] = data & 0xff;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
x->len = nparams + 2;
|
||||
err = spi_sync(lcd->spi_dev, &lcd->msg);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tdo24m_adj_mode(struct tdo24m *lcd, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case MODE_VGA:
|
||||
tdo24m_writes(lcd, lcd_vga_pass_through);
|
||||
tdo24m_writes(lcd, lcd_panel_config);
|
||||
tdo24m_writes(lcd, lcd_vga_transfer);
|
||||
break;
|
||||
case MODE_QVGA:
|
||||
tdo24m_writes(lcd, lcd_qvga_pass_through);
|
||||
tdo24m_writes(lcd, lcd_panel_config);
|
||||
tdo24m_writes(lcd, lcd_qvga_transfer);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lcd->mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tdo24m_power_on(struct tdo24m *lcd)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = tdo24m_writes(lcd, lcd_panel_on);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = tdo24m_writes(lcd, lcd_panel_reset);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = tdo24m_adj_mode(lcd, lcd->mode);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tdo24m_power_off(struct tdo24m *lcd)
|
||||
{
|
||||
return tdo24m_writes(lcd, lcd_panel_off);
|
||||
}
|
||||
|
||||
static int tdo24m_power(struct tdo24m *lcd, int power)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
|
||||
ret = tdo24m_power_on(lcd);
|
||||
else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
|
||||
ret = tdo24m_power_off(lcd);
|
||||
|
||||
if (!ret)
|
||||
lcd->power = power;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int tdo24m_set_power(struct lcd_device *ld, int power)
|
||||
{
|
||||
struct tdo24m *lcd = lcd_get_data(ld);
|
||||
return tdo24m_power(lcd, power);
|
||||
}
|
||||
|
||||
static int tdo24m_get_power(struct lcd_device *ld)
|
||||
{
|
||||
struct tdo24m *lcd = lcd_get_data(ld);
|
||||
return lcd->power;
|
||||
}
|
||||
|
||||
static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m)
|
||||
{
|
||||
struct tdo24m *lcd = lcd_get_data(ld);
|
||||
int mode = MODE_QVGA;
|
||||
|
||||
if (m->xres == 640 || m->xres == 480)
|
||||
mode = MODE_VGA;
|
||||
|
||||
if (lcd->mode == mode)
|
||||
return 0;
|
||||
|
||||
return tdo24m_adj_mode(lcd, mode);
|
||||
}
|
||||
|
||||
static struct lcd_ops tdo24m_ops = {
|
||||
.get_power = tdo24m_get_power,
|
||||
.set_power = tdo24m_set_power,
|
||||
.set_mode = tdo24m_set_mode,
|
||||
};
|
||||
|
||||
static int __devinit tdo24m_probe(struct spi_device *spi)
|
||||
{
|
||||
struct tdo24m *lcd;
|
||||
struct spi_message *m;
|
||||
struct spi_transfer *x;
|
||||
int err;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_3;
|
||||
err = spi_setup(spi);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
lcd = kzalloc(sizeof(struct tdo24m), GFP_KERNEL);
|
||||
if (!lcd)
|
||||
return -ENOMEM;
|
||||
|
||||
lcd->spi_dev = spi;
|
||||
lcd->power = FB_BLANK_POWERDOWN;
|
||||
lcd->mode = MODE_VGA; /* default to VGA */
|
||||
|
||||
lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL));
|
||||
if (lcd->buf == NULL) {
|
||||
kfree(lcd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
m = &lcd->msg;
|
||||
x = &lcd->xfer;
|
||||
|
||||
spi_message_init(m);
|
||||
|
||||
x->tx_buf = &lcd->buf[0];
|
||||
spi_message_add_tail(x, m);
|
||||
|
||||
lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev,
|
||||
lcd, &tdo24m_ops);
|
||||
if (IS_ERR(lcd->lcd_dev)) {
|
||||
err = PTR_ERR(lcd->lcd_dev);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&spi->dev, lcd);
|
||||
err = tdo24m_power(lcd, FB_BLANK_UNBLANK);
|
||||
if (err)
|
||||
goto out_unregister;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unregister:
|
||||
lcd_device_unregister(lcd->lcd_dev);
|
||||
out_free:
|
||||
kfree(lcd->buf);
|
||||
kfree(lcd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit tdo24m_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
tdo24m_power(lcd, FB_BLANK_POWERDOWN);
|
||||
lcd_device_unregister(lcd->lcd_dev);
|
||||
kfree(lcd->buf);
|
||||
kfree(lcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
|
||||
{
|
||||
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
|
||||
}
|
||||
|
||||
static int tdo24m_resume(struct spi_device *spi)
|
||||
{
|
||||
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
return tdo24m_power(lcd, FB_BLANK_UNBLANK);
|
||||
}
|
||||
#else
|
||||
#define tdo24m_suspend NULL
|
||||
#define tdo24m_resume NULL
|
||||
#endif
|
||||
|
||||
/* Power down all displays on reboot, poweroff or halt */
|
||||
static void tdo24m_shutdown(struct spi_device *spi)
|
||||
{
|
||||
struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
|
||||
|
||||
tdo24m_power(lcd, FB_BLANK_POWERDOWN);
|
||||
}
|
||||
|
||||
static struct spi_driver tdo24m_driver = {
|
||||
.driver = {
|
||||
.name = "tdo24m",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = tdo24m_probe,
|
||||
.remove = __devexit_p(tdo24m_remove),
|
||||
.shutdown = tdo24m_shutdown,
|
||||
.suspend = tdo24m_suspend,
|
||||
.resume = tdo24m_resume,
|
||||
};
|
||||
|
||||
static int __init tdo24m_init(void)
|
||||
{
|
||||
return spi_register_driver(&tdo24m_driver);
|
||||
}
|
||||
module_init(tdo24m_init);
|
||||
|
||||
static void __exit tdo24m_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&tdo24m_driver);
|
||||
}
|
||||
module_exit(tdo24m_exit);
|
||||
|
||||
MODULE_AUTHOR("Eric Miao <[email protected]>");
|
||||
MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id bw2_match[] = {
|
||||
static const struct of_device_id bw2_match[] = {
|
||||
{
|
||||
.name = "bwtwo",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id cg14_match[] = {
|
||||
static const struct of_device_id cg14_match[] = {
|
||||
{
|
||||
.name = "cgfourteen",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id cg3_match[] = {
|
||||
static const struct of_device_id cg3_match[] = {
|
||||
{
|
||||
.name = "cgthree",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -34,10 +34,11 @@ static int cg6_blank(int, struct fb_info *);
|
|||
|
||||
static void cg6_imageblit(struct fb_info *, const struct fb_image *);
|
||||
static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
|
||||
static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
|
||||
static int cg6_sync(struct fb_info *);
|
||||
static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
|
||||
static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
|
||||
static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
|
||||
static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
|
||||
|
||||
/*
|
||||
* Frame buffer operations
|
||||
|
|
@ -47,6 +48,7 @@ static struct fb_ops cg6_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
.fb_setcolreg = cg6_setcolreg,
|
||||
.fb_blank = cg6_blank,
|
||||
.fb_pan_display = cg6_pan_display,
|
||||
.fb_fillrect = cg6_fillrect,
|
||||
.fb_copyarea = cg6_copyarea,
|
||||
.fb_imageblit = cg6_imageblit,
|
||||
|
|
@ -161,6 +163,7 @@ static struct fb_ops cg6_ops = {
|
|||
#define CG6_THC_MISC_INT_ENAB (1 << 5)
|
||||
#define CG6_THC_MISC_INT (1 << 4)
|
||||
#define CG6_THC_MISC_INIT 0x9f
|
||||
#define CG6_THC_CURSOFF ((65536-32) | ((65536-32) << 16))
|
||||
|
||||
/* The contents are unknown */
|
||||
struct cg6_tec {
|
||||
|
|
@ -280,6 +283,33 @@ static int cg6_sync(struct fb_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void cg6_switch_from_graph(struct cg6_par *par)
|
||||
{
|
||||
struct cg6_thc __iomem *thc = par->thc;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&par->lock, flags);
|
||||
|
||||
/* Hide the cursor. */
|
||||
sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
|
||||
|
||||
spin_unlock_irqrestore(&par->lock, flags);
|
||||
}
|
||||
|
||||
static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
struct cg6_par *par = (struct cg6_par *)info->par;
|
||||
|
||||
/* We just use this to catch switches out of
|
||||
* graphics mode.
|
||||
*/
|
||||
cg6_switch_from_graph(par);
|
||||
|
||||
if (var->xoffset || var->yoffset || var->vmode)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cg6_fillrect - Draws a rectangle on the screen.
|
||||
*
|
||||
|
|
@ -643,9 +673,13 @@ static void __devinit cg6_chip_init(struct fb_info *info)
|
|||
struct cg6_par *par = (struct cg6_par *)info->par;
|
||||
struct cg6_tec __iomem *tec = par->tec;
|
||||
struct cg6_fbc __iomem *fbc = par->fbc;
|
||||
struct cg6_thc __iomem *thc = par->thc;
|
||||
u32 rev, conf, mode;
|
||||
int i;
|
||||
|
||||
/* Hide the cursor. */
|
||||
sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
|
||||
|
||||
/* Turn off stuff in the Transform Engine. */
|
||||
sbus_writel(0, &tec->tec_matrix);
|
||||
sbus_writel(0, &tec->tec_clip);
|
||||
|
|
@ -814,7 +848,7 @@ static int __devexit cg6_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id cg6_match[] = {
|
||||
static const struct of_device_id cg6_match[] = {
|
||||
{
|
||||
.name = "cgsix",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -628,27 +628,18 @@ static long cirrusfb_get_mclk(long freq, int bpp, long *div)
|
|||
static int cirrusfb_check_var(struct fb_var_screeninfo *var,
|
||||
struct fb_info *info)
|
||||
{
|
||||
int nom, den; /* translyting from pixels->bytes */
|
||||
int yres, i;
|
||||
static struct { int xres, yres; } modes[] =
|
||||
{ { 1600, 1280 },
|
||||
{ 1280, 1024 },
|
||||
{ 1024, 768 },
|
||||
{ 800, 600 },
|
||||
{ 640, 480 },
|
||||
{ -1, -1 } };
|
||||
int yres;
|
||||
/* memory size in pixels */
|
||||
unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
|
||||
|
||||
switch (var->bits_per_pixel) {
|
||||
case 1:
|
||||
nom = 4;
|
||||
den = 8;
|
||||
pixels /= 4;
|
||||
break; /* 8 pixel per byte, only 1/4th of mem usable */
|
||||
case 8:
|
||||
case 16:
|
||||
case 24:
|
||||
case 32:
|
||||
nom = var->bits_per_pixel / 8;
|
||||
den = 1;
|
||||
break; /* 1 pixel == 1 byte */
|
||||
default:
|
||||
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
|
||||
|
|
@ -658,43 +649,29 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (var->xres * nom / den * var->yres > info->screen_size) {
|
||||
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
|
||||
"resolution too high to fit into video memory!\n",
|
||||
var->xres, var->yres, var->bits_per_pixel);
|
||||
DPRINTK("EXIT - EINVAL error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (var->xres_virtual < var->xres)
|
||||
var->xres_virtual = var->xres;
|
||||
/* use highest possible virtual resolution */
|
||||
if (var->xres_virtual == -1 &&
|
||||
var->yres_virtual == -1) {
|
||||
printk(KERN_INFO
|
||||
"cirrusfb: using maximum available virtual resolution\n");
|
||||
for (i = 0; modes[i].xres != -1; i++) {
|
||||
int size = modes[i].xres * nom / den * modes[i].yres;
|
||||
if (size < info->screen_size / 2)
|
||||
break;
|
||||
}
|
||||
if (modes[i].xres == -1) {
|
||||
printk(KERN_ERR "cirrusfb: could not find a virtual "
|
||||
"resolution that fits into video memory!!\n");
|
||||
DPRINTK("EXIT - EINVAL error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
var->xres_virtual = modes[i].xres;
|
||||
var->yres_virtual = modes[i].yres;
|
||||
if (var->yres_virtual == -1) {
|
||||
var->yres_virtual = pixels / var->xres_virtual;
|
||||
|
||||
printk(KERN_INFO "cirrusfb: virtual resolution set to "
|
||||
"maximum of %dx%d\n", var->xres_virtual,
|
||||
var->yres_virtual);
|
||||
}
|
||||
|
||||
if (var->xres_virtual < var->xres)
|
||||
var->xres_virtual = var->xres;
|
||||
if (var->yres_virtual < var->yres)
|
||||
var->yres_virtual = var->yres;
|
||||
|
||||
if (var->xres_virtual * var->yres_virtual > pixels) {
|
||||
printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
|
||||
"virtual resolution too high to fit into video memory!\n",
|
||||
var->xres_virtual, var->yres_virtual,
|
||||
var->bits_per_pixel);
|
||||
DPRINTK("EXIT - EINVAL error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (var->xoffset < 0)
|
||||
var->xoffset = 0;
|
||||
if (var->yoffset < 0)
|
||||
|
|
|
|||
|
|
@ -43,22 +43,6 @@ config VGACON_SOFT_SCROLLBACK_SIZE
|
|||
buffer. Each 64KB will give you approximately 16 80x25
|
||||
screenfuls of scrollback buffer
|
||||
|
||||
config VIDEO_SELECT
|
||||
bool "Video mode selection support"
|
||||
depends on X86 && VGA_CONSOLE
|
||||
---help---
|
||||
This enables support for text mode selection on kernel startup. If
|
||||
you want to take advantage of some high-resolution text mode your
|
||||
card's BIOS offers, but the traditional Linux utilities like
|
||||
SVGATextMode don't, you can say Y here and set the mode using the
|
||||
"vga=" option from your boot loader (lilo or loadlin) or set
|
||||
"vga=ask" which brings up a video mode menu on kernel startup. (Try
|
||||
"man bootparam" or see the documentation of your boot loader about
|
||||
how to pass options to the kernel.)
|
||||
|
||||
Read the file <file:Documentation/svga.txt> for more information
|
||||
about the Video mode selection support. If unsure, say N.
|
||||
|
||||
config MDA_CONSOLE
|
||||
depends on !M68K && !PARISC && ISA
|
||||
tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
|
||||
|
|
|
|||
|
|
@ -2400,11 +2400,15 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
|
|||
|
||||
if (!fbcon_is_inactive(vc, info)) {
|
||||
if (ops->blank_state != blank) {
|
||||
int ret = 1;
|
||||
|
||||
ops->blank_state = blank;
|
||||
fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
|
||||
ops->cursor_flash = (!blank);
|
||||
|
||||
if (fb_blank(info, blank))
|
||||
if (info->fbops->fb_blank)
|
||||
ret = info->fbops->fb_blank(blank, info);
|
||||
if (ret)
|
||||
fbcon_generic_blank(vc, info, blank);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static inline int mono_col(const struct fb_info *info)
|
|||
__u32 max_len;
|
||||
max_len = max(info->var.green.length, info->var.red.length);
|
||||
max_len = max(info->var.blue.length, max_len);
|
||||
return ~(0xfff << (max_len & 0xff));
|
||||
return (~(0xfff << max_len)) & 0xff;
|
||||
}
|
||||
|
||||
static inline int attr_col_ec(int shift, struct vc_data *vc,
|
||||
|
|
|
|||
|
|
@ -979,6 +979,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
|
|||
|
||||
info->flags &= ~FBINFO_MISC_USEREVENT;
|
||||
event.info = info;
|
||||
event.data = &mode;
|
||||
fb_notifier_call_chain(evnt, &event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id ffb_match[] = {
|
||||
static const struct of_device_id ffb_match[] = {
|
||||
{
|
||||
.name = "SUNW,ffb",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ static int leo_blank(int, struct fb_info *);
|
|||
|
||||
static int leo_mmap(struct fb_info *, struct vm_area_struct *);
|
||||
static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
|
||||
static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
|
||||
|
||||
/*
|
||||
* Frame buffer operations
|
||||
|
|
@ -42,6 +43,7 @@ static struct fb_ops leo_ops = {
|
|||
.owner = THIS_MODULE,
|
||||
.fb_setcolreg = leo_setcolreg,
|
||||
.fb_blank = leo_blank,
|
||||
.fb_pan_display = leo_pan_display,
|
||||
.fb_fillrect = cfb_fillrect,
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = cfb_imageblit,
|
||||
|
|
@ -206,6 +208,60 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
|
|||
return;
|
||||
}
|
||||
|
||||
static void leo_switch_from_graph(struct fb_info *info)
|
||||
{
|
||||
struct leo_par *par = (struct leo_par *) info->par;
|
||||
struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
|
||||
struct leo_cursor __iomem *cursor = par->cursor;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&par->lock, flags);
|
||||
|
||||
par->extent = ((info->var.xres - 1) |
|
||||
((info->var.yres - 1) << 16));
|
||||
|
||||
sbus_writel(0xffffffff, &ss->wid);
|
||||
sbus_writel(0xffff, &ss->wmask);
|
||||
sbus_writel(0, &ss->vclipmin);
|
||||
sbus_writel(par->extent, &ss->vclipmax);
|
||||
sbus_writel(0, &ss->fg);
|
||||
sbus_writel(0xff000000, &ss->planemask);
|
||||
sbus_writel(0x310850, &ss->rop);
|
||||
sbus_writel(0, &ss->widclip);
|
||||
sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
|
||||
&par->lc_ss0_usr->extent);
|
||||
sbus_writel(4, &par->lc_ss0_usr->addrspace);
|
||||
sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
|
||||
sbus_writel(0, &par->lc_ss0_usr->fontt);
|
||||
do {
|
||||
val = sbus_readl(&par->lc_ss0_usr->csr);
|
||||
} while (val & 0x20000000);
|
||||
|
||||
/* setup screen buffer for cfb_* functions */
|
||||
sbus_writel(1, &ss->wid);
|
||||
sbus_writel(0x00ffffff, &ss->planemask);
|
||||
sbus_writel(0x310b90, &ss->rop);
|
||||
sbus_writel(0, &par->lc_ss0_usr->addrspace);
|
||||
|
||||
/* hide cursor */
|
||||
sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
|
||||
|
||||
spin_unlock_irqrestore(&par->lock, flags);
|
||||
}
|
||||
|
||||
static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
/* We just use this to catch switches out of
|
||||
* graphics mode.
|
||||
*/
|
||||
leo_switch_from_graph(info);
|
||||
|
||||
if (var->xoffset || var->yoffset || var->vmode)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* leo_setcolreg - Optional function. Sets a color register.
|
||||
* @regno: boolean, 0 copy local, 1 get_user() function
|
||||
|
|
@ -454,44 +510,6 @@ static void leo_init_wids(struct fb_info *info)
|
|||
leo_wid_put(info, &wl);
|
||||
}
|
||||
|
||||
static void leo_switch_from_graph(struct fb_info *info)
|
||||
{
|
||||
struct leo_par *par = (struct leo_par *) info->par;
|
||||
struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&par->lock, flags);
|
||||
|
||||
par->extent = ((info->var.xres - 1) |
|
||||
((info->var.yres - 1) << 16));
|
||||
|
||||
sbus_writel(0xffffffff, &ss->wid);
|
||||
sbus_writel(0xffff, &ss->wmask);
|
||||
sbus_writel(0, &ss->vclipmin);
|
||||
sbus_writel(par->extent, &ss->vclipmax);
|
||||
sbus_writel(0, &ss->fg);
|
||||
sbus_writel(0xff000000, &ss->planemask);
|
||||
sbus_writel(0x310850, &ss->rop);
|
||||
sbus_writel(0, &ss->widclip);
|
||||
sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
|
||||
&par->lc_ss0_usr->extent);
|
||||
sbus_writel(4, &par->lc_ss0_usr->addrspace);
|
||||
sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
|
||||
sbus_writel(0, &par->lc_ss0_usr->fontt);
|
||||
do {
|
||||
val = sbus_readl(&par->lc_ss0_usr->csr);
|
||||
} while (val & 0x20000000);
|
||||
|
||||
/* setup screen buffer for cfb_* functions */
|
||||
sbus_writel(1, &ss->wid);
|
||||
sbus_writel(0x00ffffff, &ss->planemask);
|
||||
sbus_writel(0x310b90, &ss->rop);
|
||||
sbus_writel(0, &par->lc_ss0_usr->addrspace);
|
||||
|
||||
spin_unlock_irqrestore(&par->lock, flags);
|
||||
}
|
||||
|
||||
static void leo_init_hw(struct fb_info *info)
|
||||
{
|
||||
struct leo_par *par = (struct leo_par *) info->par;
|
||||
|
|
@ -641,7 +659,7 @@ static int __devexit leo_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id leo_match[] = {
|
||||
static const struct of_device_id leo_match[] = {
|
||||
{
|
||||
.name = "SUNW,leo",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -40,29 +40,63 @@
|
|||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
#define DEBUG 1
|
||||
#ifdef DEBUG
|
||||
#define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
|
||||
#else
|
||||
#define DPRINTK(f, a...)
|
||||
#endif
|
||||
|
||||
|
||||
/* Display specific information */
|
||||
#define DPY_W 832
|
||||
#define DPY_H 622
|
||||
|
||||
static int user_wfm_size;
|
||||
|
||||
/* frame differs from image. frame includes non-visible pixels */
|
||||
struct epd_frame {
|
||||
int fw; /* frame width */
|
||||
int fh; /* frame height */
|
||||
u16 config[4];
|
||||
int wfm_size;
|
||||
};
|
||||
|
||||
static struct epd_frame epd_frame_table[] = {
|
||||
{
|
||||
.fw = 832,
|
||||
.fh = 622
|
||||
.fw = 832,
|
||||
.fh = 622,
|
||||
.config = {
|
||||
15 /* sdlew */
|
||||
| 2 << 8 /* sdosz */
|
||||
| 0 << 11 /* sdor */
|
||||
| 0 << 12 /* sdces */
|
||||
| 0 << 15, /* sdcer */
|
||||
42 /* gdspl */
|
||||
| 1 << 8 /* gdr1 */
|
||||
| 1 << 9 /* sdshr */
|
||||
| 0 << 15, /* gdspp */
|
||||
18 /* gdspw */
|
||||
| 0 << 15, /* dispc */
|
||||
599 /* vdlc */
|
||||
| 0 << 11 /* dsi */
|
||||
| 0 << 12, /* dsic */
|
||||
},
|
||||
.wfm_size = 47001,
|
||||
},
|
||||
{
|
||||
.fw = 1088,
|
||||
.fh = 791,
|
||||
.config = {
|
||||
0x0104,
|
||||
0x031f,
|
||||
0x0088,
|
||||
0x02ff,
|
||||
},
|
||||
.wfm_size = 46770,
|
||||
},
|
||||
{
|
||||
.fw = 1200,
|
||||
.fh = 842,
|
||||
.config = {
|
||||
0x0101,
|
||||
0x030e,
|
||||
0x0012,
|
||||
0x0280,
|
||||
},
|
||||
.wfm_size = 46770,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -134,9 +168,8 @@ static u16 calc_img_cksum(u16 *start, int length)
|
|||
}
|
||||
|
||||
/* here we decode the incoming waveform file and populate metromem */
|
||||
#define EXP_WFORM_SIZE 47001
|
||||
static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
||||
u8 *frame_count)
|
||||
static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
|
||||
struct metronomefb_par *par)
|
||||
{
|
||||
int tta;
|
||||
int wmta;
|
||||
|
|
@ -148,26 +181,31 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
int wfm_idx, owfm_idx;
|
||||
int mem_idx = 0;
|
||||
struct waveform_hdr *wfm_hdr;
|
||||
u8 *metromem = par->metromem_wfm;
|
||||
struct device *dev = par->info->dev;
|
||||
|
||||
if (size != EXP_WFORM_SIZE) {
|
||||
printk(KERN_ERR "Error: unexpected size %d != %d\n", size,
|
||||
EXP_WFORM_SIZE);
|
||||
if (user_wfm_size)
|
||||
epd_frame_table[par->dt].wfm_size = user_wfm_size;
|
||||
|
||||
if (size != epd_frame_table[par->dt].wfm_size) {
|
||||
dev_err(dev, "Error: unexpected size %d != %d\n", size,
|
||||
epd_frame_table[par->dt].wfm_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wfm_hdr = (struct waveform_hdr *) mem;
|
||||
|
||||
if (wfm_hdr->fvsn != 1) {
|
||||
printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn);
|
||||
dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (wfm_hdr->luts != 0) {
|
||||
printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts);
|
||||
dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts);
|
||||
return -EINVAL;
|
||||
}
|
||||
cksum = calc_cksum(32, 47, mem);
|
||||
if (cksum != wfm_hdr->wfm_cs) {
|
||||
printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum,
|
||||
dev_err(dev, "Error: bad cksum %x != %x\n", cksum,
|
||||
wfm_hdr->wfm_cs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -175,7 +213,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
wfm_hdr->trc += 1;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (*(wfm_hdr->stuff2a + i) != 0) {
|
||||
printk(KERN_ERR "Error: unexpected value in padding\n");
|
||||
dev_err(dev, "Error: unexpected value in padding\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -200,7 +238,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
return -EINVAL;
|
||||
cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem);
|
||||
if (cksum != mem[cksum_idx]) {
|
||||
printk(KERN_ERR "Error: bad temperature range table cksum"
|
||||
dev_err(dev, "Error: bad temperature range table cksum"
|
||||
" %x != %x\n", cksum, mem[cksum_idx]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -212,7 +250,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
return -EINVAL;
|
||||
cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
|
||||
if (cksum != mem[cksum_idx]) {
|
||||
printk(KERN_ERR "Error: bad mode table address cksum"
|
||||
dev_err(dev, "Error: bad mode table address cksum"
|
||||
" %x != %x\n", cksum, mem[cksum_idx]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -224,7 +262,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
return -EINVAL;
|
||||
cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem);
|
||||
if (cksum != mem[cksum_idx]) {
|
||||
printk(KERN_ERR "Error: bad temperature table address cksum"
|
||||
dev_err(dev, "Error: bad temperature table address cksum"
|
||||
" %x != %x\n", cksum, mem[cksum_idx]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -259,11 +297,11 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t,
|
|||
return -EINVAL;
|
||||
cksum = calc_cksum(owfm_idx, cksum_idx, mem);
|
||||
if (cksum != mem[cksum_idx]) {
|
||||
printk(KERN_ERR "Error: bad waveform data cksum"
|
||||
dev_err(dev, "Error: bad waveform data cksum"
|
||||
" %x != %x\n", cksum, mem[cksum_idx]);
|
||||
return -EINVAL;
|
||||
}
|
||||
*frame_count = (mem_idx/64);
|
||||
par->frame_count = (mem_idx/64);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -274,15 +312,12 @@ static int metronome_display_cmd(struct metronomefb_par *par)
|
|||
u16 cs;
|
||||
u16 opcode;
|
||||
static u8 borderval;
|
||||
u8 *ptr;
|
||||
|
||||
/* setup display command
|
||||
we can't immediately set the opcode since the controller
|
||||
will try parse the command before we've set it all up
|
||||
so we just set cs here and set the opcode at the end */
|
||||
|
||||
ptr = par->metromem;
|
||||
|
||||
if (par->metromem_cmd->opcode == 0xCC40)
|
||||
opcode = cs = 0xCC41;
|
||||
else
|
||||
|
|
@ -335,44 +370,17 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par)
|
|||
|
||||
static int __devinit metronome_config_cmd(struct metronomefb_par *par)
|
||||
{
|
||||
int i;
|
||||
u16 cs;
|
||||
|
||||
/* setup config command
|
||||
we can't immediately set the opcode since the controller
|
||||
will try parse the command before we've set it all up
|
||||
so we just set cs here and set the opcode at the end */
|
||||
|
||||
cs = 0xCC10;
|
||||
|
||||
/* set the 12 args ( 8 bytes ) for config. see spec for meanings */
|
||||
i = 0;
|
||||
par->metromem_cmd->args[i] = 15 /* sdlew */
|
||||
| 2 << 8 /* sdosz */
|
||||
| 0 << 11 /* sdor */
|
||||
| 0 << 12 /* sdces */
|
||||
| 0 << 15; /* sdcer */
|
||||
cs += par->metromem_cmd->args[i++];
|
||||
|
||||
par->metromem_cmd->args[i] = 42 /* gdspl */
|
||||
| 1 << 8 /* gdr1 */
|
||||
| 1 << 9 /* sdshr */
|
||||
| 0 << 15; /* gdspp */
|
||||
cs += par->metromem_cmd->args[i++];
|
||||
|
||||
par->metromem_cmd->args[i] = 18 /* gdspw */
|
||||
| 0 << 15; /* dispc */
|
||||
cs += par->metromem_cmd->args[i++];
|
||||
|
||||
par->metromem_cmd->args[i] = 599 /* vdlc */
|
||||
| 0 << 11 /* dsi */
|
||||
| 0 << 12; /* dsic */
|
||||
cs += par->metromem_cmd->args[i++];
|
||||
will try parse the command before we've set it all up */
|
||||
|
||||
memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config,
|
||||
sizeof(epd_frame_table[par->dt].config));
|
||||
/* the rest are 0 */
|
||||
memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2);
|
||||
memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2);
|
||||
|
||||
par->metromem_cmd->csum = cs;
|
||||
par->metromem_cmd->csum = 0xCC10;
|
||||
par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4);
|
||||
par->metromem_cmd->opcode = 0xCC10; /* config cmd */
|
||||
|
||||
return par->board->met_wait_event(par);
|
||||
|
|
@ -408,12 +416,9 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
|
|||
{
|
||||
int res;
|
||||
|
||||
par->board->init_gpio_regs(par);
|
||||
|
||||
par->board->init_lcdc_regs(par);
|
||||
|
||||
/* now that lcd is setup, setup dma descriptor */
|
||||
par->board->post_dma_setup(par);
|
||||
res = par->board->setup_io(par);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
res = metronome_powerup_cmd(par);
|
||||
if (res)
|
||||
|
|
@ -430,16 +435,16 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par)
|
|||
|
||||
static void metronomefb_dpy_update(struct metronomefb_par *par)
|
||||
{
|
||||
int fbsize;
|
||||
u16 cksum;
|
||||
unsigned char *buf = (unsigned char __force *)par->info->screen_base;
|
||||
|
||||
fbsize = par->info->fix.smem_len;
|
||||
/* copy from vm to metromem */
|
||||
memcpy(par->metromem_img, buf, DPY_W*DPY_H);
|
||||
memcpy(par->metromem_img, buf, fbsize);
|
||||
|
||||
cksum = calc_img_cksum((u16 *) par->metromem_img,
|
||||
(epd_frame_table[0].fw * DPY_H)/2);
|
||||
*((u16 *)(par->metromem_img) +
|
||||
(epd_frame_table[0].fw * DPY_H)/2) = cksum;
|
||||
cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2);
|
||||
*((u16 *)(par->metromem_img) + fbsize/2) = cksum;
|
||||
metronome_display_cmd(par);
|
||||
}
|
||||
|
||||
|
|
@ -574,8 +579,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
|
|||
unsigned char *videomemory;
|
||||
struct metronomefb_par *par;
|
||||
const struct firmware *fw_entry;
|
||||
int cmd_size, wfm_size, img_size, padding_size, totalsize;
|
||||
int i;
|
||||
int panel_type;
|
||||
int fw, fh;
|
||||
int epd_dt_index;
|
||||
|
||||
/* pick up board specific routines */
|
||||
board = dev->dev.platform_data;
|
||||
|
|
@ -586,96 +593,108 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
|
|||
if (!try_module_get(board->owner))
|
||||
return -ENODEV;
|
||||
|
||||
info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
|
||||
if (!info)
|
||||
goto err;
|
||||
|
||||
/* we have two blocks of memory.
|
||||
info->screen_base which is vm, and is the fb used by apps.
|
||||
par->metromem which is physically contiguous memory and
|
||||
contains the display controller commands, waveform,
|
||||
processed image data and padding. this is the data pulled
|
||||
by the device's LCD controller and pushed to Metronome */
|
||||
by the device's LCD controller and pushed to Metronome.
|
||||
the metromem memory is allocated by the board driver and
|
||||
is provided to us */
|
||||
|
||||
videomemorysize = (DPY_W*DPY_H);
|
||||
panel_type = board->get_panel_type();
|
||||
switch (panel_type) {
|
||||
case 6:
|
||||
epd_dt_index = 0;
|
||||
break;
|
||||
case 8:
|
||||
epd_dt_index = 1;
|
||||
break;
|
||||
case 97:
|
||||
epd_dt_index = 2;
|
||||
break;
|
||||
default:
|
||||
dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n");
|
||||
epd_dt_index = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
fw = epd_frame_table[epd_dt_index].fw;
|
||||
fh = epd_frame_table[epd_dt_index].fh;
|
||||
|
||||
/* we need to add a spare page because our csum caching scheme walks
|
||||
* to the end of the page */
|
||||
videomemorysize = PAGE_SIZE + (fw * fh);
|
||||
videomemory = vmalloc(videomemorysize);
|
||||
if (!videomemory)
|
||||
return -ENOMEM;
|
||||
goto err_fb_rel;
|
||||
|
||||
memset(videomemory, 0, videomemorysize);
|
||||
|
||||
info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev);
|
||||
if (!info)
|
||||
goto err_vfree;
|
||||
|
||||
info->screen_base = (char __force __iomem *)videomemory;
|
||||
info->fbops = &metronomefb_ops;
|
||||
|
||||
metronomefb_fix.line_length = fw;
|
||||
metronomefb_var.xres = fw;
|
||||
metronomefb_var.yres = fh;
|
||||
metronomefb_var.xres_virtual = fw;
|
||||
metronomefb_var.yres_virtual = fh;
|
||||
info->var = metronomefb_var;
|
||||
info->fix = metronomefb_fix;
|
||||
info->fix.smem_len = videomemorysize;
|
||||
par = info->par;
|
||||
par->info = info;
|
||||
par->board = board;
|
||||
par->dt = epd_dt_index;
|
||||
init_waitqueue_head(&par->waitq);
|
||||
|
||||
/* this table caches per page csum values. */
|
||||
par->csum_table = vmalloc(videomemorysize/PAGE_SIZE);
|
||||
if (!par->csum_table)
|
||||
goto err_csum_table;
|
||||
|
||||
/* the metromem buffer is divided as follows:
|
||||
command | CRC | padding
|
||||
16kb waveform data | CRC | padding
|
||||
image data | CRC
|
||||
and an extra 256 bytes for dma descriptors
|
||||
eg: IW=832 IH=622 WS=128
|
||||
*/
|
||||
|
||||
cmd_size = 1 * epd_frame_table[0].fw;
|
||||
wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1)
|
||||
/ epd_frame_table[0].fw) * epd_frame_table[0].fw;
|
||||
img_size = epd_frame_table[0].fh * epd_frame_table[0].fw;
|
||||
padding_size = 4 * epd_frame_table[0].fw;
|
||||
totalsize = cmd_size + wfm_size + img_size + padding_size;
|
||||
par->metromemsize = PAGE_ALIGN(totalsize + 256);
|
||||
DPRINTK("desired memory size = %d\n", par->metromemsize);
|
||||
dev->dev.coherent_dma_mask = 0xffffffffull;
|
||||
par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize,
|
||||
&par->metromem_dma, GFP_KERNEL);
|
||||
if (!par->metromem) {
|
||||
printk(KERN_ERR
|
||||
"metronomefb: unable to allocate dma buffer\n");
|
||||
goto err_vfree;
|
||||
|
||||
/* the physical framebuffer that we use is setup by
|
||||
* the platform device driver. It will provide us
|
||||
* with cmd, wfm and image memory in a contiguous area. */
|
||||
retval = board->setup_fb(par);
|
||||
if (retval) {
|
||||
dev_err(&dev->dev, "Failed to setup fb\n");
|
||||
goto err_csum_table;
|
||||
}
|
||||
|
||||
/* after this point we should have a framebuffer */
|
||||
if ((!par->metromem_wfm) || (!par->metromem_img) ||
|
||||
(!par->metromem_dma)) {
|
||||
dev_err(&dev->dev, "fb access failure\n");
|
||||
retval = -EINVAL;
|
||||
goto err_csum_table;
|
||||
}
|
||||
|
||||
info->fix.smem_start = par->metromem_dma;
|
||||
par->metromem_cmd = (struct metromem_cmd *) par->metromem;
|
||||
par->metromem_wfm = par->metromem + cmd_size;
|
||||
par->metromem_img = par->metromem + cmd_size + wfm_size;
|
||||
par->metromem_img_csum = (u16 *) (par->metromem_img +
|
||||
(epd_frame_table[0].fw * DPY_H));
|
||||
DPRINTK("img offset=0x%x\n", cmd_size + wfm_size);
|
||||
par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size
|
||||
+ wfm_size + img_size + padding_size);
|
||||
par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size
|
||||
+ img_size + padding_size;
|
||||
|
||||
/* load the waveform in. assume mode 3, temp 31 for now
|
||||
a) request the waveform file from userspace
|
||||
b) process waveform and decode into metromem */
|
||||
retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "metronomefb: couldn't get waveform\n");
|
||||
goto err_dma_free;
|
||||
dev_err(&dev->dev, "Failed to get waveform\n");
|
||||
goto err_csum_table;
|
||||
}
|
||||
|
||||
retval = load_waveform((u8 *) fw_entry->data, fw_entry->size,
|
||||
par->metromem_wfm, 3, 31, &par->frame_count);
|
||||
retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31,
|
||||
par);
|
||||
release_firmware(fw_entry);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "metronomefb: couldn't process waveform\n");
|
||||
goto err_dma_free;
|
||||
dev_err(&dev->dev, "Failed processing waveform\n");
|
||||
goto err_csum_table;
|
||||
}
|
||||
|
||||
if (board->setup_irq(info))
|
||||
goto err_dma_free;
|
||||
goto err_csum_table;
|
||||
|
||||
retval = metronome_init_regs(par);
|
||||
if (retval < 0)
|
||||
|
|
@ -688,8 +707,8 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
|
|||
|
||||
retval = fb_alloc_cmap(&info->cmap, 8, 0);
|
||||
if (retval < 0) {
|
||||
printk(KERN_ERR "Failed to allocate colormap\n");
|
||||
goto err_fb_rel;
|
||||
dev_err(&dev->dev, "Failed to allocate colormap\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
/* set cmap */
|
||||
|
|
@ -704,7 +723,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
|
|||
|
||||
platform_set_drvdata(dev, info);
|
||||
|
||||
printk(KERN_INFO
|
||||
dev_dbg(&dev->dev,
|
||||
"fb%d: Metronome frame buffer device, using %dK of video"
|
||||
" memory\n", info->node, videomemorysize >> 10);
|
||||
|
||||
|
|
@ -712,17 +731,15 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
|
|||
|
||||
err_cmap:
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
err_fb_rel:
|
||||
framebuffer_release(info);
|
||||
err_free_irq:
|
||||
board->free_irq(info);
|
||||
err_dma_free:
|
||||
dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem,
|
||||
par->metromem_dma);
|
||||
board->cleanup(par);
|
||||
err_csum_table:
|
||||
vfree(par->csum_table);
|
||||
err_vfree:
|
||||
vfree(videomemory);
|
||||
err_fb_rel:
|
||||
framebuffer_release(info);
|
||||
err:
|
||||
module_put(board->owner);
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -733,15 +750,15 @@ static int __devexit metronomefb_remove(struct platform_device *dev)
|
|||
|
||||
if (info) {
|
||||
struct metronomefb_par *par = info->par;
|
||||
fb_deferred_io_cleanup(info);
|
||||
dma_free_writecombine(&dev->dev, par->metromemsize,
|
||||
par->metromem, par->metromem_dma);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
vfree(par->csum_table);
|
||||
|
||||
unregister_framebuffer(info);
|
||||
fb_deferred_io_cleanup(info);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
par->board->cleanup(par);
|
||||
vfree(par->csum_table);
|
||||
vfree((void __force *)info->screen_base);
|
||||
par->board->free_irq(info);
|
||||
module_put(par->board->owner);
|
||||
dev_dbg(&dev->dev, "calling release\n");
|
||||
framebuffer_release(info);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -766,6 +783,9 @@ static void __exit metronomefb_exit(void)
|
|||
platform_driver_unregister(&metronomefb_driver);
|
||||
}
|
||||
|
||||
module_param(user_wfm_size, uint, 0);
|
||||
MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size");
|
||||
|
||||
module_init(metronomefb_init);
|
||||
module_exit(metronomefb_exit);
|
||||
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id p9100_match[] = {
|
||||
static const struct of_device_id p9100_match[] = {
|
||||
{
|
||||
.name = "p9100",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id tcx_match[] = {
|
||||
static const struct of_device_id tcx_match[] = {
|
||||
{
|
||||
.name = "SUNW,tcx",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@ static inline int mtrr_del(int reg, unsigned long base,
|
|||
#define VOODOO5_MAX_PIXCLOCK 350000
|
||||
|
||||
static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
|
||||
.id = "3Dfx",
|
||||
.type = FB_TYPE_PACKED_PIXELS,
|
||||
.visual = FB_VISUAL_PSEUDOCOLOR,
|
||||
.ypanstep = 1,
|
||||
|
|
@ -426,7 +425,7 @@ static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
|
|||
if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
|
||||
/* Banshee/Voodoo3 */
|
||||
chip_size = 2;
|
||||
if (has_sgram && (draminit0 & DRAMINIT0_SGRAM_TYPE))
|
||||
if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE))
|
||||
chip_size = 1;
|
||||
} else {
|
||||
/* Voodoo4/5 */
|
||||
|
|
@ -1200,15 +1199,15 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
|
|||
/* Configure the default fb_fix_screeninfo first */
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_3DFX_BANSHEE:
|
||||
strcat(tdfx_fix.id, " Banshee");
|
||||
strcpy(tdfx_fix.id, "3Dfx Banshee");
|
||||
default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
|
||||
break;
|
||||
case PCI_DEVICE_ID_3DFX_VOODOO3:
|
||||
strcat(tdfx_fix.id, " Voodoo3");
|
||||
strcpy(tdfx_fix.id, "3Dfx Voodoo3");
|
||||
default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
|
||||
break;
|
||||
case PCI_DEVICE_ID_3DFX_VOODOO5:
|
||||
strcat(tdfx_fix.id, " Voodoo5");
|
||||
strcpy(tdfx_fix.id, "3Dfx Voodoo5");
|
||||
default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -680,11 +680,11 @@ static struct xenbus_driver xenfb = {
|
|||
|
||||
static int __init xenfb_init(void)
|
||||
{
|
||||
if (!is_running_on_xen())
|
||||
if (!xen_domain())
|
||||
return -ENODEV;
|
||||
|
||||
/* Nothing to do if running in dom0. */
|
||||
if (is_initial_xendomain())
|
||||
if (xen_initial_domain())
|
||||
return -ENODEV;
|
||||
|
||||
return xenbus_register_frontend(&xenfb);
|
||||
|
|
|
|||
Loading…
Reference in a new issue