aboutsummaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig23
-rw-r--r--drivers/video/amifb.c49
-rw-r--r--drivers/video/arcfb.c8
-rw-r--r--drivers/video/aty/atyfb_base.c4
-rw-r--r--drivers/video/aty/mach64_accel.c9
-rw-r--r--drivers/video/aty/radeon_base.c4
-rw-r--r--drivers/video/aty/radeon_pm.c2
-rw-r--r--drivers/video/au1100fb.c6
-rw-r--r--drivers/video/backlight/88pm860x_bl.c2
-rw-r--r--drivers/video/backlight/Kconfig116
-rw-r--r--drivers/video/backlight/Makefile4
-rw-r--r--drivers/video/backlight/adp8860_bl.c836
-rw-r--r--drivers/video/backlight/adx_bl.c4
-rw-r--r--drivers/video/backlight/ep93xx_bl.c160
-rw-r--r--drivers/video/backlight/l4f00242t03.c11
-rw-r--r--drivers/video/backlight/max8925_bl.c1
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c47
-rw-r--r--drivers/video/backlight/pcf50633-backlight.c190
-rw-r--r--drivers/video/backlight/s6e63m0.c920
-rw-r--r--drivers/video/backlight/s6e63m0_gamma.h266
-rw-r--r--drivers/video/backlight/tosa_bl.c2
-rw-r--r--drivers/video/bf54x-lq043fb.c7
-rw-r--r--drivers/video/bfin-lq035q1-fb.c252
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c22
-rw-r--r--drivers/video/bw2.c9
-rw-r--r--drivers/video/cg14.c9
-rw-r--r--drivers/video/cg3.c9
-rw-r--r--drivers/video/cg6.c9
-rw-r--r--drivers/video/cirrusfb.c1
-rw-r--r--drivers/video/cobalt_lcdfb.c2
-rw-r--r--drivers/video/cyber2000fb.c3
-rw-r--r--drivers/video/da8xx-fb.c301
-rw-r--r--drivers/video/efifb.c11
-rw-r--r--drivers/video/fb_defio.c14
-rw-r--r--drivers/video/fbmem.c77
-rw-r--r--drivers/video/fbsysfs.c1
-rw-r--r--drivers/video/ffb.c9
-rw-r--r--drivers/video/fm2fb.c1
-rw-r--r--drivers/video/fsl-diu-fb.c10
-rw-r--r--drivers/video/gbefb.c16
-rw-r--r--drivers/video/geode/gxfb_core.c20
-rw-r--r--drivers/video/geode/lxfb_core.c18
-rw-r--r--drivers/video/hgafb.c10
-rw-r--r--drivers/video/hitfb.c8
-rw-r--r--drivers/video/imxfb.c72
-rw-r--r--drivers/video/intelfb/intelfb.h4
-rw-r--r--drivers/video/leo.c9
-rw-r--r--drivers/video/mb862xx/mb862xxfb.c10
-rw-r--r--drivers/video/mx3fb.c3
-rw-r--r--drivers/video/nuc900fb.c4
-rw-r--r--drivers/video/offb.c28
-rw-r--r--drivers/video/omap/lcdc.c14
-rw-r--r--drivers/video/omap/rfbi.c5
-rw-r--r--drivers/video/omap2/displays/Kconfig9
-rw-r--r--drivers/video/omap2/displays/Makefile1
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c821
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c78
-rw-r--r--drivers/video/omap2/displays/panel-taal.c143
-rw-r--r--drivers/video/omap2/dss/Kconfig6
-rw-r--r--drivers/video/omap2/dss/Makefile3
-rw-r--r--drivers/video/omap2/dss/core.c85
-rw-r--r--drivers/video/omap2/dss/display.c9
-rw-r--r--drivers/video/omap2/dss/dss.c24
-rw-r--r--drivers/video/omap2/dss/dss.h50
-rw-r--r--drivers/video/omap2/dss/manager.c21
-rw-r--r--drivers/video/omap2/dss/sdi.c26
-rw-r--r--drivers/video/omap2/dss/venc.c15
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c5
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c25
-rw-r--r--drivers/video/omap2/vram.c33
-rw-r--r--drivers/video/p9100.c9
-rw-r--r--drivers/video/platinumfb.c9
-rw-r--r--drivers/video/pmag-ba-fb.c6
-rw-r--r--drivers/video/pmagb-b-fb.c12
-rw-r--r--drivers/video/s3c2410fb.c10
-rw-r--r--drivers/video/s3fb.c101
-rw-r--r--drivers/video/sgivwfb.c10
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c6
-rw-r--r--drivers/video/sis/sis_main.c2
-rw-r--r--drivers/video/sunxvr1000.c9
-rw-r--r--drivers/video/tcx.c9
-rw-r--r--drivers/video/vesafb.c11
-rw-r--r--drivers/video/vfb.c4
-rw-r--r--drivers/video/vga16fb.c36
-rw-r--r--drivers/video/via/Makefile4
-rw-r--r--drivers/video/via/accel.c137
-rw-r--r--drivers/video/via/accel.h40
-rw-r--r--drivers/video/via/chip.h8
-rw-r--r--drivers/video/via/dvi.c37
-rw-r--r--drivers/video/via/global.h1
-rw-r--r--drivers/video/via/hw.c307
-rw-r--r--drivers/video/via/hw.h20
-rw-r--r--drivers/video/via/ioctl.h2
-rw-r--r--drivers/video/via/lcd.c31
-rw-r--r--drivers/video/via/lcd.h2
-rw-r--r--drivers/video/via/share.h20
-rw-r--r--drivers/video/via/via-core.c668
-rw-r--r--drivers/video/via/via-gpio.c285
-rw-r--r--drivers/video/via/via_i2c.c232
-rw-r--r--drivers/video/via/via_modesetting.c126
-rw-r--r--drivers/video/via/via_modesetting.h (renamed from drivers/video/via/via_i2c.h)42
-rw-r--r--drivers/video/via/via_utility.c1
-rw-r--r--drivers/video/via/viafbdev.c192
-rw-r--r--drivers/video/via/viafbdev.h14
-rw-r--r--drivers/video/via/viamode.c15
-rw-r--r--drivers/video/via/vt1636.c34
-rw-r--r--drivers/video/via/vt1636.h2
-rw-r--r--drivers/video/w100fb.c10
-rw-r--r--drivers/video/xilinxfb.c23
109 files changed, 6277 insertions, 1196 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6e16244f3ed..3d94a147172 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -8,6 +8,9 @@ menu "Graphics support"
config HAVE_FB_ATMEL
bool
+config HAVE_FB_IMX
+ bool
+
source "drivers/char/agp/Kconfig"
source "drivers/gpu/vga/Kconfig"
@@ -400,9 +403,6 @@ config FB_SA1100
If you plan to use the LCD display with your SA-1100 system, say
Y here.
-config HAVE_FB_IMX
- bool
-
config FB_IMX
tristate "Motorola i.MX LCD support"
depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2)
@@ -1511,6 +1511,7 @@ config FB_VIA
select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT
select I2C
+ select GPIOLIB
help
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@@ -1520,6 +1521,21 @@ config FB_VIA
To compile this driver as a module, choose M here: the
module will be called viafb.
+
+if FB_VIA
+
+config FB_VIA_DIRECT_PROCFS
+ bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)"
+ depends on FB_VIA
+ default n
+ help
+ Allow direct hardware access to some output registers via procfs.
+ This is dangerous but may provide the only chance to get the
+ correct output device configuration.
+ Its use is strongly discouraged.
+
+endif
+
config FB_NEOMAGIC
tristate "NeoMagic display support"
depends on FB && PCI
@@ -2186,7 +2202,6 @@ config FB_MSM
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- default y
config FB_MX3
tristate "MX3 Framebuffer support"
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index dca48df9844..e5d6b56d444 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -50,8 +50,9 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
-
+#include <linux/platform_device.h>
#include <linux/uaccess.h>
+
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
@@ -1135,7 +1136,7 @@ static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg
* Interface to the low level console driver
*/
-static void amifb_deinit(void);
+static void amifb_deinit(struct platform_device *pdev);
/*
* Internal routines
@@ -2246,7 +2247,7 @@ static inline void chipfree(void)
* Initialisation
*/
-static int __init amifb_init(void)
+static int __init amifb_probe(struct platform_device *pdev)
{
int tag, i, err = 0;
u_long chipptr;
@@ -2261,16 +2262,6 @@ static int __init amifb_init(void)
}
amifb_setup(option);
#endif
- if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
- return -ENODEV;
-
- /*
- * We request all registers starting from bplpt[0]
- */
- if (!request_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120,
- "amifb [Denise/Lisa]"))
- return -EBUSY;
-
custom.dmacon = DMAF_ALL | DMAF_MASTER;
switch (amiga_chipset) {
@@ -2377,6 +2368,7 @@ default_chipset:
fb_info.fbops = &amifb_ops;
fb_info.par = &currentpar;
fb_info.flags = FBINFO_DEFAULT;
+ fb_info.device = &pdev->dev;
if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
@@ -2451,18 +2443,18 @@ default_chipset:
return 0;
amifb_error:
- amifb_deinit();
+ amifb_deinit(pdev);
return err;
}
-static void amifb_deinit(void)
+static void amifb_deinit(struct platform_device *pdev)
{
if (fb_info.cmap.len)
fb_dealloc_cmap(&fb_info.cmap);
+ fb_dealloc_cmap(&fb_info.cmap);
chipfree();
if (videomemory)
iounmap((void*)videomemory);
- release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
custom.dmacon = DMAF_ALL | DMAF_MASTER;
}
@@ -3794,14 +3786,35 @@ static void ami_rebuild_copper(void)
}
}
-static void __exit amifb_exit(void)
+static int __exit amifb_remove(struct platform_device *pdev)
{
unregister_framebuffer(&fb_info);
- amifb_deinit();
+ amifb_deinit(pdev);
amifb_video_off();
+ return 0;
+}
+
+static struct platform_driver amifb_driver = {
+ .remove = __exit_p(amifb_remove),
+ .driver = {
+ .name = "amiga-video",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init amifb_init(void)
+{
+ return platform_driver_probe(&amifb_driver, amifb_probe);
}
module_init(amifb_init);
+
+static void __exit amifb_exit(void)
+{
+ platform_driver_unregister(&amifb_driver);
+}
+
module_exit(amifb_exit);
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:amiga-video");
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 8d406fb689c..f3d7440f007 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -80,7 +80,7 @@ struct arcfb_par {
spinlock_t lock;
};
-static struct fb_fix_screeninfo arcfb_fix __initdata = {
+static struct fb_fix_screeninfo arcfb_fix __devinitdata = {
.id = "arcfb",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_MONO01,
@@ -90,7 +90,7 @@ static struct fb_fix_screeninfo arcfb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static struct fb_var_screeninfo arcfb_var __initdata = {
+static struct fb_var_screeninfo arcfb_var __devinitdata = {
.xres = 128,
.yres = 64,
.xres_virtual = 128,
@@ -588,7 +588,7 @@ err:
return retval;
}
-static int arcfb_remove(struct platform_device *dev)
+static int __devexit arcfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
@@ -602,7 +602,7 @@ static int arcfb_remove(struct platform_device *dev)
static struct platform_driver arcfb_driver = {
.probe = arcfb_probe,
- .remove = arcfb_remove,
+ .remove = __devexit_p(arcfb_remove),
.driver = {
.name = "arcfb",
},
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 29d72851f85..f8d69ad3683 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -1820,10 +1820,6 @@ struct atyclk {
#define ATYIO_FEATW 0x41545903 /* ATY\03 */
#endif
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index 51fcc0a2c94..e45833ce975 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -242,7 +242,7 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0;
+ u32 color, dx = rect->dx, width = rect->width, rotation = 0;
if (par->asleep)
return;
@@ -253,8 +253,11 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
return;
}
- color |= (rect->color << 8);
- color |= (rect->color << 16);
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR)
+ color = ((u32 *)(info->pseudo_palette))[rect->color];
+ else
+ color = rect->color;
if (info->var.bits_per_pixel == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 6c37e8ee5ef..3c1e13ed1cb 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -2099,7 +2099,7 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u
}
-static ssize_t radeon_show_edid1(struct kobject *kobj,
+static ssize_t radeon_show_edid1(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
@@ -2112,7 +2112,7 @@ static ssize_t radeon_show_edid1(struct kobject *kobj,
}
-static ssize_t radeon_show_edid2(struct kobject *kobj,
+static ssize_t radeon_show_edid2(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 515cf1978d1..c4e17642d9c 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -2872,7 +2872,7 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlis
}
#if 0
- /* Power down TV DAC, taht saves a significant amount of power,
+ /* Power down TV DAC, that saves a significant amount of power,
* we'll have something better once we actually have some TVOut
* support
*/
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 40f61320ce1..34b2fc472fe 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -95,7 +95,7 @@ struct fb_bitfield rgb_bitfields[][4] =
{ { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } },
};
-static struct fb_fix_screeninfo au1100fb_fix __initdata = {
+static struct fb_fix_screeninfo au1100fb_fix __devinitdata = {
.id = "AU1100 FB",
.xpanstep = 1,
.ypanstep = 1,
@@ -103,7 +103,7 @@ static struct fb_fix_screeninfo au1100fb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
-static struct fb_var_screeninfo au1100fb_var __initdata = {
+static struct fb_var_screeninfo au1100fb_var __devinitdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
@@ -458,7 +458,7 @@ static struct fb_ops au1100fb_ops =
/* AU1100 LCD controller device driver */
-static int __init au1100fb_drv_probe(struct platform_device *dev)
+static int __devinit au1100fb_drv_probe(struct platform_device *dev)
{
struct au1100fb_device *fbdev = NULL;
struct resource *regs_res;
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index 68d2518fada..38ffc3fbcbe 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -222,6 +222,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
data->port = __check_device(pdata, name);
if (data->port < 0) {
dev_err(&pdev->dev, "wrong platform data is assigned");
+ kfree(data);
return -EINVAL;
}
@@ -266,6 +267,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
backlight_update_status(bl);
return 0;
out:
+ backlight_device_unregister(bl);
kfree(data);
return ret;
}
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index c025c84601b..e54a337227e 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,12 +8,13 @@ menuconfig BACKLIGHT_LCD_SUPPORT
Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs.
+if BACKLIGHT_LCD_SUPPORT
+
#
# LCD
#
config LCD_CLASS_DEVICE
tristate "Lowlevel LCD controls"
- depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of LCD.
@@ -24,31 +25,32 @@ 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.
+if LCD_CLASS_DEVICE
+
config LCD_CORGI
tristate "LCD Panel support for SHARP corgi/spitz model"
- depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL
+ depends on 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_L4F00242T03
tristate "Epson L4F00242T03 LCD"
- depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+ depends on SPI_MASTER && GENERIC_GPIO
help
SPI driver for Epson L4F00242T03. This provides basic support
for init and powering the LCD up/down through a sysfs interface.
config LCD_LMS283GF05
tristate "Samsung LMS283GF05 LCD"
- depends on LCD_CLASS_DEVICE && SPI_MASTER && GENERIC_GPIO
+ depends on SPI_MASTER && GENERIC_GPIO
help
SPI driver for Samsung LMS283GF05. This provides basic support
for powering the LCD up/down through a sysfs interface.
config LCD_LTV350QV
tristate "Samsung LTV350QV LCD Panel"
- depends on LCD_CLASS_DEVICE && SPI_MASTER
- default n
+ depends on SPI_MASTER
help
If you have a Samsung LTV350QV LCD panel, say y to include a
power control driver for it. The panel starts up in power
@@ -59,60 +61,61 @@ config LCD_LTV350QV
config LCD_ILI9320
tristate
- depends on LCD_CLASS_DEVICE && BACKLIGHT_LCD_SUPPORT
- default n
help
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 and TDO35S LCD Panels support"
- depends on LCD_CLASS_DEVICE && SPI_MASTER
- default n
+ depends on SPI_MASTER
help
If you have a Toppoly TDO24M/TDO35S 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
+ depends on SPI_MASTER
select LCD_ILI9320
- default n
help
If you have a VGG2432A4 panel based on the ILI9320 controller chip
then say y to include a power driver for it.
config LCD_PLATFORM
tristate "Platform LCD controls"
- depends on LCD_CLASS_DEVICE
help
This driver provides a platform-device registered LCD power
control interface.
config LCD_TOSA
tristate "Sharp SL-6000 LCD Driver"
- depends on LCD_CLASS_DEVICE && SPI
- depends on MACH_TOSA
- default n
+ depends on SPI && MACH_TOSA
help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its LCD.
config LCD_HP700
tristate "HP Jornada 700 series LCD Driver"
- depends on LCD_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT
default y
help
If you have an HP Jornada 700 series handheld (710/720/728)
say Y to enable LCD control driver.
+config LCD_S6E63M0
+ tristate "S6E63M0 AMOLED LCD Driver"
+ depends on SPI && BACKLIGHT_CLASS_DEVICE
+ default n
+ help
+ If you have an S6E63M0 LCD Panel, say Y to enable its
+ LCD control driver.
+
+endif # LCD_CLASS_DEVICE
+
#
# Backlight
#
config BACKLIGHT_CLASS_DEVICE
tristate "Lowlevel Backlight controls"
- depends on BACKLIGHT_LCD_SUPPORT
default m
help
This framework adds support for low-level control of the LCD
@@ -121,9 +124,11 @@ config BACKLIGHT_CLASS_DEVICE
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
+if BACKLIGHT_CLASS_DEVICE
+
config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control"
- depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL
+ depends on FB_ATMEL
default y if MACH_SAM9261EK || MACH_SAM9G10EK || MACH_SAM9263EK
help
This provides a backlight control internal to the Atmel LCDC
@@ -136,8 +141,7 @@ config BACKLIGHT_ATMEL_LCDC
config BACKLIGHT_ATMEL_PWM
tristate "Atmel PWM backlight control"
- depends on BACKLIGHT_CLASS_DEVICE && ATMEL_PWM
- default n
+ depends on ATMEL_PWM
help
Say Y here if you want to use the PWM peripheral in Atmel AT91 and
AVR32 devices. This driver will need additional platform data to know
@@ -146,9 +150,18 @@ config BACKLIGHT_ATMEL_PWM
To compile this driver as a module, choose M here: the module will be
called atmel-pwm-bl.
+config BACKLIGHT_EP93XX
+ tristate "Cirrus EP93xx Backlight Driver"
+ depends on FB_EP93XX
+ help
+ If you have a LCD backlight connected to the BRIGHT output of
+ the EP93xx, say Y here to enable this driver.
+
+ To compile this driver as a module, choose M here: the module will
+ be called ep93xx_bl.
+
config BACKLIGHT_GENERIC
tristate "Generic (aka Sharp Corgi) Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE
default y
help
Say y to enable the generic platform backlight driver previously
@@ -157,7 +170,7 @@ config BACKLIGHT_GENERIC
config BACKLIGHT_LOCOMO
tristate "Sharp LOCOMO LCD/Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
+ depends on SHARP_LOCOMO
default y
help
If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
@@ -165,7 +178,7 @@ config BACKLIGHT_LOCOMO
config BACKLIGHT_OMAP1
tristate "OMAP1 PWL-based LCD Backlight"
- depends on BACKLIGHT_CLASS_DEVICE && ARCH_OMAP1
+ depends on ARCH_OMAP1
default y
help
This driver controls the LCD backlight level and power for
@@ -174,7 +187,7 @@ config BACKLIGHT_OMAP1
config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && SH_HP6XX
+ depends on SH_HP6XX
default y
help
If you have a HP Jornada 680, say y to enable the
@@ -182,7 +195,6 @@ config BACKLIGHT_HP680
config BACKLIGHT_HP700
tristate "HP Jornada 700 series Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE
depends on SA1100_JORNADA720_SSP && !PREEMPT
default y
help
@@ -191,76 +203,70 @@ config BACKLIGHT_HP700
config BACKLIGHT_PROGEAR
tristate "Frontpath ProGear Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && PCI && X86
- default n
+ depends on PCI && X86
help
If you have a Frontpath ProGear say Y to enable the
backlight driver.
config BACKLIGHT_CARILLO_RANCH
tristate "Intel Carillo Ranch Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
- default n
+ depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
help
If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
backlight driver.
config BACKLIGHT_PWM
tristate "Generic PWM based Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && HAVE_PWM
+ depends on HAVE_PWM
help
If you have a LCD backlight adjustable by PWM, say Y to enable
this driver.
config BACKLIGHT_DA903X
tristate "Backlight Driver for DA9030/DA9034 using WLED"
- depends on BACKLIGHT_CLASS_DEVICE && PMIC_DA903X
+ depends on PMIC_DA903X
help
If you have a LCD backlight connected to the WLED output of DA9030
or DA9034 WLED output, say Y here to enable this driver.
config BACKLIGHT_MAX8925
tristate "Backlight driver for MAX8925"
- depends on BACKLIGHT_CLASS_DEVICE && MFD_MAX8925
+ depends on MFD_MAX8925
help
If you have a LCD backlight connected to the WLED output of MAX8925
WLED output, say Y here to enable this driver.
config BACKLIGHT_MBP_NVIDIA
tristate "MacBook Pro Nvidia Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && X86
- default n
+ depends on X86
help
If you have an Apple Macbook Pro with Nvidia graphics hardware say Y
to enable a driver for its backlight
config BACKLIGHT_TOSA
tristate "Sharp SL-6000 Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && I2C
- depends on MACH_TOSA && LCD_TOSA
- default n
+ depends on I2C && MACH_TOSA && LCD_TOSA
help
If you have an Sharp SL-6000 Zaurus say Y to enable a driver
for its backlight
config BACKLIGHT_SAHARA
tristate "Tabletkiosk Sahara Touch-iT Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && X86
- default n
+ depends on X86
help
If you have a Tabletkiosk Sahara Touch-iT, say y to enable the
backlight driver.
config BACKLIGHT_WM831X
tristate "WM831x PMIC Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && MFD_WM831X
+ depends on MFD_WM831X
help
If you have a backlight driven by the ISINK and DCDC of a
WM831x PMIC say y to enable the backlight driver for it.
config BACKLIGHT_ADX
tristate "Avionic Design Xanthos Backlight Driver"
- depends on BACKLIGHT_CLASS_DEVICE && ARCH_PXA_ADX
+ depends on ARCH_PXA_ADX
default y
help
Say Y to enable the backlight driver on Avionic Design Xanthos-based
@@ -268,7 +274,7 @@ config BACKLIGHT_ADX
config BACKLIGHT_ADP5520
tristate "Backlight Driver for ADP5520/ADP5501 using WLED"
- depends on BACKLIGHT_CLASS_DEVICE && PMIC_ADP5520
+ depends on PMIC_ADP5520
help
If you have a LCD backlight connected to the BST/BL_SNK output of
ADP5520 or ADP5501, say Y here to enable this driver.
@@ -276,9 +282,31 @@ config BACKLIGHT_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520_bl.
+config BACKLIGHT_ADP8860
+ tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED"
+ depends on BACKLIGHT_CLASS_DEVICE && I2C
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ If you have a LCD backlight connected to the ADP8860, ADP8861 or
+ ADP8863 say Y here to enable this driver.
+
+ To compile this driver as a module, choose M here: the module will
+ be called adp8860_bl.
+
config BACKLIGHT_88PM860X
tristate "Backlight Driver for 88PM8606 using WLED"
- depends on BACKLIGHT_CLASS_DEVICE && MFD_88PM860X
+ depends on MFD_88PM860X
help
Say Y to enable the backlight driver for Marvell 88PM8606.
+config BACKLIGHT_PCF50633
+ tristate "Backlight driver for NXP PCF50633 MFD"
+ depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633
+ help
+ If you have a backlight driven by a NXP PCF50633 MFD, say Y here to
+ enable its driver.
+
+endif # BACKLIGHT_CLASS_DEVICE
+
+endif # BACKLIGHT_LCD_SUPPORT
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 09d1f14d625..44c0f81ad85 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -11,9 +11,11 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o
obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o
obj-$(CONFIG_LCD_TDO24M) += tdo24m.o
obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o
+obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o
+obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o
obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
@@ -30,5 +32,7 @@ obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
obj-$(CONFIG_BACKLIGHT_ADX) += adx_bl.o
obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o
obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
+obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
new file mode 100644
index 00000000000..3ec24609151
--- /dev/null
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -0,0 +1,836 @@
+/*
+ * Backlight driver for Analog Devices ADP8860 Backlight Devices
+ *
+ * Copyright 2009-2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <linux/i2c/adp8860.h>
+#define ADP8860_EXT_FEATURES
+#define ADP8860_USE_LEDS
+
+#define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */
+#define ADP8860_MDCR 0x01 /* Device mode and status */
+#define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */
+#define ADP8860_INTR_EN 0x03 /* Interrupts enable */
+#define ADP8860_CFGR 0x04 /* Configuration register */
+#define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */
+#define ADP8860_BLOFF 0x06 /* Backlight off timeout */
+#define ADP8860_BLDIM 0x07 /* Backlight dim timeout */
+#define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */
+#define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */
+#define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */
+#define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */
+#define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */
+#define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */
+#define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */
+#define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */
+#define ADP8860_ISCC 0x10 /* Independent sink current control register */
+#define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */
+#define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */
+#define ADP8860_ISCF 0x13 /* Independent sink current fade register */
+#define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */
+#define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */
+#define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */
+#define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */
+#define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */
+#define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */
+#define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */
+#define ADP8860_CCFG 0x1B /* Comparator configuration */
+#define ADP8860_CCFG2 0x1C /* Second comparator configuration */
+#define ADP8860_L2_TRP 0x1D /* L2 comparator reference */
+#define ADP8860_L2_HYS 0x1E /* L2 hysteresis */
+#define ADP8860_L3_TRP 0x1F /* L3 comparator reference */
+#define ADP8860_L3_HYS 0x20 /* L3 hysteresis */
+#define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */
+#define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */
+#define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */
+#define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */
+
+#define ADP8860_MANUFID 0x0 /* Analog Devices ADP8860 Manufacturer ID */
+#define ADP8861_MANUFID 0x4 /* Analog Devices ADP8861 Manufacturer ID */
+#define ADP8863_MANUFID 0x2 /* Analog Devices ADP8863 Manufacturer ID */
+
+#define ADP8860_DEVID(x) ((x) & 0xF)
+#define ADP8860_MANID(x) ((x) >> 4)
+
+/* MDCR Device mode and status */
+#define INT_CFG (1 << 6)
+#define NSTBY (1 << 5)
+#define DIM_EN (1 << 4)
+#define GDWN_DIS (1 << 3)
+#define SIS_EN (1 << 2)
+#define CMP_AUTOEN (1 << 1)
+#define BLEN (1 << 0)
+
+/* ADP8860_CCFG Main ALS comparator level enable */
+#define L3_EN (1 << 1)
+#define L2_EN (1 << 0)
+
+#define CFGR_BLV_SHIFT 3
+#define CFGR_BLV_MASK 0x3
+#define ADP8860_FLAG_LED_MASK 0xFF
+
+#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4))
+#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
+#define ALS_CCFG_VAL(filt) ((0x7 & filt) << 5)
+
+enum {
+ adp8860,
+ adp8861,
+ adp8863
+};
+
+struct adp8860_led {
+ struct led_classdev cdev;
+ struct work_struct work;
+ struct i2c_client *client;
+ enum led_brightness new_brightness;
+ int id;
+ int flags;
+};
+
+struct adp8860_bl {
+ struct i2c_client *client;
+ struct backlight_device *bl;
+ struct adp8860_led *led;
+ struct adp8860_backlight_platform_data *pdata;
+ struct mutex lock;
+ unsigned long cached_daylight_max;
+ int id;
+ int revid;
+ int current_brightness;
+ unsigned en_ambl_sens:1;
+ unsigned gdwn_dis:1;
+};
+
+static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(client, reg);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
+ return ret;
+ }
+
+ *val = (uint8_t)ret;
+ return 0;
+}
+
+static int adp8860_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+ struct adp8860_bl *data = i2c_get_clientdata(client);
+ uint8_t reg_val;
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = adp8860_read(client, reg, &reg_val);
+
+ if (!ret && ((reg_val & bit_mask) == 0)) {
+ reg_val |= bit_mask;
+ ret = adp8860_write(client, reg, reg_val);
+ }
+
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
+{
+ struct adp8860_bl *data = i2c_get_clientdata(client);
+ uint8_t reg_val;
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = adp8860_read(client, reg, &reg_val);
+
+ if (!ret && (reg_val & bit_mask)) {
+ reg_val &= ~bit_mask;
+ ret = adp8860_write(client, reg, reg_val);
+ }
+
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+/*
+ * Independent sink / LED
+ */
+#if defined(ADP8860_USE_LEDS)
+static void adp8860_led_work(struct work_struct *work)
+{
+ struct adp8860_led *led = container_of(work, struct adp8860_led, work);
+ adp8860_write(led->client, ADP8860_ISC1 - led->id + 1,
+ led->new_brightness >> 1);
+}
+
+static void adp8860_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct adp8860_led *led;
+
+ led = container_of(led_cdev, struct adp8860_led, cdev);
+ led->new_brightness = value;
+ schedule_work(&led->work);
+}
+
+static int adp8860_led_setup(struct adp8860_led *led)
+{
+ struct i2c_client *client = led->client;
+ int ret = 0;
+
+ ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0);
+ ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1));
+
+ if (led->id > 4)
+ ret |= adp8860_set_bits(client, ADP8860_ISCT1,
+ (led->flags & 0x3) << ((led->id - 5) * 2));
+ else
+ ret |= adp8860_set_bits(client, ADP8860_ISCT2,
+ (led->flags & 0x3) << ((led->id - 1) * 2));
+
+ return ret;
+}
+
+static int __devinit adp8860_led_probe(struct i2c_client *client)
+{
+ struct adp8860_backlight_platform_data *pdata =
+ client->dev.platform_data;
+ struct adp8860_bl *data = i2c_get_clientdata(client);
+ struct adp8860_led *led, *led_dat;
+ struct led_info *cur_led;
+ int ret, i;
+
+ led = kzalloc(sizeof(*led) * pdata->num_leds, GFP_KERNEL);
+ if (led == NULL) {
+ dev_err(&client->dev, "failed to alloc memory\n");
+ return -ENOMEM;
+ }
+
+ ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law);
+ ret = adp8860_write(client, ADP8860_ISCT1,
+ (pdata->led_on_time & 0x3) << 6);
+ ret |= adp8860_write(client, ADP8860_ISCF,
+ FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
+
+ if (ret) {
+ dev_err(&client->dev, "failed to write\n");
+ goto err_free;
+ }
+
+ for (i = 0; i < pdata->num_leds; ++i) {
+ cur_led = &pdata->leds[i];
+ led_dat = &led[i];
+
+ led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK;
+
+ if (led_dat->id > 7 || led_dat->id < 1) {
+ dev_err(&client->dev, "Invalid LED ID %d\n",
+ led_dat->id);
+ goto err;
+ }
+
+ if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
+ dev_err(&client->dev, "LED %d used by Backlight\n",
+ led_dat->id);
+ goto err;
+ }
+
+ led_dat->cdev.name = cur_led->name;
+ led_dat->cdev.default_trigger = cur_led->default_trigger;
+ led_dat->cdev.brightness_set = adp8860_led_set;
+ led_dat->cdev.brightness = LED_OFF;
+ led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
+ led_dat->client = client;
+ led_dat->new_brightness = LED_OFF;
+ INIT_WORK(&led_dat->work, adp8860_led_work);
+
+ ret = led_classdev_register(&client->dev, &led_dat->cdev);
+ if (ret) {
+ dev_err(&client->dev, "failed to register LED %d\n",
+ led_dat->id);
+ goto err;
+ }
+
+ ret = adp8860_led_setup(led_dat);
+ if (ret) {
+ dev_err(&client->dev, "failed to write\n");
+ i++;
+ goto err;
+ }
+ }
+
+ data->led = led;
+
+ return 0;
+
+ err:
+ for (i = i - 1; i >= 0; --i) {
+ led_classdev_unregister(&led[i].cdev);
+ cancel_work_sync(&led[i].work);
+ }
+
+ err_free:
+ kfree(led);
+
+ return ret;
+}
+
+static int __devexit adp8860_led_remove(struct i2c_client *client)
+{
+ struct adp8860_backlight_platform_data *pdata =
+ client->dev.platform_data;
+ struct adp8860_bl *data = i2c_get_clientdata(client);
+ int i;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ led_classdev_unregister(&data->led[i].cdev);
+ cancel_work_sync(&data->led[i].work);
+ }
+
+ kfree(data->led);
+ return 0;
+}
+#else
+static int __devinit adp8860_led_probe(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int __devexit adp8860_led_remove(struct i2c_client *client)
+{
+ return 0;
+}
+#endif
+
+static int adp8860_bl_set(struct backlight_device *bl, int brightness)
+{
+ struct adp8860_bl *data = bl_get_data(bl);
+ struct i2c_client *client = data->client;
+ int ret = 0;
+
+ if (data->en_ambl_sens) {
+ if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) {
+ /* Disable Ambient Light auto adjust */
+ ret |= adp8860_clr_bits(client, ADP8860_MDCR,
+ CMP_AUTOEN);
+ ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
+ } else {
+ /*
+ * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
+ * restore daylight l1 sysfs brightness
+ */
+ ret |= adp8860_write(client, ADP8860_BLMX1,
+ data->cached_daylight_max);
+ ret |= adp8860_set_bits(client, ADP8860_MDCR,
+ CMP_AUTOEN);
+ }
+ } else
+ ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
+
+ if (data->current_brightness && brightness == 0)
+ ret |= adp8860_set_bits(client,
+ ADP8860_MDCR, DIM_EN);
+ else if (data->current_brightness == 0 && brightness)
+ ret |= adp8860_clr_bits(client,
+ ADP8860_MDCR, DIM_EN);
+
+ if (!ret)
+ data->current_brightness = brightness;
+
+ return ret;
+}
+
+static int adp8860_bl_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ return adp8860_bl_set(bl, brightness);
+}
+
+static int adp8860_bl_get_brightness(struct backlight_device *bl)
+{
+ struct adp8860_bl *data = bl_get_data(bl);
+
+ return data->current_brightness;
+}
+
+static const struct backlight_ops adp8860_bl_ops = {
+ .update_status = adp8860_bl_update_status,
+ .get_brightness = adp8860_bl_get_brightness,
+};
+
+static int adp8860_bl_setup(struct backlight_device *bl)
+{
+ struct adp8860_bl *data = bl_get_data(bl);
+ struct i2c_client *client = data->client;
+ struct adp8860_backlight_platform_data *pdata = data->pdata;
+ int ret = 0;
+
+ ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign);
+ ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max);
+ ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim);
+
+ if (data->en_ambl_sens) {
+ data->cached_daylight_max = pdata->l1_daylight_max;
+ ret |= adp8860_write(client, ADP8860_BLMX2,
+ pdata->l2_office_max);
+ ret |= adp8860_write(client, ADP8860_BLDM2,
+ pdata->l2_office_dim);
+ ret |= adp8860_write(client, ADP8860_BLMX3,
+ pdata->l3_dark_max);
+ ret |= adp8860_write(client, ADP8860_BLDM3,
+ pdata->l3_dark_dim);
+
+ ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip);
+ ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst);
+ ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip);
+ ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst);
+ ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN |
+ ALS_CCFG_VAL(pdata->abml_filt));
+ }
+
+ ret |= adp8860_write(client, ADP8860_CFGR,
+ BL_CFGR_VAL(pdata->bl_fade_law, 0));
+
+ ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in,
+ pdata->bl_fade_out));
+
+ ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY |
+ (data->gdwn_dis ? GDWN_DIS : 0));
+
+ return ret;
+}
+
+static ssize_t adp8860_show(struct device *dev, char *buf, int reg)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+ int error;
+ uint8_t reg_val;
+
+ mutex_lock(&data->lock);
+ error = adp8860_read(data->client, reg, &reg_val);
+ mutex_unlock(&data->lock);
+
+ if (error < 0)
+ return error;
+
+ return sprintf(buf, "%u\n", reg_val);
+}
+
+static ssize_t adp8860_store(struct device *dev, const char *buf,
+ size_t count, int reg)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ mutex_lock(&data->lock);
+ adp8860_write(data->client, reg, val);
+ mutex_unlock(&data->lock);
+
+ return count;
+}
+
+static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLMX3);
+}
+
+static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return adp8860_store(dev, buf, count, ADP8860_BLMX3);
+}
+
+static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show,
+ adp8860_bl_l3_dark_max_store);
+
+static ssize_t adp8860_bl_l2_office_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLMX2);
+}
+
+static ssize_t adp8860_bl_l2_office_max_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return adp8860_store(dev, buf, count, ADP8860_BLMX2);
+}
+static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show,
+ adp8860_bl_l2_office_max_store);
+
+static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLMX1);
+}
+
+static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+
+ strict_strtoul(buf, 10, &data->cached_daylight_max);
+ return adp8860_store(dev, buf, count, ADP8860_BLMX1);
+}
+static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
+ adp8860_bl_l1_daylight_max_store);
+
+static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLDM3);
+}
+
+static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return adp8860_store(dev, buf, count, ADP8860_BLDM3);
+}
+static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show,
+ adp8860_bl_l3_dark_dim_store);
+
+static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLDM2);
+}
+
+static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return adp8860_store(dev, buf, count, ADP8860_BLDM2);
+}
+static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show,
+ adp8860_bl_l2_office_dim_store);
+
+static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return adp8860_show(dev, buf, ADP8860_BLDM1);
+}
+
+static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return adp8860_store(dev, buf, count, ADP8860_BLDM1);
+}
+static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show,
+ adp8860_bl_l1_daylight_dim_store);
+
+#ifdef ADP8860_EXT_FEATURES
+static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+ int error;
+ uint8_t reg_val;
+ uint16_t ret_val;
+
+ mutex_lock(&data->lock);
+ error = adp8860_read(data->client, ADP8860_PH1LEVL, &reg_val);
+ ret_val = reg_val;
+ error |= adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
+ mutex_unlock(&data->lock);
+
+ if (error < 0)
+ return error;
+
+ /* Return 13-bit conversion value for the first light sensor */
+ ret_val += (reg_val & 0x1F) << 8;
+
+ return sprintf(buf, "%u\n", ret_val);
+}
+static DEVICE_ATTR(ambient_light_level, 0444,
+ adp8860_bl_ambient_light_level_show, NULL);
+
+static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+ int error;
+ uint8_t reg_val;
+
+ mutex_lock(&data->lock);
+ error = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
+ mutex_unlock(&data->lock);
+
+ if (error < 0)
+ return error;
+
+ return sprintf(buf, "%u\n",
+ ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
+}
+
+static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct adp8860_bl *data = dev_get_drvdata(dev);
+ unsigned long val;
+ uint8_t reg_val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val == 0) {
+ /* Enable automatic ambient light sensing */
+ adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
+ } else if ((val > 0) && (val < 6)) {
+ /* Disable automatic ambient light sensing */
+ adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
+
+ /* Set user supplied ambient light zone */
+ mutex_lock(&data->lock);
+ adp8860_read(data->client, ADP8860_CFGR, &reg_val);
+ reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
+ reg_val |= val << CFGR_BLV_SHIFT;
+ adp8860_write(data->client, ADP8860_CFGR, reg_val);
+ mutex_unlock(&data->lock);
+ }
+
+ return count;
+}
+static DEVICE_ATTR(ambient_light_zone, 0664,
+ adp8860_bl_ambient_light_zone_show,
+ adp8860_bl_ambient_light_zone_store);
+#endif
+
+static struct attribute *adp8860_bl_attributes[] = {
+ &dev_attr_l3_dark_max.attr,
+ &dev_attr_l3_dark_dim.attr,
+ &dev_attr_l2_office_max.attr,
+ &dev_attr_l2_office_dim.attr,
+ &dev_attr_l1_daylight_max.attr,
+ &dev_attr_l1_daylight_dim.attr,
+#ifdef ADP8860_EXT_FEATURES
+ &dev_attr_ambient_light_level.attr,
+ &dev_attr_ambient_light_zone.attr,
+#endif
+ NULL
+};
+
+static const struct attribute_group adp8860_bl_attr_group = {
+ .attrs = adp8860_bl_attributes,
+};
+
+static int __devinit adp8860_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct backlight_device *bl;
+ struct adp8860_bl *data;
+ struct adp8860_backlight_platform_data *pdata =
+ client->dev.platform_data;
+ struct backlight_properties props;
+ uint8_t reg_val;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+ return -EIO;
+ }
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data?\n");
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ ret = adp8860_read(client, ADP8860_MFDVID, &reg_val);
+ if (ret < 0)
+ goto out2;
+
+ switch (ADP8860_MANID(reg_val)) {
+ case ADP8863_MANUFID:
+ data->gdwn_dis = !!pdata->gdwn_dis;
+ case ADP8860_MANUFID:
+ data->en_ambl_sens = !!pdata->en_ambl_sens;
+ break;
+ case ADP8861_MANUFID:
+ data->gdwn_dis = !!pdata->gdwn_dis;
+ break;
+ default:
+ dev_err(&client->dev, "failed to probe\n");
+ ret = -ENODEV;
+ goto out2;
+ }
+
+ /* It's confirmed that the DEVID field is actually a REVID */
+
+ data->revid = ADP8860_DEVID(reg_val);
+ data->client = client;
+ data->pdata = pdata;
+ data->id = id->driver_data;
+ data->current_brightness = 0;
+ i2c_set_clientdata(client, data);
+
+ memset(&props, 0, sizeof(props));
+ props.max_brightness = ADP8860_MAX_BRIGHTNESS;
+
+ mutex_init(&data->lock);
+
+ bl = backlight_device_register(dev_driver_string(&client->dev),
+ &client->dev, data, &adp8860_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ dev_err(&client->dev, "failed to register backlight\n");
+ ret = PTR_ERR(bl);
+ goto out2;
+ }
+
+ bl->props.max_brightness =
+ bl->props.brightness = ADP8860_MAX_BRIGHTNESS;
+
+ data->bl = bl;
+
+ if (data->en_ambl_sens)
+ ret = sysfs_create_group(&bl->dev.kobj,
+ &adp8860_bl_attr_group);
+
+ if (ret) {
+ dev_err(&client->dev, "failed to register sysfs\n");
+ goto out1;
+ }
+
+ ret = adp8860_bl_setup(bl);
+ if (ret) {
+ ret = -EIO;
+ goto out;
+ }
+
+ backlight_update_status(bl);
+
+ dev_info(&client->dev, "%s Rev.%d Backlight\n",
+ client->name, data->revid);
+
+ if (pdata->num_leds)
+ adp8860_led_probe(client);
+
+ return 0;
+
+out:
+ if (data->en_ambl_sens)
+ sysfs_remove_group(&data->bl->dev.kobj,
+ &adp8860_bl_attr_group);
+out1:
+ backlight_device_unregister(bl);
+out2:
+ kfree(data);
+
+ return ret;
+}
+
+static int __devexit adp8860_remove(struct i2c_client *client)
+{
+ struct adp8860_bl *data = i2c_get_clientdata(client);
+
+ adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
+
+ if (data->led)
+ adp8860_led_remove(client);
+
+ if (data->en_ambl_sens)
+ sysfs_remove_group(&data->bl->dev.kobj,
+ &adp8860_bl_attr_group);
+
+ backlight_device_unregister(data->bl);
+ kfree(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+ adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
+
+ return 0;
+}
+
+static int adp8860_i2c_resume(struct i2c_client *client)
+{
+ adp8860_set_bits(client, ADP8860_MDCR, NSTBY);
+
+ return 0;
+}
+#else
+#define adp8860_i2c_suspend NULL
+#define adp8860_i2c_resume NULL
+#endif
+
+static const struct i2c_device_id adp8860_id[] = {
+ { "adp8860", adp8860 },
+ { "adp8861", adp8861 },
+ { "adp8863", adp8863 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adp8860_id);
+
+static struct i2c_driver adp8860_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ },
+ .probe = adp8860_probe,
+ .remove = __devexit_p(adp8860_remove),
+ .suspend = adp8860_i2c_suspend,
+ .resume = adp8860_i2c_resume,
+ .id_table = adp8860_id,
+};
+
+static int __init adp8860_init(void)
+{
+ return i2c_add_driver(&adp8860_driver);
+}
+module_init(adp8860_init);
+
+static void __exit adp8860_exit(void)
+{
+ i2c_del_driver(&adp8860_driver);
+}
+module_exit(adp8860_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP8860 Backlight driver");
+MODULE_ALIAS("i2c:adp8860-backlight");
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
index 7f4a7c30a98..fe9af129c5d 100644
--- a/drivers/video/backlight/adx_bl.c
+++ b/drivers/video/backlight/adx_bl.c
@@ -107,8 +107,8 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev)
props.max_brightness = 0xff;
bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev,
bl, &adx_backlight_ops, &props);
- if (!bldev) {
- ret = -ENOMEM;
+ if (IS_ERR(bldev)) {
+ ret = PTR_ERR(bldev);
goto out;
}
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
new file mode 100644
index 00000000000..b0cc4918480
--- /dev/null
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -0,0 +1,160 @@
+/*
+ * Driver for the Cirrus EP93xx lcd backlight
+ *
+ * Copyright (c) 2010 H Hartley Sweeten <hsweeten@visionengravers.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.
+ *
+ * This driver controls the pulse width modulated brightness control output,
+ * BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
+ */
+
+
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include <mach/hardware.h>
+
+#define EP93XX_RASTER_REG(x) (EP93XX_RASTER_BASE + (x))
+#define EP93XX_RASTER_BRIGHTNESS EP93XX_RASTER_REG(0x20)
+
+#define EP93XX_MAX_COUNT 255
+#define EP93XX_MAX_BRIGHT 255
+#define EP93XX_DEF_BRIGHT 128
+
+struct ep93xxbl {
+ void __iomem *mmio;
+ int brightness;
+};
+
+static int ep93xxbl_set(struct backlight_device *bl, int brightness)
+{
+ struct ep93xxbl *ep93xxbl = bl_get_data(bl);
+
+ __raw_writel((brightness << 8) | EP93XX_MAX_COUNT, ep93xxbl->mmio);
+
+ ep93xxbl->brightness = brightness;
+
+ return 0;
+}
+
+static int ep93xxbl_update_status(struct backlight_device *bl)
+{
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK ||
+ bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ return ep93xxbl_set(bl, brightness);
+}
+
+static int ep93xxbl_get_brightness(struct backlight_device *bl)
+{
+ struct ep93xxbl *ep93xxbl = bl_get_data(bl);
+
+ return ep93xxbl->brightness;
+}
+
+static const struct backlight_ops ep93xxbl_ops = {
+ .update_status = ep93xxbl_update_status,
+ .get_brightness = ep93xxbl_get_brightness,
+};
+
+static int __init ep93xxbl_probe(struct platform_device *dev)
+{
+ struct ep93xxbl *ep93xxbl;
+ struct backlight_device *bl;
+ struct backlight_properties props;
+
+ ep93xxbl = devm_kzalloc(&dev->dev, sizeof(*ep93xxbl), GFP_KERNEL);
+ if (!ep93xxbl)
+ return -ENOMEM;
+
+ /*
+ * This register is located in the range already ioremap'ed by
+ * the framebuffer driver. A MFD driver seems a bit of overkill
+ * to handle this so use the static I/O mapping; this address
+ * is already virtual.
+ *
+ * NOTE: No locking is required; the framebuffer does not touch
+ * this register.
+ */
+ ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = EP93XX_MAX_BRIGHT;
+ bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl,
+ &ep93xxbl_ops, &props);
+ if (IS_ERR(bl))
+ return PTR_ERR(bl);
+
+ bl->props.brightness = EP93XX_DEF_BRIGHT;
+
+ platform_set_drvdata(dev, bl);
+
+ ep93xxbl_update_status(bl);
+
+ return 0;
+}
+
+static int ep93xxbl_remove(struct platform_device *dev)
+{
+ struct backlight_device *bl = platform_get_drvdata(dev);
+
+ backlight_device_unregister(bl);
+ platform_set_drvdata(dev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ep93xxbl_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct backlight_device *bl = platform_get_drvdata(dev);
+
+ return ep93xxbl_set(bl, 0);
+}
+
+static int ep93xxbl_resume(struct platform_device *dev)
+{
+ struct backlight_device *bl = platform_get_drvdata(dev);
+
+ backlight_update_status(bl);
+ return 0;
+}
+#else
+#define ep93xxbl_suspend NULL
+#define ep93xxbl_resume NULL
+#endif
+
+static struct platform_driver ep93xxbl_driver = {
+ .driver = {
+ .name = "ep93xx-bl",
+ .owner = THIS_MODULE,
+ },
+ .probe = ep93xxbl_probe,
+ .remove = __devexit_p(ep93xxbl_remove),
+ .suspend = ep93xxbl_suspend,
+ .resume = ep93xxbl_resume,
+};
+
+static int __init ep93xxbl_init(void)
+{
+ return platform_driver_register(&ep93xxbl_driver);
+}
+module_init(ep93xxbl_init);
+
+static void __exit ep93xxbl_exit(void)
+{
+ platform_driver_unregister(&ep93xxbl_driver);
+}
+module_exit(ep93xxbl_exit);
+
+MODULE_DESCRIPTION("EP93xx Backlight Driver");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ep93xx-bl");
diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c
index bcdb12c93ef..9093ef0fa86 100644
--- a/drivers/video/backlight/l4f00242t03.c
+++ b/drivers/video/backlight/l4f00242t03.c
@@ -125,8 +125,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (priv == NULL) {
dev_err(&spi->dev, "No memory for this device.\n");
- ret = -ENOMEM;
- goto err;
+ return -ENOMEM;
}
dev_set_drvdata(&spi->dev, priv);
@@ -139,7 +138,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (ret) {
dev_err(&spi->dev,
"Unable to get the lcd l4f00242t03 reset gpio.\n");
- return ret;
+ goto err;
}
ret = gpio_direction_output(pdata->reset_gpio, 1);
@@ -151,7 +150,7 @@ static int __devinit l4f00242t03_probe(struct spi_device *spi)
if (ret) {
dev_err(&spi->dev,
"Unable to get the lcd l4f00242t03 data en gpio.\n");
- return ret;
+ goto err2;
}
ret = gpio_direction_output(pdata->data_enable_gpio, 0);
@@ -222,9 +221,9 @@ static int __devexit l4f00242t03_remove(struct spi_device *spi)
gpio_free(pdata->reset_gpio);
if (priv->io_reg)
- regulator_put(priv->core_reg);
- if (priv->core_reg)
regulator_put(priv->io_reg);
+ if (priv->core_reg)
+ regulator_put(priv->core_reg);
kfree(priv);
diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c
index b5accc957ad..b2b2c7ba1f6 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -162,6 +162,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev)
backlight_update_status(bl);
return 0;
out:
+ backlight_device_unregister(bl);
kfree(data);
return ret;
}
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 1b5d3fe6bbb..9fb533f6373 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -141,7 +141,7 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
.callback = mbp_dmi_match,
.ident = "MacBook 1,1",
.matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
},
.driver_data = (void *)&intel_chipset_data,
@@ -184,6 +184,42 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
},
{
.callback = mbp_dmi_match,
+ .ident = "MacBookPro 1,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
+ },
+ .driver_data = (void *)&intel_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookPro 1,2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,2"),
+ },
+ .driver_data = (void *)&intel_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookPro 2,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,1"),
+ },
+ .driver_data = (void *)&intel_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
+ .ident = "MacBookPro 2,2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
+ },
+ .driver_data = (void *)&intel_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
.ident = "MacBookPro 3,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
@@ -238,6 +274,15 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
},
{
.callback = mbp_dmi_match,
+ .ident = "MacBook 6,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
+ },
+ .driver_data = (void *)&nvidia_chipset_data,
+ },
+ {
+ .callback = mbp_dmi_match,
.ident = "MacBookAir 2,1",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c
new file mode 100644
index 00000000000..3c424f7efdc
--- /dev/null
+++ b/drivers/video/backlight/pcf50633-backlight.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * PCF50633 backlight device driver
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <linux/mfd/pcf50633/core.h>
+#include <linux/mfd/pcf50633/backlight.h>
+
+struct pcf50633_bl {
+ struct pcf50633 *pcf;
+ struct backlight_device *bl;
+
+ unsigned int brightness;
+ unsigned int brightness_limit;
+};
+
+/*
+ * pcf50633_bl_set_brightness_limit
+ *
+ * Update the brightness limit for the pc50633 backlight. The actual brightness
+ * will not go above the limit. This is useful to limit power drain for example
+ * on low battery.
+ *
+ * @dev: Pointer to a pcf50633 device
+ * @limit: The brightness limit. Valid values are 0-63
+ */
+int pcf50633_bl_set_brightness_limit(struct pcf50633 *pcf, unsigned int limit)
+{
+ struct pcf50633_bl *pcf_bl = platform_get_drvdata(pcf->bl_pdev);
+
+ if (!pcf_bl)
+ return -ENODEV;
+
+ pcf_bl->brightness_limit = limit & 0x3f;
+ backlight_update_status(pcf_bl->bl);
+
+ return 0;
+}
+
+static int pcf50633_bl_update_status(struct backlight_device *bl)
+{
+ struct pcf50633_bl *pcf_bl = bl_get_data(bl);
+ unsigned int new_brightness;
+
+
+ if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK) ||
+ bl->props.power != FB_BLANK_UNBLANK)
+ new_brightness = 0;
+ else if (bl->props.brightness < pcf_bl->brightness_limit)
+ new_brightness = bl->props.brightness;
+ else
+ new_brightness = pcf_bl->brightness_limit;
+
+
+ if (pcf_bl->brightness == new_brightness)
+ return 0;
+
+ if (new_brightness) {
+ pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDOUT,
+ new_brightness);
+ if (!pcf_bl->brightness)
+ pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 1);
+ } else {
+ pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDENA, 0);
+ }
+
+ pcf_bl->brightness = new_brightness;
+
+ return 0;
+}
+
+static int pcf50633_bl_get_brightness(struct backlight_device *bl)
+{
+ struct pcf50633_bl *pcf_bl = bl_get_data(bl);
+ return pcf_bl->brightness;
+}
+
+static const struct backlight_ops pcf50633_bl_ops = {
+ .get_brightness = pcf50633_bl_get_brightness,
+ .update_status = pcf50633_bl_update_status,
+ .options = BL_CORE_SUSPENDRESUME,
+};
+
+static int __devinit pcf50633_bl_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct pcf50633_bl *pcf_bl;
+ struct device *parent = pdev->dev.parent;
+ struct pcf50633_platform_data *pcf50633_data = parent->platform_data;
+ struct pcf50633_bl_platform_data *pdata = pcf50633_data->backlight_data;
+ struct backlight_properties bl_props;
+
+ pcf_bl = kzalloc(sizeof(*pcf_bl), GFP_KERNEL);
+ if (!pcf_bl)
+ return -ENOMEM;
+
+ bl_props.max_brightness = 0x3f;
+ bl_props.power = FB_BLANK_UNBLANK;
+
+ if (pdata) {
+ bl_props.brightness = pdata->default_brightness;
+ pcf_bl->brightness_limit = pdata->default_brightness_limit;
+ } else {
+ bl_props.brightness = 0x3f;
+ pcf_bl->brightness_limit = 0x3f;
+ }
+
+ pcf_bl->pcf = dev_to_pcf50633(pdev->dev.parent);
+
+ pcf_bl->bl = backlight_device_register(pdev->name, &pdev->dev, pcf_bl,
+ &pcf50633_bl_ops, &bl_props);
+
+ if (IS_ERR(pcf_bl->bl)) {
+ ret = PTR_ERR(pcf_bl->bl);
+ goto err_free;
+ }
+
+ platform_set_drvdata(pdev, pcf_bl);
+
+ pcf50633_reg_write(pcf_bl->pcf, PCF50633_REG_LEDDIM, pdata->ramp_time);
+
+ /* Should be different from bl_props.brightness, so we do not exit
+ * update_status early the first time it's called */
+ pcf_bl->brightness = pcf_bl->bl->props.brightness + 1;
+
+ backlight_update_status(pcf_bl->bl);
+
+ return 0;
+
+err_free:
+ kfree(pcf_bl);
+
+ return ret;
+}
+
+static int __devexit pcf50633_bl_remove(struct platform_device *pdev)
+{
+ struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev);
+
+ backlight_device_unregister(pcf_bl->bl);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(pcf_bl);
+
+ return 0;
+}
+
+static struct platform_driver pcf50633_bl_driver = {
+ .probe = pcf50633_bl_probe,
+ .remove = __devexit_p(pcf50633_bl_remove),
+ .driver = {
+ .name = "pcf50633-backlight",
+ },
+};
+
+static int __init pcf50633_bl_init(void)
+{
+ return platform_driver_register(&pcf50633_bl_driver);
+}
+module_init(pcf50633_bl_init);
+
+static void __exit pcf50633_bl_exit(void)
+{
+ platform_driver_unregister(&pcf50633_bl_driver);
+}
+module_exit(pcf50633_bl_exit);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("PCF50633 backlight driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcf50633-backlight");
diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c
new file mode 100644
index 00000000000..a3128c9cb7a
--- /dev/null
+++ b/drivers/video/backlight/s6e63m0.c
@@ -0,0 +1,920 @@
+/*
+ * S6E63M0 AMOLED LCD panel driver.
+ *
+ * Author: InKi Dae <inki.dae@samsung.com>
+ *
+ * Derived from drivers/video/omap/lcd-apollon.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+
+#include "s6e63m0_gamma.h"
+
+#define SLEEPMSEC 0x1000
+#define ENDDEF 0x2000
+#define DEFMASK 0xFF00
+#define COMMAND_ONLY 0xFE
+#define DATA_ONLY 0xFF
+
+#define MIN_BRIGHTNESS 0
+#define MAX_BRIGHTNESS 10
+
+#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
+
+struct s6e63m0 {
+ struct device *dev;
+ struct spi_device *spi;
+ unsigned int power;
+ unsigned int current_brightness;
+ unsigned int gamma_mode;
+ unsigned int gamma_table_count;
+ struct lcd_device *ld;
+ struct backlight_device *bd;
+ struct lcd_platform_data *lcd_pd;
+};
+
+static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
+ 0xF8, 0x01,
+ DATA_ONLY, 0x27,
+ DATA_ONLY, 0x27,
+ DATA_ONLY, 0x07,
+ DATA_ONLY, 0x07,
+ DATA_ONLY, 0x54,
+ DATA_ONLY, 0x9f,
+ DATA_ONLY, 0x63,
+ DATA_ONLY, 0x86,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x33,
+ DATA_ONLY, 0x0d,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
+ 0xf2, 0x02,
+ DATA_ONLY, 0x03,
+ DATA_ONLY, 0x1c,
+ DATA_ONLY, 0x10,
+ DATA_ONLY, 0x10,
+
+ 0xf7, 0x03,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_GAMMA_SETTING[] = {
+ 0xfa, 0x00,
+ DATA_ONLY, 0x18,
+ DATA_ONLY, 0x08,
+ DATA_ONLY, 0x24,
+ DATA_ONLY, 0x64,
+ DATA_ONLY, 0x56,
+ DATA_ONLY, 0x33,
+ DATA_ONLY, 0xb6,
+ DATA_ONLY, 0xba,
+ DATA_ONLY, 0xa8,
+ DATA_ONLY, 0xac,
+ DATA_ONLY, 0xb1,
+ DATA_ONLY, 0x9d,
+ DATA_ONLY, 0xc1,
+ DATA_ONLY, 0xc1,
+ DATA_ONLY, 0xb7,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x9c,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x9f,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0xd6,
+
+ 0xfa, 0x01,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ETC_CONDITION_SET[] = {
+ 0xf6, 0x00,
+ DATA_ONLY, 0x8c,
+ DATA_ONLY, 0x07,
+
+ 0xb3, 0xc,
+
+ 0xb5, 0x2c,
+ DATA_ONLY, 0x12,
+ DATA_ONLY, 0x0c,
+ DATA_ONLY, 0x0a,
+ DATA_ONLY, 0x10,
+ DATA_ONLY, 0x0e,
+ DATA_ONLY, 0x17,
+ DATA_ONLY, 0x13,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x2a,
+ DATA_ONLY, 0x24,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1b,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x17,
+
+ DATA_ONLY, 0x2b,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x3a,
+ DATA_ONLY, 0x34,
+ DATA_ONLY, 0x30,
+ DATA_ONLY, 0x2c,
+ DATA_ONLY, 0x29,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x25,
+ DATA_ONLY, 0x23,
+ DATA_ONLY, 0x21,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x1e,
+ DATA_ONLY, 0x1e,
+
+ 0xb6, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x11,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x33,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+
+ 0xb7, 0x2c,
+ DATA_ONLY, 0x12,
+ DATA_ONLY, 0x0c,
+ DATA_ONLY, 0x0a,
+ DATA_ONLY, 0x10,
+ DATA_ONLY, 0x0e,
+ DATA_ONLY, 0x17,
+ DATA_ONLY, 0x13,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x2a,
+ DATA_ONLY, 0x24,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1b,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x17,
+
+ DATA_ONLY, 0x2b,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x3a,
+ DATA_ONLY, 0x34,
+ DATA_ONLY, 0x30,
+ DATA_ONLY, 0x2c,
+ DATA_ONLY, 0x29,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x25,
+ DATA_ONLY, 0x23,
+ DATA_ONLY, 0x21,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x1e,
+ DATA_ONLY, 0x1e,
+
+ 0xb8, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x11,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x33,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+
+ 0xb9, 0x2c,
+ DATA_ONLY, 0x12,
+ DATA_ONLY, 0x0c,
+ DATA_ONLY, 0x0a,
+ DATA_ONLY, 0x10,
+ DATA_ONLY, 0x0e,
+ DATA_ONLY, 0x17,
+ DATA_ONLY, 0x13,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x2a,
+ DATA_ONLY, 0x24,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x1b,
+ DATA_ONLY, 0x1a,
+ DATA_ONLY, 0x17,
+
+ DATA_ONLY, 0x2b,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x3a,
+ DATA_ONLY, 0x34,
+ DATA_ONLY, 0x30,
+ DATA_ONLY, 0x2c,
+ DATA_ONLY, 0x29,
+ DATA_ONLY, 0x26,
+ DATA_ONLY, 0x25,
+ DATA_ONLY, 0x23,
+ DATA_ONLY, 0x21,
+ DATA_ONLY, 0x20,
+ DATA_ONLY, 0x1e,
+ DATA_ONLY, 0x1e,
+
+ 0xba, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x11,
+ DATA_ONLY, 0x22,
+ DATA_ONLY, 0x33,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+ DATA_ONLY, 0x44,
+
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x55,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+ DATA_ONLY, 0x66,
+
+ 0xc1, 0x4d,
+ DATA_ONLY, 0x96,
+ DATA_ONLY, 0x1d,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x01,
+ DATA_ONLY, 0xdf,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x03,
+ DATA_ONLY, 0x1f,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x00,
+ DATA_ONLY, 0x03,
+ DATA_ONLY, 0x06,
+ DATA_ONLY, 0x09,
+ DATA_ONLY, 0x0d,
+ DATA_ONLY, 0x0f,
+ DATA_ONLY, 0x12,
+ DATA_ONLY, 0x15,
+ DATA_ONLY, 0x18,
+
+ 0xb2, 0x10,
+ DATA_ONLY, 0x10,
+ DATA_ONLY, 0x0b,
+ DATA_ONLY, 0x05,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ACL_ON[] = {
+ /* ACL on */
+ 0xc0, 0x01,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ACL_OFF[] = {
+ /* ACL off */
+ 0xc0, 0x00,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ELVSS_ON[] = {
+ /* ELVSS on */
+ 0xb1, 0x0b,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_ELVSS_OFF[] = {
+ /* ELVSS off */
+ 0xb1, 0x0a,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_STAND_BY_OFF[] = {
+ 0x11, COMMAND_ONLY,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_STAND_BY_ON[] = {
+ 0x10, COMMAND_ONLY,
+
+ ENDDEF, 0x0000
+};
+
+static const unsigned short SEQ_DISPLAY_ON[] = {
+ 0x29, COMMAND_ONLY,
+
+ ENDDEF, 0x0000
+};
+
+
+static int s6e63m0_spi_write_byte(struct s6e63m0 *lcd, int addr, int data)
+{
+ u16 buf[1];
+ struct spi_message msg;
+
+ struct spi_transfer xfer = {
+ .len = 2,
+ .tx_buf = buf,
+ };
+
+ buf[0] = (addr << 8) | data;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ return spi_sync(lcd->spi, &msg);
+}
+
+static int s6e63m0_spi_write(struct s6e63m0 *lcd, unsigned char address,
+ unsigned char command)
+{
+ int ret = 0;
+
+ if (address != DATA_ONLY)
+ ret = s6e63m0_spi_write_byte(lcd, 0x0, address);
+ if (command != COMMAND_ONLY)
+ ret = s6e63m0_spi_write_byte(lcd, 0x1, command);
+
+ return ret;
+}
+
+static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
+ const unsigned short *wbuf)
+{
+ int ret = 0, i = 0;
+
+ while ((wbuf[i] & DEFMASK) != ENDDEF) {
+ if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
+ ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
+ if (ret)
+ break;
+ } else
+ udelay(wbuf[i+1]*1000);
+ i += 2;
+ }
+
+ return ret;
+}
+
+static int _s6e63m0_gamma_ctl(struct s6e63m0 *lcd, const unsigned int *gamma)
+{
+ unsigned int i = 0;
+ int ret = 0;
+
+ /* disable gamma table updating. */
+ ret = s6e63m0_spi_write(lcd, 0xfa, 0x00);
+ if (ret) {
+ dev_err(lcd->dev, "failed to disable gamma table updating.\n");
+ goto gamma_err;
+ }
+
+ for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
+ ret = s6e63m0_spi_write(lcd, DATA_ONLY, gamma[i]);
+ if (ret) {
+ dev_err(lcd->dev, "failed to set gamma table.\n");
+ goto gamma_err;
+ }
+ }
+
+ /* update gamma table. */
+ ret = s6e63m0_spi_write(lcd, 0xfa, 0x01);
+ if (ret)
+ dev_err(lcd->dev, "failed to update gamma table.\n");
+
+gamma_err:
+ return ret;
+}
+
+static int s6e63m0_gamma_ctl(struct s6e63m0 *lcd, int gamma)
+{
+ int ret = 0;
+
+ ret = _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
+
+ return ret;
+}
+
+
+static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
+{
+ int ret, i;
+ const unsigned short *init_seq[] = {
+ SEQ_PANEL_CONDITION_SET,
+ SEQ_DISPLAY_CONDITION_SET,
+ SEQ_GAMMA_SETTING,
+ SEQ_ETC_CONDITION_SET,
+ SEQ_ACL_ON,
+ SEQ_ELVSS_ON,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+ ret = s6e63m0_panel_send_sequence(lcd, init_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
+{
+ int ret = 0, i;
+ const unsigned short *enable_seq[] = {
+ SEQ_STAND_BY_OFF,
+ SEQ_DISPLAY_ON,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
+ ret = s6e63m0_panel_send_sequence(lcd, enable_seq[i]);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
+{
+ int ret;
+
+ ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON);
+
+ return ret;
+}
+
+static int s6e63m0_power_on(struct s6e63m0 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+ struct backlight_device *bd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL.\n");
+ return -EFAULT;
+ }
+
+ bd = lcd->bd;
+ if (!bd) {
+ dev_err(lcd->dev, "backlight device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->power_on(lcd->ld, 1);
+ mdelay(pd->power_on_delay);
+ }
+
+ if (!pd->reset) {
+ dev_err(lcd->dev, "reset is NULL.\n");
+ return -EFAULT;
+ } else {
+ pd->reset(lcd->ld);
+ mdelay(pd->reset_delay);
+ }
+
+ ret = s6e63m0_ldi_init(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to initialize ldi.\n");
+ return ret;
+ }
+
+ ret = s6e63m0_ldi_enable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "failed to enable ldi.\n");
+ return ret;
+ }
+
+ /* set brightness to current value after power on or resume. */
+ ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
+ if (ret) {
+ dev_err(lcd->dev, "lcd gamma setting failed.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int s6e63m0_power_off(struct s6e63m0 *lcd)
+{
+ int ret = 0;
+ struct lcd_platform_data *pd = NULL;
+
+ pd = lcd->lcd_pd;
+ if (!pd) {
+ dev_err(lcd->dev, "platform data is NULL.\n");
+ return -EFAULT;
+ }
+
+ ret = s6e63m0_ldi_disable(lcd);
+ if (ret) {
+ dev_err(lcd->dev, "lcd setting failed.\n");
+ return -EIO;
+ }
+
+ mdelay(pd->power_off_delay);
+
+ if (!pd->power_on) {
+ dev_err(lcd->dev, "power_on is NULL.\n");
+ return -EFAULT;
+ } else
+ pd->power_on(lcd->ld, 0);
+
+ return 0;
+}
+
+static int s6e63m0_power(struct s6e63m0 *lcd, int power)
+{
+ int ret = 0;
+
+ if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+ ret = s6e63m0_power_on(lcd);
+ else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+ ret = s6e63m0_power_off(lcd);
+
+ if (!ret)
+ lcd->power = power;
+
+ return ret;
+}
+
+static int s6e63m0_set_power(struct lcd_device *ld, int power)
+{
+ struct s6e63m0 *lcd = lcd_get_data(ld);
+
+ if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+ power != FB_BLANK_NORMAL) {
+ dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+ return -EINVAL;
+ }
+
+ return s6e63m0_power(lcd, power);
+}
+
+static int s6e63m0_get_power(struct lcd_device *ld)
+{
+ struct s6e63m0 *lcd = lcd_get_data(ld);
+
+ return lcd->power;
+}
+
+static int s6e63m0_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+static int s6e63m0_set_brightness(struct backlight_device *bd)
+{
+ int ret = 0, brightness = bd->props.brightness;
+ struct s6e63m0 *lcd = bl_get_data(bd);
+
+ if (brightness < MIN_BRIGHTNESS ||
+ brightness > bd->props.max_brightness) {
+ dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
+ MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+ return -EINVAL;
+ }
+
+ ret = s6e63m0_gamma_ctl(lcd, bd->props.brightness);
+ if (ret) {
+ dev_err(&bd->dev, "lcd brightness setting failed.\n");
+ return -EIO;
+ }
+
+ return ret;
+}
+
+static struct lcd_ops s6e63m0_lcd_ops = {
+ .set_power = s6e63m0_set_power,
+ .get_power = s6e63m0_get_power,
+};
+
+static const struct backlight_ops s6e63m0_backlight_ops = {
+ .get_brightness = s6e63m0_get_brightness,
+ .update_status = s6e63m0_set_brightness,
+};
+
+static ssize_t s6e63m0_sysfs_show_gamma_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct s6e63m0 *lcd = dev_get_drvdata(dev);
+ char temp[10];
+
+ switch (lcd->gamma_mode) {
+ case 0:
+ sprintf(temp, "2.2 mode\n");
+ strcat(buf, temp);
+ break;
+ case 1:
+ sprintf(temp, "1.9 mode\n");
+ strcat(buf, temp);
+ break;
+ case 2:
+ sprintf(temp, "1.7 mode\n");
+ strcat(buf, temp);
+ break;
+ default:
+ dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7)n");
+ break;
+ }
+
+ return strlen(buf);
+}
+
+static ssize_t s6e63m0_sysfs_store_gamma_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct s6e63m0 *lcd = dev_get_drvdata(dev);
+ struct backlight_device *bd = NULL;
+ int brightness, rc;
+
+ rc = strict_strtoul(buf, 0, (unsigned long *)&lcd->gamma_mode);
+ if (rc < 0)
+ return rc;
+
+ bd = lcd->bd;
+
+ brightness = bd->props.brightness;
+
+ switch (lcd->gamma_mode) {
+ case 0:
+ _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
+ break;
+ case 1:
+ _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_19_table[brightness]);
+ break;
+ case 2:
+ _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_17_table[brightness]);
+ break;
+ default:
+ dev_info(dev, "gamma mode could be 0:2.2, 1:1.9 or 2:1.7\n");
+ _s6e63m0_gamma_ctl(lcd, gamma_table.gamma_22_table[brightness]);
+ break;
+ }
+ return len;
+}
+
+static DEVICE_ATTR(gamma_mode, 0644,
+ s6e63m0_sysfs_show_gamma_mode, s6e63m0_sysfs_store_gamma_mode);
+
+static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct s6e63m0 *lcd = dev_get_drvdata(dev);
+ char temp[3];
+
+ sprintf(temp, "%d\n", lcd->gamma_table_count);
+ strcpy(buf, temp);
+
+ return strlen(buf);
+}
+static DEVICE_ATTR(gamma_table, 0644,
+ s6e63m0_sysfs_show_gamma_table, NULL);
+
+static int __init s6e63m0_probe(struct spi_device *spi)
+{
+ int ret = 0;
+ struct s6e63m0 *lcd = NULL;
+ struct lcd_device *ld = NULL;
+ struct backlight_device *bd = NULL;
+
+ lcd = kzalloc(sizeof(struct s6e63m0), GFP_KERNEL);
+ if (!lcd)
+ return -ENOMEM;
+
+ /* s6e63m0 lcd panel uses 3-wire 9bits SPI Mode. */
+ spi->bits_per_word = 9;
+
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "spi setup failed.\n");
+ goto out_free_lcd;
+ }
+
+ lcd->spi = spi;
+ lcd->dev = &spi->dev;
+
+ lcd->lcd_pd = (struct lcd_platform_data *)spi->dev.platform_data;
+ if (!lcd->lcd_pd) {
+ dev_err(&spi->dev, "platform data is NULL.\n");
+ goto out_free_lcd;
+ }
+
+ ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops);
+ if (IS_ERR(ld)) {
+ ret = PTR_ERR(ld);
+ goto out_free_lcd;
+ }
+
+ lcd->ld = ld;
+
+ bd = backlight_device_register("s6e63m0bl-bl", &spi->dev, lcd,
+ &s6e63m0_backlight_ops, NULL);
+ if (IS_ERR(bd)) {
+ ret = PTR_ERR(bd);
+ goto out_lcd_unregister;
+ }
+
+ bd->props.max_brightness = MAX_BRIGHTNESS;
+ bd->props.brightness = MAX_BRIGHTNESS;
+ lcd->bd = bd;
+
+ /*
+ * it gets gamma table count available so it gets user
+ * know that.
+ */
+ lcd->gamma_table_count =
+ sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int));
+
+ ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
+ if (ret < 0)
+ dev_err(&(spi->dev), "failed to add sysfs entries\n");
+
+ ret = device_create_file(&(spi->dev), &dev_attr_gamma_table);
+ if (ret < 0)
+ dev_err(&(spi->dev), "failed to add sysfs entries\n");
+
+ /*
+ * if lcd panel was on from bootloader like u-boot then
+ * do not lcd on.
+ */
+ if (!lcd->lcd_pd->lcd_enabled) {
+ /*
+ * if lcd panel was off from bootloader then
+ * current lcd status is powerdown and then
+ * it enables lcd panel.
+ */
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ s6e63m0_power(lcd, FB_BLANK_UNBLANK);
+ } else
+ lcd->power = FB_BLANK_UNBLANK;
+
+ dev_set_drvdata(&spi->dev, lcd);
+
+ dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
+
+ return 0;
+
+out_lcd_unregister:
+ lcd_device_unregister(ld);
+out_free_lcd:
+ kfree(lcd);
+ return ret;
+}
+
+static int __devexit s6e63m0_remove(struct spi_device *spi)
+{
+ struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+ s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+ lcd_device_unregister(lcd->ld);
+ kfree(lcd);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+unsigned int before_power;
+
+static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+ int ret = 0;
+ struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+ before_power = lcd->power;
+
+ /*
+ * when lcd panel is suspend, lcd panel becomes off
+ * regardless of status.
+ */
+ ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+
+ return ret;
+}
+
+static int s6e63m0_resume(struct spi_device *spi)
+{
+ int ret = 0;
+ struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+ /*
+ * after suspended, if lcd panel status is FB_BLANK_UNBLANK
+ * (at that time, before_power is FB_BLANK_UNBLANK) then
+ * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
+ */
+ if (before_power == FB_BLANK_UNBLANK)
+ lcd->power = FB_BLANK_POWERDOWN;
+
+ dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+
+ ret = s6e63m0_power(lcd, before_power);
+
+ return ret;
+}
+#else
+#define s6e63m0_suspend NULL
+#define s6e63m0_resume NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt. */
+static void s6e63m0_shutdown(struct spi_device *spi)
+{
+ struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+
+ s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver s6e63m0_driver = {
+ .driver = {
+ .name = "s6e63m0",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = s6e63m0_probe,
+ .remove = __devexit_p(s6e63m0_remove),
+ .shutdown = s6e63m0_shutdown,
+ .suspend = s6e63m0_suspend,
+ .resume = s6e63m0_resume,
+};
+
+static int __init s6e63m0_init(void)
+{
+ return spi_register_driver(&s6e63m0_driver);
+}
+
+static void __exit s6e63m0_exit(void)
+{
+ spi_unregister_driver(&s6e63m0_driver);
+}
+
+module_init(s6e63m0_init);
+module_exit(s6e63m0_exit);
+
+MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("S6E63M0 LCD Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/backlight/s6e63m0_gamma.h b/drivers/video/backlight/s6e63m0_gamma.h
new file mode 100644
index 00000000000..2c44bdb0696
--- /dev/null
+++ b/drivers/video/backlight/s6e63m0_gamma.h
@@ -0,0 +1,266 @@
+/* linux/drivers/video/samsung/s6e63m0_brightness.h
+ *
+ * Gamma level definitions.
+ *
+ * Copyright (c) 2009 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.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.
+*/
+
+#ifndef _S6E63M0_BRIGHTNESS_H
+#define _S6E63M0_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL 11
+#define GAMMA_TABLE_COUNT 21
+
+/* gamma value: 2.2 */
+static const unsigned int s6e63m0_22_300[] = {
+ 0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
+ 0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
+ 0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb
+};
+
+static const unsigned int s6e63m0_22_280[] = {
+ 0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
+ 0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
+ 0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
+};
+
+static const unsigned int s6e63m0_22_260[] = {
+ 0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
+ 0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
+ 0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
+
+};
+
+static const unsigned int s6e63m0_22_240[] = {
+ 0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
+ 0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
+ 0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA
+
+};
+static const unsigned int s6e63m0_22_220[] = {
+ 0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
+ 0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
+ 0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
+};
+
+static const unsigned int s6e63m0_22_200[] = {
+ 0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
+ 0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
+ 0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
+};
+
+static const unsigned int s6e63m0_22_170[] = {
+ 0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
+ 0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
+ 0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
+};
+
+static const unsigned int s6e63m0_22_140[] = {
+ 0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
+ 0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
+ 0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
+};
+
+static const unsigned int s6e63m0_22_110[] = {
+ 0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
+ 0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
+ 0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_22_90[] = {
+ 0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
+ 0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
+ 0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
+};
+
+static const unsigned int s6e63m0_22_30[] = {
+ 0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
+ 0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
+ 0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
+};
+
+/* gamma value: 1.9 */
+static const unsigned int s6e63m0_19_300[] = {
+ 0x18, 0x08, 0x24, 0x61, 0x5F, 0x39, 0xBA,
+ 0xBD, 0xAD, 0xB1, 0xB6, 0xA5, 0xC4, 0xC5,
+ 0xBC, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
+};
+
+static const unsigned int s6e63m0_19_280[] = {
+ 0x18, 0x08, 0x24, 0x61, 0x60, 0x39, 0xBB,
+ 0xBE, 0xAD, 0xB2, 0xB6, 0xA6, 0xC5, 0xC7,
+ 0xBD, 0x00, 0x9B, 0x00, 0x9E, 0x00, 0xD5
+};
+
+static const unsigned int s6e63m0_19_260[] = {
+ 0x18, 0x08, 0x24, 0x63, 0x61, 0x3B, 0xBA,
+ 0xBE, 0xAC, 0xB3, 0xB8, 0xA7, 0xC6, 0xC8,
+ 0xBD, 0x00, 0x96, 0x00, 0x98, 0x00, 0xCF
+};
+
+static const unsigned int s6e63m0_19_240[] = {
+ 0x18, 0x08, 0x24, 0x67, 0x64, 0x3F, 0xBB,
+ 0xBE, 0xAD, 0xB3, 0xB9, 0xA7, 0xC8, 0xC9,
+ 0xBE, 0x00, 0x90, 0x00, 0x92, 0x00, 0xC8
+};
+
+static const unsigned int s6e63m0_19_220[] = {
+ 0x18, 0x08, 0x24, 0x68, 0x64, 0x40, 0xBC,
+ 0xBF, 0xAF, 0xB4, 0xBA, 0xA9, 0xC8, 0xCA,
+ 0xBE, 0x00, 0x8B, 0x00, 0x8C, 0x00, 0xC0
+};
+
+static const unsigned int s6e63m0_19_200[] = {
+ 0x18, 0x08, 0x24, 0x68, 0x64, 0x3F, 0xBE,
+ 0xC0, 0xB0, 0xB6, 0xBB, 0xAB, 0xC8, 0xCB,
+ 0xBF, 0x00, 0x85, 0x00, 0x86, 0x00, 0xB8
+};
+
+static const unsigned int s6e63m0_19_170[] = {
+ 0x18, 0x08, 0x24, 0x69, 0x64, 0x40, 0xBF,
+ 0xC1, 0xB0, 0xB9, 0xBE, 0xAD, 0xCB, 0xCD,
+ 0xC2, 0x00, 0x7A, 0x00, 0x7B, 0x00, 0xAA
+};
+
+static const unsigned int s6e63m0_19_140[] = {
+ 0x18, 0x08, 0x24, 0x6E, 0x65, 0x45, 0xC0,
+ 0xC3, 0xB2, 0xBA, 0xBE, 0xAE, 0xCD, 0xD0,
+ 0xC4, 0x00, 0x70, 0x00, 0x70, 0x00, 0x9C
+};
+
+static const unsigned int s6e63m0_19_110[] = {
+ 0x18, 0x08, 0x24, 0x6F, 0x65, 0x46, 0xC2,
+ 0xC4, 0xB3, 0xBF, 0xC2, 0xB2, 0xCF, 0xD1,
+ 0xC6, 0x00, 0x64, 0x00, 0x64, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_19_90[] = {
+ 0x18, 0x08, 0x24, 0x74, 0x60, 0x4A, 0xC3,
+ 0xC6, 0xB5, 0xBF, 0xC3, 0xB2, 0xD2, 0xD3,
+ 0xC8, 0x00, 0x5B, 0x00, 0x5B, 0x00, 0x81
+};
+
+static const unsigned int s6e63m0_19_30[] = {
+ 0x18, 0x08, 0x24, 0x84, 0x45, 0x4F, 0xCA,
+ 0xCB, 0xBC, 0xC9, 0xCB, 0xBC, 0xDA, 0xDA,
+ 0xD0, 0x00, 0x35, 0x00, 0x34, 0x00, 0x4E
+};
+
+/* gamma value: 1.7 */
+static const unsigned int s6e63m0_17_300[] = {
+ 0x18, 0x08, 0x24, 0x70, 0x70, 0x4F, 0xBF,
+ 0xC2, 0xB2, 0xB8, 0xBC, 0xAC, 0xCB, 0xCD,
+ 0xC3, 0x00, 0xA0, 0x00, 0xA4, 0x00, 0xDB
+};
+
+static const unsigned int s6e63m0_17_280[] = {
+ 0x18, 0x08, 0x24, 0x71, 0x71, 0x50, 0xBF,
+ 0xC2, 0xB2, 0xBA, 0xBE, 0xAE, 0xCB, 0xCD,
+ 0xC3, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6
+};
+
+static const unsigned int s6e63m0_17_260[] = {
+ 0x18, 0x08, 0x24, 0x72, 0x72, 0x50, 0xC0,
+ 0xC3, 0xB4, 0xB9, 0xBE, 0xAE, 0xCC, 0xCF,
+ 0xC4, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1
+};
+
+static const unsigned int s6e63m0_17_240[] = {
+ 0x18, 0x08, 0x24, 0x71, 0x72, 0x4F, 0xC2,
+ 0xC4, 0xB5, 0xBB, 0xBF, 0xB0, 0xCC, 0xCF,
+ 0xC3, 0x00, 0x91, 0x00, 0x95, 0x00, 0xCA
+};
+
+static const unsigned int s6e63m0_17_220[] = {
+ 0x18, 0x08, 0x24, 0x71, 0x73, 0x4F, 0xC2,
+ 0xC5, 0xB5, 0xBD, 0xC0, 0xB2, 0xCD, 0xD1,
+ 0xC5, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2
+};
+
+static const unsigned int s6e63m0_17_200[] = {
+ 0x18, 0x08, 0x24, 0x72, 0x75, 0x51, 0xC2,
+ 0xC6, 0xB5, 0xBF, 0xC1, 0xB3, 0xCE, 0xD1,
+ 0xC6, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA
+};
+
+static const unsigned int s6e63m0_17_170[] = {
+ 0x18, 0x08, 0x24, 0x75, 0x77, 0x54, 0xC3,
+ 0xC7, 0xB7, 0xC0, 0xC3, 0xB4, 0xD1, 0xD3,
+ 0xC9, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB
+};
+
+static const unsigned int s6e63m0_17_140[] = {
+ 0x18, 0x08, 0x24, 0x7B, 0x77, 0x58, 0xC3,
+ 0xC8, 0xB8, 0xC2, 0xC6, 0xB6, 0xD3, 0xD4,
+ 0xCA, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E
+};
+
+static const unsigned int s6e63m0_17_110[] = {
+ 0x18, 0x08, 0x24, 0x81, 0x7B, 0x5D, 0xC6,
+ 0xCA, 0xBB, 0xC3, 0xC7, 0xB8, 0xD6, 0xD8,
+ 0xCD, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D
+};
+
+static const unsigned int s6e63m0_17_90[] = {
+ 0x18, 0x08, 0x24, 0x82, 0x7A, 0x5B, 0xC8,
+ 0xCB, 0xBD, 0xC5, 0xCA, 0xBA, 0xD6, 0xD8,
+ 0xCE, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82
+};
+
+static const unsigned int s6e63m0_17_30[] = {
+ 0x18, 0x08, 0x24, 0x8F, 0x73, 0x63, 0xD1,
+ 0xD0, 0xC5, 0xCC, 0xD1, 0xC2, 0xDE, 0xE0,
+ 0xD6, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51
+};
+
+struct s6e63m0_gamma {
+ unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
+ unsigned int *gamma_19_table[MAX_GAMMA_LEVEL];
+ unsigned int *gamma_17_table[MAX_GAMMA_LEVEL];
+};
+
+static struct s6e63m0_gamma gamma_table = {
+ .gamma_22_table[0] = (unsigned int *)&s6e63m0_22_30,
+ .gamma_22_table[1] = (unsigned int *)&s6e63m0_22_90,
+ .gamma_22_table[2] = (unsigned int *)&s6e63m0_22_110,
+ .gamma_22_table[3] = (unsigned int *)&s6e63m0_22_140,
+ .gamma_22_table[4] = (unsigned int *)&s6e63m0_22_170,
+ .gamma_22_table[5] = (unsigned int *)&s6e63m0_22_200,
+ .gamma_22_table[6] = (unsigned int *)&s6e63m0_22_220,
+ .gamma_22_table[7] = (unsigned int *)&s6e63m0_22_240,
+ .gamma_22_table[8] = (unsigned int *)&s6e63m0_22_260,
+ .gamma_22_table[9] = (unsigned int *)&s6e63m0_22_280,
+ .gamma_22_table[10] = (unsigned int *)&s6e63m0_22_300,
+
+ .gamma_19_table[0] = (unsigned int *)&s6e63m0_19_30,
+ .gamma_19_table[1] = (unsigned int *)&s6e63m0_19_90,
+ .gamma_19_table[2] = (unsigned int *)&s6e63m0_19_110,
+ .gamma_19_table[3] = (unsigned int *)&s6e63m0_19_140,
+ .gamma_19_table[4] = (unsigned int *)&s6e63m0_19_170,
+ .gamma_19_table[5] = (unsigned int *)&s6e63m0_19_200,
+ .gamma_19_table[6] = (unsigned int *)&s6e63m0_19_220,
+ .gamma_19_table[7] = (unsigned int *)&s6e63m0_19_240,
+ .gamma_19_table[8] = (unsigned int *)&s6e63m0_19_260,
+ .gamma_19_table[9] = (unsigned int *)&s6e63m0_19_280,
+ .gamma_19_table[10] = (unsigned int *)&s6e63m0_19_300,
+
+ .gamma_17_table[0] = (unsigned int *)&s6e63m0_17_30,
+ .gamma_17_table[1] = (unsigned int *)&s6e63m0_17_90,
+ .gamma_17_table[2] = (unsigned int *)&s6e63m0_17_110,
+ .gamma_17_table[3] = (unsigned int *)&s6e63m0_17_140,
+ .gamma_17_table[4] = (unsigned int *)&s6e63m0_17_170,
+ .gamma_17_table[5] = (unsigned int *)&s6e63m0_17_200,
+ .gamma_17_table[6] = (unsigned int *)&s6e63m0_17_220,
+ .gamma_17_table[7] = (unsigned int *)&s6e63m0_17_240,
+ .gamma_17_table[8] = (unsigned int *)&s6e63m0_17_260,
+ .gamma_17_table[9] = (unsigned int *)&s6e63m0_17_280,
+ .gamma_17_table[10] = (unsigned int *)&s6e63m0_17_300,
+};
+
+#endif
+
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index e03e60bbfd8..2a04b382ec4 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -119,7 +119,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
err_reg:
data->bl = NULL;
- i2c_set_clientdata(client, NULL);
err_gpio_dir:
gpio_free(TOSA_GPIO_BL_C20MA);
err_gpio_bl:
@@ -133,7 +132,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client)
backlight_device_unregister(data->bl);
data->bl = NULL;
- i2c_set_clientdata(client, NULL);
gpio_free(TOSA_GPIO_BL_C20MA);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 23b2a8c0dbf..b020ba7f1cf 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -501,7 +501,9 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
{
+#ifndef NO_BL_SUPPORT
struct backlight_properties props;
+#endif
struct bfin_bf54xfb_info *info;
struct fb_info *fbinfo;
int ret;
@@ -654,7 +656,8 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
printk(KERN_ERR DRIVER_NAME
": unable to register backlight.\n");
ret = -EINVAL;
- goto out9;
+ unregister_framebuffer(fbinfo);
+ goto out8;
}
lcd_dev = lcd_device_register(DRIVER_NAME, &pdev->dev, NULL, &bfin_lcd_ops);
@@ -663,8 +666,6 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
return 0;
-out9:
- unregister_framebuffer(fbinfo);
out8:
free_irq(info->irq, info);
out7:
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
index 2baac7cc142..c8e1f04941b 100644
--- a/drivers/video/bfin-lq035q1-fb.c
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -61,47 +61,13 @@
#define LCD_X_RES 320 /* Horizontal Resolution */
#define LCD_Y_RES 240 /* Vertical Resolution */
#define DMA_BUS_SIZE 16
+#define U_LINE 4 /* Blanking Lines */
-#define USE_RGB565_16_BIT_PPI
-
-#ifdef USE_RGB565_16_BIT_PPI
-#define LCD_BPP 16 /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 1
-#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */
-#endif
/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
* http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
*/
-#ifdef USE_RGB565_8_BIT_PPI
-#define LCD_BPP 16 /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 2
-#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */
-#endif
-
-#ifdef USE_RGB888_8_BIT_PPI
-#define LCD_BPP 24 /* Bit Per Pixel */
-#define CLOCKS_PER_PIX 3
-#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */
-#endif
-
- /*
- * HS and VS timing parameters (all in number of PPI clk ticks)
- */
-
-#define U_LINE 4 /* Blanking Lines */
-
-#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */
-#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */
-#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */
-#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */
-
-#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */
-#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */
-#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */
-
-#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
#define BFIN_LCD_NBR_PALETTE_ENTRIES 256
@@ -110,12 +76,6 @@
#define PPI_PORT_CFG_01 0x10
#define PPI_POLS_1 0x8000
-#if (CLOCKS_PER_PIX > 1)
-#define PPI_PMODE (DLEN_8 | PACK_EN)
-#else
-#define PPI_PMODE (DLEN_16)
-#endif
-
#define LQ035_INDEX 0x74
#define LQ035_DATA 0x76
@@ -139,6 +99,15 @@ struct bfin_lq035q1fb_info {
int irq;
spinlock_t lock; /* lock */
u32 pseudo_pal[16];
+
+ u32 lcd_bpp;
+ u32 h_actpix;
+ u32 h_period;
+ u32 h_pulse;
+ u32 h_start;
+ u32 v_lines;
+ u32 v_pulse;
+ u32 v_period;
};
static int nocursor;
@@ -234,16 +203,69 @@ static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
return 0;
}
+static int bfin_lq035q1_calc_timing(struct bfin_lq035q1fb_info *fbi)
+{
+ unsigned long clocks_per_pix, cpld_pipeline_delay_cor;
+
+ /*
+ * Interface 16/18-bit TFT over an 8-bit wide PPI using a small
+ * Programmable Logic Device (CPLD)
+ * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
+ */
+
+ switch (fbi->disp_info->ppi_mode) {
+ case USE_RGB565_16_BIT_PPI:
+ fbi->lcd_bpp = 16;
+ clocks_per_pix = 1;
+ cpld_pipeline_delay_cor = 0;
+ break;
+ case USE_RGB565_8_BIT_PPI:
+ fbi->lcd_bpp = 16;
+ clocks_per_pix = 2;
+ cpld_pipeline_delay_cor = 3;
+ break;
+ case USE_RGB888_8_BIT_PPI:
+ fbi->lcd_bpp = 24;
+ clocks_per_pix = 3;
+ cpld_pipeline_delay_cor = 5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * HS and VS timing parameters (all in number of PPI clk ticks)
+ */
+
+ fbi->h_actpix = (LCD_X_RES * clocks_per_pix); /* active horizontal pixel */
+ fbi->h_period = (336 * clocks_per_pix); /* HS period */
+ fbi->h_pulse = (2 * clocks_per_pix); /* HS pulse width */
+ fbi->h_start = (7 * clocks_per_pix + cpld_pipeline_delay_cor); /* first valid pixel */
+
+ fbi->v_lines = (LCD_Y_RES + U_LINE); /* total vertical lines */
+ fbi->v_pulse = (2 * clocks_per_pix); /* VS pulse width (1-5 H_PERIODs) */
+ fbi->v_period = (fbi->h_period * fbi->v_lines); /* VS period */
+
+ return 0;
+}
+
static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
{
- bfin_write_PPI_DELAY(H_START);
- bfin_write_PPI_COUNT(H_ACTPIX - 1);
- bfin_write_PPI_FRAME(V_LINES);
+ unsigned ppi_pmode;
+
+ if (fbi->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI)
+ ppi_pmode = DLEN_16;
+ else
+ ppi_pmode = (DLEN_8 | PACK_EN);
+
+ bfin_write_PPI_DELAY(fbi->h_start);
+ bfin_write_PPI_COUNT(fbi->h_actpix - 1);
+ bfin_write_PPI_FRAME(fbi->v_lines);
bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */
PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */
- PPI_PMODE | /* 8/16 bit data length / PACK_EN? */
+ ppi_pmode | /* 8/16 bit data length / PACK_EN? */
PPI_POLS_1); /* faling edge syncs POLS */
}
@@ -272,19 +294,19 @@ static void bfin_lq035q1_stop_timers(void)
}
-static void bfin_lq035q1_init_timers(void)
+static void bfin_lq035q1_init_timers(struct bfin_lq035q1fb_info *fbi)
{
bfin_lq035q1_stop_timers();
- set_gptimer_period(TIMER_HSYNC_id, H_PERIOD);
- set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE);
+ set_gptimer_period(TIMER_HSYNC_id, fbi->h_period);
+ set_gptimer_pwidth(TIMER_HSYNC_id, fbi->h_pulse);
set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
TIMER_TIN_SEL | TIMER_CLK_SEL|
TIMER_EMU_RUN);
- set_gptimer_period(TIMER_VSYNC_id, V_PERIOD);
- set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE);
+ set_gptimer_period(TIMER_VSYNC_id, fbi->v_period);
+ set_gptimer_pwidth(TIMER_VSYNC_id, fbi->v_pulse);
set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
TIMER_TIN_SEL | TIMER_CLK_SEL |
TIMER_EMU_RUN);
@@ -294,21 +316,21 @@ static void bfin_lq035q1_init_timers(void)
static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
{
+
set_dma_config(CH_PPI,
set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
INTR_DISABLE, DIMENSION_2D,
DATA_SIZE_16,
DMA_NOSYNC_KEEP_DMA_BUF));
- set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
+ set_dma_x_count(CH_PPI, (LCD_X_RES * fbi->lcd_bpp) / DMA_BUS_SIZE);
set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
- set_dma_y_count(CH_PPI, V_LINES);
+ set_dma_y_count(CH_PPI, fbi->v_lines);
set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
}
-#if (CLOCKS_PER_PIX == 1)
static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
@@ -316,22 +338,27 @@ static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
P_PPI0_D15, 0};
-#else
-static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+
+static const u16 ppi0_req_8[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
P_PPI0_D6, P_PPI0_D7, 0};
-#endif
-static inline void bfin_lq035q1_free_ports(void)
+static inline void bfin_lq035q1_free_ports(unsigned ppi16)
{
- peripheral_free_list(ppi0_req_16);
+ if (ppi16)
+ peripheral_free_list(ppi0_req_16);
+ else
+ peripheral_free_list(ppi0_req_8);
+
if (ANOMALY_05000400)
gpio_free(P_IDENT(P_PPI0_FS3));
}
-static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
+static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev,
+ unsigned ppi16)
{
+ int ret;
/* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
* Drive PPI_FS3 Low
*/
@@ -342,7 +369,12 @@ static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
}
- if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) {
+ if (ppi16)
+ ret = peripheral_request_list(ppi0_req_16, DRIVER_NAME);
+ else
+ ret = peripheral_request_list(ppi0_req_8, DRIVER_NAME);
+
+ if (ret) {
dev_err(&pdev->dev, "requesting peripherals failed\n");
return -EFAULT;
}
@@ -364,7 +396,7 @@ static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
bfin_lq035q1_config_dma(fbi);
bfin_lq035q1_config_ppi(fbi);
- bfin_lq035q1_init_timers();
+ bfin_lq035q1_init_timers(fbi);
/* start dma */
enable_dma(CH_PPI);
@@ -402,12 +434,9 @@ static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- switch (var->bits_per_pixel) {
-#if (LCD_BPP == 24)
- case 24:/* TRUECOLOUR, 16m */
-#else
- case 16:/* DIRECTCOLOUR, 64k */
-#endif
+ struct bfin_lq035q1fb_info *fbi = info->par;
+
+ if (var->bits_per_pixel == fbi->lcd_bpp) {
var->red.offset = info->var.red.offset;
var->green.offset = info->var.green.offset;
var->blue.offset = info->var.blue.offset;
@@ -420,8 +449,7 @@ static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
- break;
- default:
+ } else {
pr_debug("%s: depth not supported: %u BPP\n", __func__,
var->bits_per_pixel);
return -EINVAL;
@@ -528,6 +556,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
{
struct bfin_lq035q1fb_info *info;
struct fb_info *fbinfo;
+ u32 active_video_mem_offset;
int ret;
ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
@@ -550,6 +579,12 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fbinfo);
+ ret = bfin_lq035q1_calc_timing(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed PPI Mode\n");
+ goto out3;
+ }
+
strcpy(fbinfo->fix.id, DRIVER_NAME);
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -571,46 +606,48 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
fbinfo->var.xres_virtual = LCD_X_RES;
fbinfo->var.yres = LCD_Y_RES;
fbinfo->var.yres_virtual = LCD_Y_RES;
- fbinfo->var.bits_per_pixel = LCD_BPP;
+ fbinfo->var.bits_per_pixel = info->lcd_bpp;
if (info->disp_info->mode & LQ035_BGR) {
-#if (LCD_BPP == 24)
- fbinfo->var.red.offset = 0;
- fbinfo->var.green.offset = 8;
- fbinfo->var.blue.offset = 16;
-#else
- fbinfo->var.red.offset = 0;
- fbinfo->var.green.offset = 5;
- fbinfo->var.blue.offset = 11;
-#endif
+ if (info->lcd_bpp == 24) {
+ fbinfo->var.red.offset = 0;
+ fbinfo->var.green.offset = 8;
+ fbinfo->var.blue.offset = 16;
+ } else {
+ fbinfo->var.red.offset = 0;
+ fbinfo->var.green.offset = 5;
+ fbinfo->var.blue.offset = 11;
+ }
} else {
-#if (LCD_BPP == 24)
- fbinfo->var.red.offset = 16;
- fbinfo->var.green.offset = 8;
- fbinfo->var.blue.offset = 0;
-#else
- fbinfo->var.red.offset = 11;
- fbinfo->var.green.offset = 5;
- fbinfo->var.blue.offset = 0;
-#endif
+ if (info->lcd_bpp == 24) {
+ fbinfo->var.red.offset = 16;
+ fbinfo->var.green.offset = 8;
+ fbinfo->var.blue.offset = 0;
+ } else {
+ fbinfo->var.red.offset = 11;
+ fbinfo->var.green.offset = 5;
+ fbinfo->var.blue.offset = 0;
+ }
}
fbinfo->var.transp.offset = 0;
-#if (LCD_BPP == 24)
- fbinfo->var.red.length = 8;
- fbinfo->var.green.length = 8;
- fbinfo->var.blue.length = 8;
-#else
- fbinfo->var.red.length = 5;
- fbinfo->var.green.length = 6;
- fbinfo->var.blue.length = 5;
-#endif
+ if (info->lcd_bpp == 24) {
+ fbinfo->var.red.length = 8;
+ fbinfo->var.green.length = 8;
+ fbinfo->var.blue.length = 8;
+ } else {
+ fbinfo->var.red.length = 5;
+ fbinfo->var.green.length = 6;
+ fbinfo->var.blue.length = 5;
+ }
fbinfo->var.transp.length = 0;
- fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8
- + ACTIVE_VIDEO_MEM_OFFSET;
+ active_video_mem_offset = ((U_LINE / 2) * LCD_X_RES * (info->lcd_bpp / 8));
+
+ fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * info->lcd_bpp / 8
+ + active_video_mem_offset;
fbinfo->fix.line_length = fbinfo->var.xres_virtual *
fbinfo->var.bits_per_pixel / 8;
@@ -629,8 +666,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
goto out3;
}
- fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
- fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
+ fbinfo->screen_base = (void *)info->fb_buffer + active_video_mem_offset;
+ fbinfo->fix.smem_start = (int)info->fb_buffer + active_video_mem_offset;
fbinfo->fbops = &bfin_lq035q1_fb_ops;
@@ -643,7 +680,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
goto out4;
}
- ret = bfin_lq035q1_request_ports(pdev);
+ ret = bfin_lq035q1_request_ports(pdev,
+ info->disp_info->ppi_mode == USE_RGB565_16_BIT_PPI);
if (ret) {
dev_err(&pdev->dev, "couldn't request gpio port\n");
goto out6;
@@ -693,7 +731,7 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
- LCD_X_RES, LCD_Y_RES, LCD_BPP);
+ LCD_X_RES, LCD_Y_RES, info->lcd_bpp);
return 0;
@@ -705,7 +743,8 @@ static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
out8:
free_irq(info->irq, info);
out7:
- bfin_lq035q1_free_ports();
+ bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+ USE_RGB565_16_BIT_PPI);
out6:
fb_dealloc_cmap(&fbinfo->cmap);
out4:
@@ -742,7 +781,8 @@ static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
fb_dealloc_cmap(&fbinfo->cmap);
- bfin_lq035q1_free_ports();
+ bfin_lq035q1_free_ports(info->disp_info->ppi_mode ==
+ USE_RGB565_16_BIT_PPI);
platform_set_drvdata(pdev, NULL);
framebuffer_release(fbinfo);
@@ -781,7 +821,7 @@ static int bfin_lq035q1_resume(struct device *dev)
bfin_lq035q1_config_dma(info);
bfin_lq035q1_config_ppi(info);
- bfin_lq035q1_init_timers();
+ bfin_lq035q1_init_timers(info);
/* start dma */
enable_dma(CH_PPI);
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 44e49c28b2a..7a50272eaab 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -420,7 +420,9 @@ static irqreturn_t bfin_t350mcqb_irq_error(int irq, void *dev_id)
static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
{
+#ifndef NO_BL_SUPPORT
struct backlight_properties props;
+#endif
struct bfin_t350mcqbfb_info *info;
struct fb_info *fbinfo;
int ret;
@@ -488,9 +490,9 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
fbinfo->fbops = &bfin_t350mcqb_fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
- info->fb_buffer =
- dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
- GFP_KERNEL);
+ info->fb_buffer = dma_alloc_coherent(NULL, fbinfo->fix.smem_len +
+ ACTIVE_VIDEO_MEM_OFFSET,
+ &info->dma_handle, GFP_KERNEL);
if (NULL == info->fb_buffer) {
printk(KERN_ERR DRIVER_NAME
@@ -550,7 +552,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
printk(KERN_ERR DRIVER_NAME
": unable to register backlight.\n");
ret = -EINVAL;
- goto out9;
+ unregister_framebuffer(fbinfo);
+ goto out8;
}
lcd_dev = lcd_device_register(DRIVER_NAME, NULL, &bfin_lcd_ops);
@@ -559,8 +562,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
return 0;
-out9:
- unregister_framebuffer(fbinfo);
out8:
free_irq(info->irq, info);
out7:
@@ -568,8 +569,8 @@ out7:
out6:
fb_dealloc_cmap(&fbinfo->cmap);
out4:
- dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
- info->dma_handle);
+ dma_free_coherent(NULL, fbinfo->fix.smem_len + ACTIVE_VIDEO_MEM_OFFSET,
+ info->fb_buffer, info->dma_handle);
out3:
framebuffer_release(fbinfo);
out2:
@@ -592,8 +593,9 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
free_irq(info->irq, info);
if (info->fb_buffer != NULL)
- dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
- info->dma_handle);
+ dma_free_coherent(NULL, fbinfo->fix.smem_len +
+ ACTIVE_VIDEO_MEM_OFFSET, info->fb_buffer,
+ info->dma_handle);
fb_dealloc_cmap(&fbinfo->cmap);
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 43320925c4c..09f1b9b462f 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -275,7 +275,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par,
static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct bw2_par *par;
int linebytes, err;
@@ -376,8 +376,11 @@ static const struct of_device_id bw2_match[] = {
MODULE_DEVICE_TABLE(of, bw2_match);
static struct of_platform_driver bw2_driver = {
- .name = "bw2",
- .match_table = bw2_match,
+ .driver = {
+ .name = "bw2",
+ .owner = THIS_MODULE,
+ .of_match_table = bw2_match,
+ },
.probe = bw2_probe,
.remove = __devexit_p(bw2_remove),
};
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index 77a040af20a..e5dc2241194 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -465,7 +465,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct cg14_par *par;
int is_8mb, linebytes, i, err;
@@ -596,8 +596,11 @@ static const struct of_device_id cg14_match[] = {
MODULE_DEVICE_TABLE(of, cg14_match);
static struct of_platform_driver cg14_driver = {
- .name = "cg14",
- .match_table = cg14_match,
+ .driver = {
+ .name = "cg14",
+ .owner = THIS_MODULE,
+ .of_match_table = cg14_match,
+ },
.probe = cg14_probe,
.remove = __devexit_p(cg14_remove),
};
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 30eedf79322..558d73a948a 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -349,7 +349,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par)
static int __devinit cg3_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct cg3_par *par;
int linebytes, err;
@@ -463,8 +463,11 @@ static const struct of_device_id cg3_match[] = {
MODULE_DEVICE_TABLE(of, cg3_match);
static struct of_platform_driver cg3_driver = {
- .name = "cg3",
- .match_table = cg3_match,
+ .driver = {
+ .name = "cg3",
+ .owner = THIS_MODULE,
+ .of_match_table = cg3_match,
+ },
.probe = cg3_probe,
.remove = __devexit_p(cg3_remove),
};
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 6d0fcb43696..480d761a27a 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -740,7 +740,7 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit cg6_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct cg6_par *par;
int linebytes, err;
@@ -856,8 +856,11 @@ static const struct of_device_id cg6_match[] = {
MODULE_DEVICE_TABLE(of, cg6_match);
static struct of_platform_driver cg6_driver = {
- .name = "cg6",
- .match_table = cg6_match,
+ .driver = {
+ .name = "cg6",
+ .owner = THIS_MODULE,
+ .of_match_table = cg6_match,
+ },
.probe = cg6_probe,
.remove = __devexit_p(cg6_remove),
};
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 8d8dfda2f86..6df7c54db0a 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -299,6 +299,7 @@ static const struct zorro_device_id cirrusfb_zorro_table[] = {
},
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
static const struct {
zorro_id id2;
diff --git a/drivers/video/cobalt_lcdfb.c b/drivers/video/cobalt_lcdfb.c
index 5eb61b5adfe..42fe155aba0 100644
--- a/drivers/video/cobalt_lcdfb.c
+++ b/drivers/video/cobalt_lcdfb.c
@@ -123,7 +123,7 @@ static void lcd_clear(struct fb_info *info)
lcd_write_control(info, LCD_RESET);
}
-static struct fb_fix_screeninfo cobalt_lcdfb_fix __initdata = {
+static struct fb_fix_screeninfo cobalt_lcdfb_fix __devinitdata = {
.id = "cobalt-lcd",
.type = FB_TYPE_TEXT,
.type_aux = FB_AUX_TEXT_MDA,
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 3a561df2e8a..0c1afd13ddd 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -388,6 +388,7 @@ cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
pseudo_val |= convert_bitfield(red, &var->red);
pseudo_val |= convert_bitfield(green, &var->green);
pseudo_val |= convert_bitfield(blue, &var->blue);
+ ret = 0;
break;
}
@@ -436,6 +437,8 @@ static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
cyber2000fb_writeb(i | 4, 0x3cf, cfb);
cyber2000fb_writeb(val, 0x3c6, cfb);
cyber2000fb_writeb(i, 0x3cf, cfb);
+ /* prevent card lock-up observed on x86 with CyberPro 2000 */
+ cyber2000fb_readb(0x3cf, cfb);
}
static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 8d244ba0f60..cad7d45c8ba 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -36,7 +36,9 @@
#define DRIVER_NAME "da8xx_lcdc"
/* LCD Status Register */
+#define LCD_END_OF_FRAME1 BIT(9)
#define LCD_END_OF_FRAME0 BIT(8)
+#define LCD_PL_LOAD_DONE BIT(6)
#define LCD_FIFO_UNDERFLOW BIT(5)
#define LCD_SYNC_LOST BIT(2)
@@ -58,11 +60,13 @@
#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20)
#define PALETTE_AND_DATA 0x00
#define PALETTE_ONLY 0x01
+#define DATA_ONLY 0x02
#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_MONOCHROME_MODE BIT(1)
#define LCD_RASTER_ENABLE BIT(0)
#define LCD_TFT_ALT_ENABLE BIT(23)
@@ -87,6 +91,10 @@
#define LCD_DMA_CTRL_REG 0x40
#define LCD_DMA_FRM_BUF_BASE_ADDR_0_REG 0x44
#define LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG 0x48
+#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C
+#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50
+
+#define LCD_NUM_BUFFERS 2
#define WSI_TIMEOUT 50
#define PALETTE_SIZE 256
@@ -111,13 +119,20 @@ static inline void lcdc_write(unsigned int val, unsigned int addr)
struct da8xx_fb_par {
resource_size_t p_palette_base;
unsigned char *v_palette_base;
+ dma_addr_t vram_phys;
+ unsigned long vram_size;
+ void *vram_virt;
+ unsigned int dma_start;
+ unsigned int dma_end;
struct clk *lcdc_clk;
int irq;
unsigned short pseudo_palette[16];
- unsigned int databuf_sz;
unsigned int palette_sz;
unsigned int pxl_clk;
int blank;
+ wait_queue_head_t vsync_wait;
+ int vsync_flag;
+ int vsync_timeout;
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
@@ -148,9 +163,9 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = {
.type = FB_TYPE_PACKED_PIXELS,
.type_aux = 0,
.visual = FB_VISUAL_PSEUDOCOLOR,
- .xpanstep = 1,
+ .xpanstep = 0,
.ypanstep = 1,
- .ywrapstep = 1,
+ .ywrapstep = 0,
.accel = FB_ACCEL_NONE
};
@@ -221,22 +236,48 @@ static inline void lcd_disable_raster(void)
static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
{
- u32 tmp = par->p_palette_base + par->databuf_sz - 4;
- u32 reg;
+ u32 start;
+ u32 end;
+ u32 reg_ras;
+ u32 reg_dma;
+
+ /* init reg to clear PLM (loading mode) fields */
+ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
+ reg_ras &= ~(3 << 20);
+
+ reg_dma = lcdc_read(LCD_DMA_CTRL_REG);
+
+ if (load_mode == LOAD_DATA) {
+ start = par->dma_start;
+ end = par->dma_end;
+
+ reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
+ reg_dma |= LCD_END_OF_FRAME_INT_ENA;
+ reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
+
+ lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ } else if (load_mode == LOAD_PALETTE) {
+ start = par->p_palette_base;
+ end = start + par->palette_sz - 1;
+
+ reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
+ reg_ras |= LCD_PL_ENABLE;
+
+ lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ }
- /* Update the databuf in the hw. */
- lcdc_write(par->p_palette_base, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
- lcdc_write(tmp, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ lcdc_write(reg_dma, LCD_DMA_CTRL_REG);
+ lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
- /* Start the DMA. */
- reg = lcdc_read(LCD_RASTER_CTRL_REG);
- reg &= ~(3 << 20);
- if (load_mode == LOAD_DATA)
- reg |= LCD_PALETTE_LOAD_MODE(PALETTE_AND_DATA);
- else if (load_mode == LOAD_PALETTE)
- reg |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
-
- lcdc_write(reg, LCD_RASTER_CTRL_REG);
+ /*
+ * The Raster enable bit must be set after all other control fields are
+ * set.
+ */
+ lcd_enable_raster();
}
/* Configure the Burst Size of DMA */
@@ -368,12 +409,8 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
u32 bpp, u32 raster_order)
{
- u32 bpl, reg;
+ u32 reg;
- /* Disable Dual Frame Buffer. */
- reg = lcdc_read(LCD_DMA_CTRL_REG);
- lcdc_write(reg & ~LCD_DUAL_FRAME_BUFFER_ENABLE,
- LCD_DMA_CTRL_REG);
/* Set the Panel Width */
/* Pixels per line = (PPL + 1)*16 */
/*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
@@ -410,9 +447,6 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
return -EINVAL;
}
- bpl = width * bpp / 8;
- par->databuf_sz = height * bpl + par->palette_sz;
-
return 0;
}
@@ -421,8 +455,9 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct fb_info *info)
{
struct da8xx_fb_par *par = info->par;
- unsigned short *palette = (unsigned short *)par->v_palette_base;
+ unsigned short *palette = (unsigned short *) par->v_palette_base;
u_short pal;
+ int update_hw = 0;
if (regno > 255)
return 1;
@@ -439,8 +474,10 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
pal |= (green & 0x00f0);
pal |= (blue & 0x000f);
- palette[regno] = pal;
-
+ if (palette[regno] != pal) {
+ update_hw = 1;
+ palette[regno] = pal;
+ }
} else if ((info->var.bits_per_pixel == 16) && regno < 16) {
red >>= (16 - info->var.red.length);
red <<= info->var.red.offset;
@@ -453,9 +490,16 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
par->pseudo_palette[regno] = red | green | blue;
- palette[0] = 0x4000;
+ if (palette[0] != 0x4000) {
+ update_hw = 1;
+ palette[0] = 0x4000;
+ }
}
+ /* Update the palette in the h/w as needed. */
+ if (update_hw)
+ lcd_blit(LOAD_PALETTE, par);
+
return 0;
}
@@ -541,15 +585,54 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
static irqreturn_t lcdc_irq_handler(int irq, void *arg)
{
+ struct da8xx_fb_par *par = arg;
u32 stat = lcdc_read(LCD_STAT_REG);
+ u32 reg_ras;
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
lcd_disable_raster();
lcdc_write(stat, LCD_STAT_REG);
lcd_enable_raster();
- } else
+ } 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_STAT_REG);
+ /* Disable PL completion inerrupt */
+ reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
+ reg_ras &= ~LCD_PL_ENABLE;
+ lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
+
+ /* Setup and start data loading mode */
+ lcd_blit(LOAD_DATA, par);
+ } else {
+ lcdc_write(stat, LCD_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);
+ }
+ }
+
return IRQ_HANDLED;
}
@@ -654,9 +737,10 @@ static int __devexit fb_remove(struct platform_device *dev)
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
- dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
- info->screen_base - PAGE_SIZE,
- info->fix.smem_start);
+ dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+ par->p_palette_base);
+ dma_free_coherent(NULL, par->vram_size, par->vram_virt,
+ par->vram_phys);
free_irq(par->irq, par);
clk_disable(par->lcdc_clk);
clk_put(par->lcdc_clk);
@@ -668,6 +752,39 @@ static int __devexit fb_remove(struct platform_device *dev)
return 0;
}
+/*
+ * Function to wait for vertical sync which for this LCD peripheral
+ * translates into waiting for the current raster frame to complete.
+ */
+static int fb_wait_for_vsync(struct fb_info *info)
+{
+ struct da8xx_fb_par *par = info->par;
+ int ret;
+
+ /*
+ * Set flag to 0 and wait for isr to set to 1. It would seem there is a
+ * race condition here where the ISR could have occured just before or
+ * just after this set. But since we are just coarsely waiting for
+ * a frame to complete then that's OK. i.e. if the frame completed
+ * just before this code executed then we have to wait another full
+ * frame time but there is no way to avoid such a situation. On the
+ * other hand if the frame completed just after then we don't need
+ * to wait long at all. Either way we are guaranteed to return to the
+ * user immediately after a frame completion which is all that is
+ * required.
+ */
+ par->vsync_flag = 0;
+ ret = wait_event_interruptible_timeout(par->vsync_wait,
+ par->vsync_flag != 0,
+ par->vsync_timeout);
+ if (ret < 0)
+ return ret;
+ if (ret == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
static int fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -697,6 +814,8 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
sync_arg.pulse_width,
sync_arg.front_porch);
break;
+ case FBIO_WAITFORVSYNC:
+ return fb_wait_for_vsync(info);
default:
return -EINVAL;
}
@@ -732,10 +851,47 @@ static int cfb_blank(int blank, struct fb_info *info)
return ret;
}
+/*
+ * Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int da8xx_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ int ret = 0;
+ struct fb_var_screeninfo new_var;
+ struct da8xx_fb_par *par = fbi->par;
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+ unsigned int end;
+ unsigned int start;
+
+ if (var->xoffset != fbi->var.xoffset ||
+ var->yoffset != fbi->var.yoffset) {
+ memcpy(&new_var, &fbi->var, sizeof(new_var));
+ new_var.xoffset = var->xoffset;
+ new_var.yoffset = var->yoffset;
+ if (fb_check_var(&new_var, fbi))
+ ret = -EINVAL;
+ else {
+ memcpy(&fbi->var, &new_var, sizeof(new_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;
+ par->dma_start = start;
+ par->dma_end = end;
+ }
+ }
+
+ return ret;
+}
+
static struct fb_ops da8xx_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = fb_check_var,
.fb_setcolreg = fb_setcolreg,
+ .fb_pan_display = da8xx_pan_display,
.fb_ioctl = fb_ioctl,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
@@ -829,40 +985,53 @@ static int __init fb_probe(struct platform_device *device)
}
/* allocate frame buffer */
- da8xx_fb_info->screen_base = dma_alloc_coherent(NULL,
- par->databuf_sz + PAGE_SIZE,
- (resource_size_t *)
- &da8xx_fb_info->fix.smem_start,
- GFP_KERNEL | GFP_DMA);
-
- if (!da8xx_fb_info->screen_base) {
+ par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp;
+ par->vram_size = PAGE_ALIGN(par->vram_size/8);
+ par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
+
+ par->vram_virt = dma_alloc_coherent(NULL,
+ par->vram_size,
+ (resource_size_t *) &par->vram_phys,
+ GFP_KERNEL | GFP_DMA);
+ if (!par->vram_virt) {
dev_err(&device->dev,
"GLCD: kmalloc for frame buffer failed\n");
ret = -EINVAL;
goto err_release_fb;
}
- /* move palette base pointer by (PAGE_SIZE - palette_sz) bytes */
- par->v_palette_base = da8xx_fb_info->screen_base +
- (PAGE_SIZE - par->palette_sz);
- par->p_palette_base = da8xx_fb_info->fix.smem_start +
- (PAGE_SIZE - par->palette_sz);
-
- /* the rest of the frame buffer is pixel data */
- da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;
- da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
- da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
- da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
+ da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
+ da8xx_fb_fix.smem_start = par->vram_phys;
+ da8xx_fb_fix.smem_len = par->vram_size;
+ da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
+
+ par->dma_start = par->vram_phys;
+ par->dma_end = par->dma_start + lcdc_info->height *
+ da8xx_fb_fix.line_length - 1;
+
+ /* allocate palette buffer */
+ par->v_palette_base = dma_alloc_coherent(NULL,
+ PALETTE_SIZE,
+ (resource_size_t *)
+ &par->p_palette_base,
+ GFP_KERNEL | GFP_DMA);
+ if (!par->v_palette_base) {
+ dev_err(&device->dev,
+ "GLCD: kmalloc for palette buffer failed\n");
+ ret = -EINVAL;
+ goto err_release_fb_mem;
+ }
+ memset(par->v_palette_base, 0, PALETTE_SIZE);
par->irq = platform_get_irq(device, 0);
if (par->irq < 0) {
ret = -ENOENT;
- goto err_release_fb_mem;
+ goto err_release_pl_mem;
}
ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par);
if (ret)
- goto err_release_fb_mem;
+ goto err_release_pl_mem;
/* Initialize par */
da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp;
@@ -870,8 +1039,8 @@ static int __init fb_probe(struct platform_device *device)
da8xx_fb_var.xres = lcdc_info->width;
da8xx_fb_var.xres_virtual = lcdc_info->width;
- da8xx_fb_var.yres = lcdc_info->height;
- da8xx_fb_var.yres_virtual = lcdc_info->height;
+ da8xx_fb_var.yres = lcdc_info->height;
+ da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS;
da8xx_fb_var.grayscale =
lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
@@ -892,18 +1061,18 @@ static int __init fb_probe(struct platform_device *device)
ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
if (ret)
goto err_free_irq;
-
- /* First palette_sz byte of the frame buffer is the palette */
da8xx_fb_info->cmap.len = par->palette_sz;
- /* Flush the buffer to the screen. */
- lcd_blit(LOAD_DATA, par);
-
/* initialize var_screeninfo */
da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
fb_set_var(da8xx_fb_info, &da8xx_fb_var);
dev_set_drvdata(&device->dev, da8xx_fb_info);
+
+ /* initialize the vsync wait queue */
+ init_waitqueue_head(&par->vsync_wait);
+ par->vsync_timeout = HZ / 5;
+
/* Register the Frame Buffer */
if (register_framebuffer(da8xx_fb_info) < 0) {
dev_err(&device->dev,
@@ -919,10 +1088,6 @@ static int __init fb_probe(struct platform_device *device)
goto err_cpu_freq;
}
#endif
-
- /* enable raster engine */
- lcd_enable_raster();
-
return 0;
#ifdef CONFIG_CPU_FREQ
@@ -936,10 +1101,12 @@ err_dealloc_cmap:
err_free_irq:
free_irq(par->irq, par);
+err_release_pl_mem:
+ dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
+ par->p_palette_base);
+
err_release_fb_mem:
- dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
- da8xx_fb_info->screen_base - PAGE_SIZE,
- da8xx_fb_info->fix.smem_start);
+ dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys);
err_release_fb:
framebuffer_release(da8xx_fb_info);
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index ecf405562f5..4a56f46af40 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -168,7 +168,7 @@ static void efifb_destroy(struct fb_info *info)
{
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(info->aperture_base, info->aperture_size);
+ release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
framebuffer_release(info);
}
@@ -292,8 +292,13 @@ static int __devinit efifb_probe(struct platform_device *dev)
info->pseudo_palette = info->par;
info->par = NULL;
- info->aperture_base = efifb_fix.smem_start;
- info->aperture_size = size_remap;
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ err = -ENOMEM;
+ goto err_release_fb;
+ }
+ info->apertures->ranges[0].base = efifb_fix.smem_start;
+ info->apertures->ranges[0].size = size_remap;
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
if (!info->screen_base) {
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 6113c47e095..6b93ef93cb1 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -66,7 +66,7 @@ static int fb_deferred_io_fault(struct vm_area_struct *vma,
return 0;
}
-int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
+int fb_deferred_io_fsync(struct file *file, int datasync)
{
struct fb_info *info = file->private_data;
@@ -100,6 +100,16 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
+ /*
+ * We want the page to remain locked from ->page_mkwrite until
+ * the PTE is marked dirty to avoid page_mkclean() being called
+ * before the PTE is updated, which would leave the page ignored
+ * by defio.
+ * Do this by locking the page here and informing the caller
+ * about it with VM_FAULT_LOCKED.
+ */
+ lock_page(page);
+
/* we loop through the pagelist before adding in order
to keep the pagelist sorted */
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
@@ -121,7 +131,7 @@ page_already_added:
/* come back after delay to process the deferred IO */
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
- return 0;
+ return VM_FAULT_LOCKED;
}
static const struct vm_operations_struct fb_deferred_io_vm_ops = {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index a15b44e9c00..731fce64df9 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1468,16 +1468,70 @@ static int fb_check_foreignness(struct fb_info *fi)
return 0;
}
-static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
+static bool apertures_overlap(struct aperture *gen, struct aperture *hw)
{
/* is the generic aperture base the same as the HW one */
- if (gen->aperture_base == hw->aperture_base)
+ if (gen->base == hw->base)
return true;
/* is the generic aperture base inside the hw base->hw base+size */
- if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size)
+ if (gen->base > hw->base && gen->base <= hw->base + hw->size)
return true;
return false;
}
+
+static bool fb_do_apertures_overlap(struct apertures_struct *gena,
+ struct apertures_struct *hwa)
+{
+ int i, j;
+ if (!hwa || !gena)
+ return false;
+
+ for (i = 0; i < hwa->count; ++i) {
+ struct aperture *h = &hwa->ranges[i];
+ for (j = 0; j < gena->count; ++j) {
+ struct aperture *g = &gena->ranges[j];
+ printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n",
+ (unsigned long long)g->base,
+ (unsigned long long)g->size,
+ (unsigned long long)h->base,
+ (unsigned long long)h->size);
+ if (apertures_overlap(g, h))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#define VGA_FB_PHYS 0xA0000
+void remove_conflicting_framebuffers(struct apertures_struct *a,
+ const char *name, bool primary)
+{
+ int i;
+
+ /* check all firmware fbs and kick off if the base addr overlaps */
+ for (i = 0 ; i < FB_MAX; i++) {
+ struct apertures_struct *gen_aper;
+ if (!registered_fb[i])
+ continue;
+
+ if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE))
+ continue;
+
+ gen_aper = registered_fb[i]->apertures;
+ if (fb_do_apertures_overlap(gen_aper, a) ||
+ (primary && gen_aper && gen_aper->count &&
+ gen_aper->ranges[0].base == VGA_FB_PHYS)) {
+
+ printk(KERN_ERR "fb: conflicting fb hw usage "
+ "%s vs %s - removing generic driver\n",
+ name, registered_fb[i]->fix.id);
+ unregister_framebuffer(registered_fb[i]);
+ }
+ }
+}
+EXPORT_SYMBOL(remove_conflicting_framebuffers);
+
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
@@ -1501,21 +1555,8 @@ register_framebuffer(struct fb_info *fb_info)
if (fb_check_foreignness(fb_info))
return -ENOSYS;
- /* check all firmware fbs and kick off if the base addr overlaps */
- for (i = 0 ; i < FB_MAX; i++) {
- if (!registered_fb[i])
- continue;
-
- if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
- if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
- printk(KERN_ERR "fb: conflicting fb hw usage "
- "%s vs %s - removing generic driver\n",
- fb_info->fix.id,
- registered_fb[i]->fix.id);
- unregister_framebuffer(registered_fb[i]);
- }
- }
- }
+ remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
+ fb_is_primary_device(fb_info));
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 81aa3129c17..0a08f134122 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -80,6 +80,7 @@ EXPORT_SYMBOL(framebuffer_alloc);
*/
void framebuffer_release(struct fb_info *info)
{
+ kfree(info->apertures);
kfree(info);
}
EXPORT_SYMBOL(framebuffer_release);
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index a42fabab69d..95c0227f47f 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -896,7 +896,7 @@ static void ffb_init_fix(struct fb_info *info)
static int __devinit ffb_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct ffb_fbc __iomem *fbc;
struct ffb_dac __iomem *dac;
struct fb_info *info;
@@ -1053,8 +1053,11 @@ static const struct of_device_id ffb_match[] = {
MODULE_DEVICE_TABLE(of, ffb_match);
static struct of_platform_driver ffb_driver = {
- .name = "ffb",
- .match_table = ffb_match,
+ .driver = {
+ .name = "ffb",
+ .owner = THIS_MODULE,
+ .of_match_table = ffb_match,
+ },
.probe = ffb_probe,
.remove = __devexit_p(ffb_remove),
};
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index 6c91c61cdb6..1b0feb8e724 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -219,6 +219,7 @@ static struct zorro_device_id fm2fb_devices[] __devinitdata = {
{ ZORRO_PROD_HELFRICH_RAINBOW_II },
{ 0 }
};
+MODULE_DEVICE_TABLE(zorro, fm2fb_devices);
static struct zorro_driver fm2fb_driver = {
.name = "fm2fb",
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 994358a4f30..27455ce298b 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1421,7 +1421,7 @@ static ssize_t show_monitor(struct device *device,
static int __devinit fsl_diu_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct mfb_info *mfbi;
phys_addr_t dummy_ad_addr;
int ret, i, error = 0;
@@ -1647,9 +1647,11 @@ static struct of_device_id fsl_diu_match[] = {
MODULE_DEVICE_TABLE(of, fsl_diu_match);
static struct of_platform_driver fsl_diu_driver = {
- .owner = THIS_MODULE,
- .name = "fsl_diu",
- .match_table = fsl_diu_match,
+ .driver = {
+ .name = "fsl_diu",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_diu_match,
+ },
.probe = fsl_diu_probe,
.remove = fsl_diu_remove,
.suspend = fsl_diu_suspend,
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 7d8c55d7fd2..ca3355e430b 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -91,10 +91,10 @@ static uint32_t pseudo_palette[16];
static uint32_t gbe_cmap[256];
static int gbe_turned_on; /* 0 turned off, 1 turned on */
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
/* default CRT mode */
-static struct fb_var_screeninfo default_var_CRT __initdata = {
+static struct fb_var_screeninfo default_var_CRT __devinitdata = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
.xres = 640,
.yres = 480,
@@ -125,7 +125,7 @@ static struct fb_var_screeninfo default_var_CRT __initdata = {
};
/* default LCD mode */
-static struct fb_var_screeninfo default_var_LCD __initdata = {
+static struct fb_var_screeninfo default_var_LCD __devinitdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
@@ -157,7 +157,7 @@ static struct fb_var_screeninfo default_var_LCD __initdata = {
/* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode default_mode_CRT __initdata = {
+static struct fb_videomode default_mode_CRT __devinitdata = {
.refresh = 60,
.xres = 640,
.yres = 480,
@@ -172,7 +172,7 @@ static struct fb_videomode default_mode_CRT __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
/* 1600x1024 SGI flatpanel 1600sw */
-static struct fb_videomode default_mode_LCD __initdata = {
+static struct fb_videomode default_mode_LCD __devinitdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
@@ -186,8 +186,8 @@ static struct fb_videomode default_mode_LCD __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_videomode *default_mode __initdata = &default_mode_CRT;
-static struct fb_var_screeninfo *default_var __initdata = &default_var_CRT;
+static struct fb_videomode *default_mode __devinitdata = &default_mode_CRT;
+static struct fb_var_screeninfo *default_var __devinitdata = &default_var_CRT;
static int flat_panel_enabled = 0;
@@ -1098,7 +1098,7 @@ static void gbefb_create_sysfs(struct device *dev)
* Initialization
*/
-static int __init gbefb_setup(char *options)
+static int __devinit gbefb_setup(char *options)
{
char *this_opt;
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 76e7dac6f25..70b1d9d51c9 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -40,7 +40,7 @@ static int vram;
static int vt_switch;
/* Modes relevant to the GX (taken from modedb.c) */
-static struct fb_videomode gx_modedb[] __initdata = {
+static struct fb_videomode gx_modedb[] __devinitdata = {
/* 640x480-60 VESA */
{ NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
@@ -110,14 +110,15 @@ static struct fb_videomode gx_modedb[] __initdata = {
#ifdef CONFIG_OLPC
#include <asm/olpc.h>
-static struct fb_videomode gx_dcon_modedb[] __initdata = {
+static struct fb_videomode gx_dcon_modedb[] __devinitdata = {
/* The only mode the DCON has is 1200x900 */
{ NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, 0 }
};
-static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+static void __devinit get_modedb(struct fb_videomode **modedb,
+ unsigned int *size)
{
if (olpc_has_dcon()) {
*modedb = (struct fb_videomode *) gx_dcon_modedb;
@@ -129,7 +130,8 @@ static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
}
#else
-static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+static void __devinit get_modedb(struct fb_videomode **modedb,
+ unsigned int *size)
{
*modedb = (struct fb_videomode *) gx_modedb;
*size = ARRAY_SIZE(gx_modedb);
@@ -226,7 +228,8 @@ static int gxfb_blank(int blank_mode, struct fb_info *info)
return gx_blank_display(info, blank_mode);
}
-static int __init gxfb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
+static int __devinit gxfb_map_video_memory(struct fb_info *info,
+ struct pci_dev *dev)
{
struct gxfb_par *par = info->par;
int ret;
@@ -290,7 +293,7 @@ static struct fb_ops gxfb_ops = {
.fb_imageblit = cfb_imageblit,
};
-static struct fb_info * __init gxfb_init_fbinfo(struct device *dev)
+static struct fb_info *__devinit gxfb_init_fbinfo(struct device *dev)
{
struct gxfb_par *par;
struct fb_info *info;
@@ -371,7 +374,8 @@ static int gxfb_resume(struct pci_dev *pdev)
}
#endif
-static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+static int __devinit gxfb_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
{
struct gxfb_par *par;
struct fb_info *info;
@@ -451,7 +455,7 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
return ret;
}
-static void gxfb_remove(struct pci_dev *pdev)
+static void __devexit gxfb_remove(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct gxfb_par *par = info->par;
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
index 1a18da86d3f..39bdbedf43b 100644
--- a/drivers/video/geode/lxfb_core.c
+++ b/drivers/video/geode/lxfb_core.c
@@ -35,7 +35,7 @@ static int vt_switch;
* we try to make it something sane - 640x480-60 is sane
*/
-static struct fb_videomode geode_modedb[] __initdata = {
+static struct fb_videomode geode_modedb[] __devinitdata = {
/* 640x480-60 */
{ NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
@@ -219,14 +219,15 @@ static struct fb_videomode geode_modedb[] __initdata = {
#ifdef CONFIG_OLPC
#include <asm/olpc.h>
-static struct fb_videomode olpc_dcon_modedb[] __initdata = {
+static struct fb_videomode olpc_dcon_modedb[] __devinitdata = {
/* The only mode the DCON has is 1200x900 */
{ NULL, 50, 1200, 900, 17460, 24, 8, 4, 5, 8, 3,
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
FB_VMODE_NONINTERLACED, 0 }
};
-static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+static void __devinit get_modedb(struct fb_videomode **modedb,
+ unsigned int *size)
{
if (olpc_has_dcon()) {
*modedb = (struct fb_videomode *) olpc_dcon_modedb;
@@ -238,7 +239,8 @@ static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
}
#else
-static void __init get_modedb(struct fb_videomode **modedb, unsigned int *size)
+static void __devinit get_modedb(struct fb_videomode **modedb,
+ unsigned int *size)
{
*modedb = (struct fb_videomode *) geode_modedb;
*size = ARRAY_SIZE(geode_modedb);
@@ -334,7 +336,7 @@ static int lxfb_blank(int blank_mode, struct fb_info *info)
}
-static int __init lxfb_map_video_memory(struct fb_info *info,
+static int __devinit lxfb_map_video_memory(struct fb_info *info,
struct pci_dev *dev)
{
struct lxfb_par *par = info->par;
@@ -412,7 +414,7 @@ static struct fb_ops lxfb_ops = {
.fb_imageblit = cfb_imageblit,
};
-static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
+static struct fb_info * __devinit lxfb_init_fbinfo(struct device *dev)
{
struct lxfb_par *par;
struct fb_info *info;
@@ -496,7 +498,7 @@ static int lxfb_resume(struct pci_dev *pdev)
#define lxfb_resume NULL
#endif
-static int __init lxfb_probe(struct pci_dev *pdev,
+static int __devinit lxfb_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct lxfb_par *par;
@@ -588,7 +590,7 @@ err:
return ret;
}
-static void lxfb_remove(struct pci_dev *pdev)
+static void __devexit lxfb_remove(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct lxfb_par *par = info->par;
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 8bbf251f83d..af8f0f2cc78 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -106,7 +106,7 @@ static DEFINE_SPINLOCK(hga_reg_lock);
/* Framebuffer driver structures */
-static struct fb_var_screeninfo __initdata hga_default_var = {
+static struct fb_var_screeninfo hga_default_var __devinitdata = {
.xres = 720,
.yres = 348,
.xres_virtual = 720,
@@ -120,7 +120,7 @@ static struct fb_var_screeninfo __initdata hga_default_var = {
.width = -1,
};
-static struct fb_fix_screeninfo __initdata hga_fix = {
+static struct fb_fix_screeninfo hga_fix __devinitdata = {
.id = "HGA",
.type = FB_TYPE_PACKED_PIXELS, /* (not sure) */
.visual = FB_VISUAL_MONO10,
@@ -276,7 +276,7 @@ static void hga_blank(int blank_mode)
spin_unlock_irqrestore(&hga_reg_lock, flags);
}
-static int __init hga_card_detect(void)
+static int __devinit hga_card_detect(void)
{
int count = 0;
void __iomem *p, *q;
@@ -596,7 +596,7 @@ static int __devinit hgafb_probe(struct platform_device *pdev)
return 0;
}
-static int hgafb_remove(struct platform_device *pdev)
+static int __devexit hgafb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
@@ -621,7 +621,7 @@ static int hgafb_remove(struct platform_device *pdev)
static struct platform_driver hgafb_driver = {
.probe = hgafb_probe,
- .remove = hgafb_remove,
+ .remove = __devexit_p(hgafb_remove),
.driver = {
.name = "hgafb",
},
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index 393f3f3d3df..cfb8d645101 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -30,14 +30,14 @@
#define WIDTH 640
-static struct fb_var_screeninfo hitfb_var __initdata = {
+static struct fb_var_screeninfo hitfb_var __devinitdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo hitfb_fix __initdata = {
+static struct fb_fix_screeninfo hitfb_fix __devinitdata = {
.id = "Hitachi HD64461",
.type = FB_TYPE_PACKED_PIXELS,
.accel = FB_ACCEL_NONE,
@@ -417,7 +417,7 @@ err_fb:
return ret;
}
-static int __exit hitfb_remove(struct platform_device *dev)
+static int __devexit hitfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
@@ -462,7 +462,7 @@ static const struct dev_pm_ops hitfb_dev_pm_ops = {
static struct platform_driver hitfb_driver = {
.probe = hitfb_probe,
- .remove = __exit_p(hitfb_remove),
+ .remove = __devexit_p(hitfb_remove),
.driver = {
.name = "hitfb",
.owner = THIS_MODULE,
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index b4b6deceed1..43f0639b1c1 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -175,6 +175,7 @@ struct imxfb_info {
struct imx_fb_videomode *mode;
int num_modes;
+ struct backlight_device *bl;
void (*lcd_power)(int);
void (*backlight_power)(int);
@@ -449,6 +450,73 @@ static int imxfb_set_par(struct fb_info *info)
return 0;
}
+
+
+static int imxfb_bl_get_brightness(struct backlight_device *bl)
+{
+ struct imxfb_info *fbi = bl_get_data(bl);
+
+ return readl(fbi->regs + LCDC_PWMR) & 0xFF;
+}
+
+static int imxfb_bl_update_status(struct backlight_device *bl)
+{
+ struct imxfb_info *fbi = bl_get_data(bl);
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ fbi->pwmr = (fbi->pwmr & ~0xFF) | brightness;
+
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ clk_enable(fbi->clk);
+ writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ clk_disable(fbi->clk);
+
+ return 0;
+}
+
+static const struct backlight_ops imxfb_lcdc_bl_ops = {
+ .update_status = imxfb_bl_update_status,
+ .get_brightness = imxfb_bl_get_brightness,
+};
+
+static void imxfb_init_backlight(struct imxfb_info *fbi)
+{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+
+ if (fbi->bl)
+ return;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 0xff;
+ writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
+
+ bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi,
+ &imxfb_lcdc_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ dev_err(&fbi->pdev->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+ return;
+ }
+
+ fbi->bl = bl;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.brightness = imxfb_bl_get_brightness(bl);
+}
+
+static void imxfb_exit_backlight(struct imxfb_info *fbi)
+{
+ if (fbi->bl)
+ backlight_device_unregister(fbi->bl);
+}
+
static void imxfb_enable_controller(struct imxfb_info *fbi)
{
pr_debug("Enabling LCD controller\n");
@@ -579,7 +647,6 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
fbi->regs + LCDC_SIZE);
writel(fbi->pcr, fbi->regs + LCDC_PCR);
- writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
@@ -779,6 +846,8 @@ static int __init imxfb_probe(struct platform_device *pdev)
}
imxfb_enable_controller(fbi);
+ fbi->pdev = pdev;
+ imxfb_init_backlight(fbi);
return 0;
@@ -816,6 +885,7 @@ static int __devexit imxfb_remove(struct platform_device *pdev)
imxfb_disable_controller(fbi);
+ imxfb_exit_backlight(fbi);
unregister_framebuffer(info);
pdata = pdev->dev.platform_data;
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 40984551c92..6b51175629c 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -371,10 +371,6 @@ struct intelfb_info {
((dinfo)->chipset == INTEL_965G) || \
((dinfo)->chipset == INTEL_965GM))
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
-#endif
-
/*** function prototypes ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 1db55f12849..9e8bf7d5e24 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -550,7 +550,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit leo_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct leo_par *par;
int linebytes, err;
@@ -663,8 +663,11 @@ static const struct of_device_id leo_match[] = {
MODULE_DEVICE_TABLE(of, leo_match);
static struct of_platform_driver leo_driver = {
- .name = "leo",
- .match_table = leo_match,
+ .driver = {
+ .name = "leo",
+ .owner = THIS_MODULE,
+ .of_match_table = leo_match,
+ },
.probe = leo_probe,
.remove = __devexit_p(leo_remove),
};
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index 8280a58a0e5..4e2b8cc3d46 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -553,7 +553,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par)
static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct device *dev = &ofdev->dev;
struct mb862xxfb_par *par;
struct fb_info *info;
@@ -718,9 +718,11 @@ static struct of_device_id __devinitdata of_platform_mb862xx_tbl[] = {
};
static struct of_platform_driver of_platform_mb862xxfb_driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .match_table = of_platform_mb862xx_tbl,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_platform_mb862xx_tbl,
+ },
.probe = of_platform_mb862xx_probe,
.remove = __devexit_p(of_platform_mb862xx_remove),
};
diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c
index 772ba3f45e6..7cfc170bce1 100644
--- a/drivers/video/mx3fb.c
+++ b/drivers/video/mx3fb.c
@@ -387,7 +387,8 @@ static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
spin_unlock_irqrestore(&mx3fb->lock, flags);
- mx3_fbi->txd->chan->device->device_terminate_all(mx3_fbi->txd->chan);
+ mx3_fbi->txd->chan->device->device_control(mx3_fbi->txd->chan,
+ DMA_TERMINATE_ALL, 0);
mx3_fbi->txd = NULL;
mx3_fbi->cookie = -EINVAL;
}
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c
index 6bf0d460a73..81687ed26ba 100644
--- a/drivers/video/nuc900fb.c
+++ b/drivers/video/nuc900fb.c
@@ -596,8 +596,6 @@ static int __devinit nuc900fb_probe(struct platform_device *pdev)
goto release_regs;
}
- nuc900_driver_clksrc_div(&pdev->dev, "ext", 0x2);
-
fbi->clk = clk_get(&pdev->dev, NULL);
if (!fbi->clk || IS_ERR(fbi->clk)) {
printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n");
@@ -667,7 +665,7 @@ release_irq:
release_regs:
iounmap(fbi->io);
release_mem_region:
- release_mem_region((unsigned long)fbi->mem, size);
+ release_mem_region(res->start, size);
free_fb:
framebuffer_release(fbinfo);
return ret;
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 61f8b8f919b..46dda7d8aae 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -285,7 +285,7 @@ static void offb_destroy(struct fb_info *info)
{
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(info->aperture_base, info->aperture_size);
+ release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
framebuffer_release(info);
}
@@ -491,8 +491,11 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var->vmode = FB_VMODE_NONINTERLACED;
/* set offb aperture size for generic probing */
- info->aperture_base = address;
- info->aperture_size = fix->smem_len;
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures)
+ goto out_aper;
+ info->apertures->ranges[0].base = address;
+ info->apertures->ranges[0].size = fix->smem_len;
info->fbops = &offb_ops;
info->screen_base = ioremap(address, fix->smem_len);
@@ -501,17 +504,20 @@ static void __init offb_init_fb(const char *name, const char *full_name,
fb_alloc_cmap(&info->cmap, 256, 0);
- if (register_framebuffer(info) < 0) {
- iounmap(par->cmap_adr);
- par->cmap_adr = NULL;
- iounmap(info->screen_base);
- framebuffer_release(info);
- release_mem_region(res_start, res_size);
- return;
- }
+ if (register_framebuffer(info) < 0)
+ goto out_err;
printk(KERN_INFO "fb%d: Open Firmware frame buffer device on %s\n",
info->node, full_name);
+ return;
+
+out_err:
+ iounmap(info->screen_base);
+out_aper:
+ iounmap(par->cmap_adr);
+ par->cmap_adr = NULL;
+ framebuffer_release(info);
+ release_mem_region(res_start, res_size);
}
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index 43ab7d8b66b..7767338f8b1 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -572,22 +572,12 @@ static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
/* PM code called only in internal controller mode */
static void omap_lcdc_suspend(void)
{
- if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
- disable_controller();
- omap_stop_lcd_dma();
- }
+ omap_lcdc_set_update_mode(OMAPFB_UPDATE_DISABLED);
}
static void omap_lcdc_resume(void)
{
- if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
- setup_regs();
- load_palette();
- setup_lcd_dma();
- set_load_mode(OMAP_LCDC_LOAD_FRAME);
- enable_irqs(OMAP_LCDC_IRQ_DONE);
- enable_controller();
- }
+ omap_lcdc_set_update_mode(OMAPFB_AUTO_UPDATE);
}
static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
index 1162603c72e..eada9f12efc 100644
--- a/drivers/video/omap/rfbi.c
+++ b/drivers/video/omap/rfbi.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include "omapfb.h"
#include "dispc.h"
@@ -83,13 +84,13 @@ static inline u32 rfbi_read_reg(int idx)
static int rfbi_get_clocks(void)
{
- rfbi.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
+ rfbi.dss_ick = clk_get(&rfbi.fbdev->dssdev->dev, "ick");
if (IS_ERR(rfbi.dss_ick)) {
dev_err(rfbi.fbdev->dev, "can't get ick\n");
return PTR_ERR(rfbi.dss_ick);
}
- rfbi.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
+ rfbi.dss1_fck = clk_get(&rfbi.fbdev->dssdev->dev, "dss1_fck");
if (IS_ERR(rfbi.dss1_fck)) {
dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
clk_put(rfbi.dss_ick);
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index dfb57ee5086..881c9f77c75 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -10,6 +10,7 @@ config PANEL_GENERIC
config PANEL_SHARP_LS037V7DW01
tristate "Sharp LS037V7DW01 LCD Panel"
depends on OMAP2_DSS
+ select BACKLIGHT_CLASS_DEVICE
help
LCD Panel used in TI's SDP3430 and EVM boards
@@ -33,8 +34,14 @@ config PANEL_TOPPOLY_TDO35S
config PANEL_TPO_TD043MTEA1
tristate "TPO TD043MTEA1 LCD Panel"
- depends on OMAP2_DSS && I2C
+ depends on OMAP2_DSS && SPI
help
LCD Panel used in OMAP3 Pandora
+config PANEL_ACX565AKM
+ tristate "ACX565AKM Panel"
+ depends on OMAP2_DSS_SDI
+ select BACKLIGHT_CLASS_DEVICE
+ help
+ This is the LCD panel used on Nokia N900
endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index e2bb32168de..aa386095d7c 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_PANEL_SHARP_LQ043T1DG01) += panel-sharp-lq043t1dg01.o
obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
obj-$(CONFIG_PANEL_TOPPOLY_TDO35S) += panel-toppoly-tdo35s.o
obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o
+obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c
new file mode 100644
index 00000000000..07fbb8a733b
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-acx565akm.c
@@ -0,0 +1,821 @@
+/*
+ * Support for ACX565AKM LCD Panel used on Nokia N900
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Original Driver Author: Imre Deak <imre.deak@nokia.com>
+ * Based on panel-generic.c by Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Adapted to new DSS2 framework: Roger Quadros <roger.quadros@nokia.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.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+
+#include <plat/display.h>
+
+#define MIPID_CMD_READ_DISP_ID 0x04
+#define MIPID_CMD_READ_RED 0x06
+#define MIPID_CMD_READ_GREEN 0x07
+#define MIPID_CMD_READ_BLUE 0x08
+#define MIPID_CMD_READ_DISP_STATUS 0x09
+#define MIPID_CMD_RDDSDR 0x0F
+#define MIPID_CMD_SLEEP_IN 0x10
+#define MIPID_CMD_SLEEP_OUT 0x11
+#define MIPID_CMD_DISP_OFF 0x28
+#define MIPID_CMD_DISP_ON 0x29
+#define MIPID_CMD_WRITE_DISP_BRIGHTNESS 0x51
+#define MIPID_CMD_READ_DISP_BRIGHTNESS 0x52
+#define MIPID_CMD_WRITE_CTRL_DISP 0x53
+
+#define CTRL_DISP_BRIGHTNESS_CTRL_ON (1 << 5)
+#define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON (1 << 4)
+#define CTRL_DISP_BACKLIGHT_ON (1 << 2)
+#define CTRL_DISP_AUTO_BRIGHTNESS_ON (1 << 1)
+
+#define MIPID_CMD_READ_CTRL_DISP 0x54
+#define MIPID_CMD_WRITE_CABC 0x55
+#define MIPID_CMD_READ_CABC 0x56
+
+#define MIPID_VER_LPH8923 3
+#define MIPID_VER_LS041Y3 4
+#define MIPID_VER_L4F00311 8
+#define MIPID_VER_ACX565AKM 9
+
+struct acx565akm_device {
+ char *name;
+ int enabled;
+ int model;
+ int revision;
+ u8 display_id[3];
+ unsigned has_bc:1;
+ unsigned has_cabc:1;
+ unsigned cabc_mode;
+ unsigned long hw_guard_end; /* next value of jiffies
+ when we can issue the
+ next sleep in/out command */
+ unsigned long hw_guard_wait; /* max guard time in jiffies */
+
+ struct spi_device *spi;
+ struct mutex mutex;
+
+ struct omap_dss_device *dssdev;
+ struct backlight_device *bl_dev;
+};
+
+static struct acx565akm_device acx_dev;
+static int acx565akm_bl_update_status(struct backlight_device *dev);
+
+/*--------------------MIPID interface-----------------------------*/
+
+static void acx565akm_transfer(struct acx565akm_device *md, int cmd,
+ const u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct spi_message m;
+ struct spi_transfer *x, xfer[5];
+ int r;
+
+ BUG_ON(md->spi == NULL);
+
+ spi_message_init(&m);
+
+ memset(xfer, 0, sizeof(xfer));
+ x = &xfer[0];
+
+ cmd &= 0xff;
+ x->tx_buf = &cmd;
+ x->bits_per_word = 9;
+ x->len = 2;
+
+ if (rlen > 1 && wlen == 0) {
+ /*
+ * Between the command and the response data there is a
+ * dummy clock cycle. Add an extra bit after the command
+ * word to account for this.
+ */
+ x->bits_per_word = 10;
+ cmd <<= 1;
+ }
+ spi_message_add_tail(x, &m);
+
+ if (wlen) {
+ x++;
+ x->tx_buf = wbuf;
+ x->len = wlen;
+ x->bits_per_word = 9;
+ spi_message_add_tail(x, &m);
+ }
+
+ if (rlen) {
+ x++;
+ x->rx_buf = rbuf;
+ x->len = rlen;
+ spi_message_add_tail(x, &m);
+ }
+
+ r = spi_sync(md->spi, &m);
+ if (r < 0)
+ dev_dbg(&md->spi->dev, "spi_sync %d\n", r);
+}
+
+static inline void acx565akm_cmd(struct acx565akm_device *md, int cmd)
+{
+ acx565akm_transfer(md, cmd, NULL, 0, NULL, 0);
+}
+
+static inline void acx565akm_write(struct acx565akm_device *md,
+ int reg, const u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, buf, len, NULL, 0);
+}
+
+static inline void acx565akm_read(struct acx565akm_device *md,
+ int reg, u8 *buf, int len)
+{
+ acx565akm_transfer(md, reg, NULL, 0, buf, len);
+}
+
+static void hw_guard_start(struct acx565akm_device *md, int guard_msec)
+{
+ md->hw_guard_wait = msecs_to_jiffies(guard_msec);
+ md->hw_guard_end = jiffies + md->hw_guard_wait;
+}
+
+static void hw_guard_wait(struct acx565akm_device *md)
+{
+ unsigned long wait = md->hw_guard_end - jiffies;
+
+ if ((long)wait > 0 && wait <= md->hw_guard_wait) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(wait);
+ }
+}
+
+/*----------------------MIPID wrappers----------------------------*/
+
+static void set_sleep_mode(struct acx565akm_device *md, int on)
+{
+ int cmd;
+
+ if (on)
+ cmd = MIPID_CMD_SLEEP_IN;
+ else
+ cmd = MIPID_CMD_SLEEP_OUT;
+ /*
+ * We have to keep 120msec between sleep in/out commands.
+ * (8.2.15, 8.2.16).
+ */
+ hw_guard_wait(md);
+ acx565akm_cmd(md, cmd);
+ hw_guard_start(md, 120);
+}
+
+static void set_display_state(struct acx565akm_device *md, int enabled)
+{
+ int cmd = enabled ? MIPID_CMD_DISP_ON : MIPID_CMD_DISP_OFF;
+
+ acx565akm_cmd(md, cmd);
+}
+
+static int panel_enabled(struct acx565akm_device *md)
+{
+ u32 disp_status;
+ int enabled;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_STATUS, (u8 *)&disp_status, 4);
+ disp_status = __be32_to_cpu(disp_status);
+ enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10));
+ dev_dbg(&md->spi->dev,
+ "LCD panel %senabled by bootloader (status 0x%04x)\n",
+ enabled ? "" : "not ", disp_status);
+ return enabled;
+}
+
+static int panel_detect(struct acx565akm_device *md)
+{
+ acx565akm_read(md, MIPID_CMD_READ_DISP_ID, md->display_id, 3);
+ dev_dbg(&md->spi->dev, "MIPI display ID: %02x%02x%02x\n",
+ md->display_id[0], md->display_id[1], md->display_id[2]);
+
+ switch (md->display_id[0]) {
+ case 0x10:
+ md->model = MIPID_VER_ACX565AKM;
+ md->name = "acx565akm";
+ md->has_bc = 1;
+ md->has_cabc = 1;
+ break;
+ case 0x29:
+ md->model = MIPID_VER_L4F00311;
+ md->name = "l4f00311";
+ break;
+ case 0x45:
+ md->model = MIPID_VER_LPH8923;
+ md->name = "lph8923";
+ break;
+ case 0x83:
+ md->model = MIPID_VER_LS041Y3;
+ md->name = "ls041y3";
+ break;
+ default:
+ md->name = "unknown";
+ dev_err(&md->spi->dev, "invalid display ID\n");
+ return -ENODEV;
+ }
+
+ md->revision = md->display_id[1];
+
+ dev_info(&md->spi->dev, "omapfb: %s rev %02x LCD detected\n",
+ md->name, md->revision);
+
+ return 0;
+}
+
+/*----------------------Backlight Control-------------------------*/
+
+static void enable_backlight_ctrl(struct acx565akm_device *md, int enable)
+{
+ u16 ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CTRL_DISP, (u8 *)&ctrl, 1);
+ if (enable) {
+ ctrl |= CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON;
+ } else {
+ ctrl &= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON |
+ CTRL_DISP_BACKLIGHT_ON);
+ }
+
+ ctrl |= 1 << 8;
+ acx565akm_write(md, MIPID_CMD_WRITE_CTRL_DISP, (u8 *)&ctrl, 2);
+}
+
+static void set_cabc_mode(struct acx565akm_device *md, unsigned mode)
+{
+ u16 cabc_ctrl;
+
+ md->cabc_mode = mode;
+ if (!md->enabled)
+ return;
+ cabc_ctrl = 0;
+ acx565akm_read(md, MIPID_CMD_READ_CABC, (u8 *)&cabc_ctrl, 1);
+ cabc_ctrl &= ~3;
+ cabc_ctrl |= (1 << 8) | (mode & 3);
+ acx565akm_write(md, MIPID_CMD_WRITE_CABC, (u8 *)&cabc_ctrl, 2);
+}
+
+static unsigned get_cabc_mode(struct acx565akm_device *md)
+{
+ return md->cabc_mode;
+}
+
+static unsigned get_hw_cabc_mode(struct acx565akm_device *md)
+{
+ u8 cabc_ctrl;
+
+ acx565akm_read(md, MIPID_CMD_READ_CABC, &cabc_ctrl, 1);
+ return cabc_ctrl & 3;
+}
+
+static void acx565akm_set_brightness(struct acx565akm_device *md, int level)
+{
+ int bv;
+
+ bv = level | (1 << 8);
+ acx565akm_write(md, MIPID_CMD_WRITE_DISP_BRIGHTNESS, (u8 *)&bv, 2);
+
+ if (level)
+ enable_backlight_ctrl(md, 1);
+ else
+ enable_backlight_ctrl(md, 0);
+}
+
+static int acx565akm_get_actual_brightness(struct acx565akm_device *md)
+{
+ u8 bv;
+
+ acx565akm_read(md, MIPID_CMD_READ_DISP_BRIGHTNESS, &bv, 1);
+
+ return bv;
+}
+
+
+static int acx565akm_bl_update_status(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+ int r;
+ int level;
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK)
+ level = dev->props.brightness;
+ else
+ level = 0;
+
+ r = 0;
+ if (md->has_bc)
+ acx565akm_set_brightness(md, level);
+ else if (md->dssdev->set_backlight)
+ r = md->dssdev->set_backlight(md->dssdev, level);
+ else
+ r = -ENODEV;
+
+ mutex_unlock(&md->mutex);
+
+ return r;
+}
+
+static int acx565akm_bl_get_intensity(struct backlight_device *dev)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&dev->dev);
+
+ dev_dbg(&dev->dev, "%s\n", __func__);
+
+ if (!md->has_bc && md->dssdev->set_backlight == NULL)
+ return -ENODEV;
+
+ if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
+ dev->props.power == FB_BLANK_UNBLANK) {
+ if (md->has_bc)
+ return acx565akm_get_actual_brightness(md);
+ else
+ return dev->props.brightness;
+ }
+
+ return 0;
+}
+
+static const struct backlight_ops acx565akm_bl_ops = {
+ .get_brightness = acx565akm_bl_get_intensity,
+ .update_status = acx565akm_bl_update_status,
+};
+
+/*--------------------Auto Brightness control via Sysfs---------------------*/
+
+static const char *cabc_modes[] = {
+ "off", /* always used when CABC is not supported */
+ "ui",
+ "still-image",
+ "moving-image",
+};
+
+static ssize_t show_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ const char *mode_str;
+ int mode;
+ int len;
+
+ if (!md->has_cabc)
+ mode = 0;
+ else
+ mode = get_cabc_mode(md);
+ mode_str = "unknown";
+ if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
+ mode_str = cabc_modes[mode];
+ len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
+
+ return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
+}
+
+static ssize_t store_cabc_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
+ const char *mode_str = cabc_modes[i];
+ int cmp_len = strlen(mode_str);
+
+ if (count > 0 && buf[count - 1] == '\n')
+ count--;
+ if (count != cmp_len)
+ continue;
+
+ if (strncmp(buf, mode_str, cmp_len) == 0)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(cabc_modes))
+ return -EINVAL;
+
+ if (!md->has_cabc && i != 0)
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ set_cabc_mode(md, i);
+ mutex_unlock(&md->mutex);
+
+ return count;
+}
+
+static ssize_t show_cabc_available_modes(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct acx565akm_device *md = dev_get_drvdata(dev);
+ int len;
+ int i;
+
+ if (!md->has_cabc)
+ return snprintf(buf, PAGE_SIZE, "%s\n", cabc_modes[0]);
+
+ for (i = 0, len = 0;
+ len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
+ len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
+ i ? " " : "", cabc_modes[i],
+ i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
+
+ return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
+}
+
+static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
+ show_cabc_mode, store_cabc_mode);
+static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
+ show_cabc_available_modes, NULL);
+
+static struct attribute *bldev_attrs[] = {
+ &dev_attr_cabc_mode.attr,
+ &dev_attr_cabc_available_modes.attr,
+ NULL,
+};
+
+static struct attribute_group bldev_attr_group = {
+ .attrs = bldev_attrs,
+};
+
+
+/*---------------------------ACX Panel----------------------------*/
+
+static int acx_get_recommended_bpp(struct omap_dss_device *dssdev)
+{
+ return 16;
+}
+
+static struct omap_video_timings acx_panel_timings = {
+ .x_res = 800,
+ .y_res = 480,
+ .pixel_clock = 24000,
+ .hfp = 28,
+ .hsw = 4,
+ .hbp = 24,
+ .vfp = 3,
+ .vsw = 3,
+ .vbp = 4,
+};
+
+static int acx_panel_probe(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct acx565akm_device *md = &acx_dev;
+ struct backlight_device *bldev;
+ int max_brightness, brightness;
+ struct backlight_properties props;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
+ OMAP_DSS_LCD_IHS;
+ /* FIXME AC bias ? */
+ dssdev->panel.timings = acx_panel_timings;
+
+ if (dssdev->platform_enable)
+ dssdev->platform_enable(dssdev);
+ /*
+ * After reset we have to wait 5 msec before the first
+ * command can be sent.
+ */
+ msleep(5);
+
+ md->enabled = panel_enabled(md);
+
+ r = panel_detect(md);
+ if (r) {
+ dev_err(&dssdev->dev, "%s panel detect error\n", __func__);
+ if (!md->enabled && dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ return r;
+ }
+
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = dssdev;
+ mutex_unlock(&acx_dev.mutex);
+
+ if (!md->enabled) {
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+ }
+
+ /*------- Backlight control --------*/
+
+ props.fb_blank = FB_BLANK_UNBLANK;
+ props.power = FB_BLANK_UNBLANK;
+
+ bldev = backlight_device_register("acx565akm", &md->spi->dev,
+ md, &acx565akm_bl_ops, &props);
+ md->bl_dev = bldev;
+ if (md->has_cabc) {
+ r = sysfs_create_group(&bldev->dev.kobj, &bldev_attr_group);
+ if (r) {
+ dev_err(&bldev->dev,
+ "%s failed to create sysfs files\n", __func__);
+ backlight_device_unregister(bldev);
+ return r;
+ }
+ md->cabc_mode = get_hw_cabc_mode(md);
+ }
+
+ if (md->has_bc)
+ max_brightness = 255;
+ else
+ max_brightness = dssdev->max_backlight_level;
+
+ if (md->has_bc)
+ brightness = acx565akm_get_actual_brightness(md);
+ else if (dssdev->get_backlight)
+ brightness = dssdev->get_backlight(dssdev);
+ else
+ brightness = 0;
+
+ bldev->props.max_brightness = max_brightness;
+ bldev->props.brightness = brightness;
+
+ acx565akm_bl_update_status(bldev);
+ return 0;
+}
+
+static void acx_panel_remove(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ sysfs_remove_group(&md->bl_dev->dev.kobj, &bldev_attr_group);
+ backlight_device_unregister(md->bl_dev);
+ mutex_lock(&acx_dev.mutex);
+ acx_dev.dssdev = NULL;
+ mutex_unlock(&acx_dev.mutex);
+}
+
+static int acx_panel_power_on(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ r = omapdss_sdi_display_enable(dssdev);
+ if (r) {
+ pr_err("%s sdi enable failed\n", __func__);
+ goto fail_unlock;
+ }
+
+ /*FIXME tweak me */
+ msleep(50);
+
+ if (dssdev->platform_enable) {
+ r = dssdev->platform_enable(dssdev);
+ if (r)
+ goto fail;
+ }
+
+ if (md->enabled) {
+ dev_dbg(&md->spi->dev, "panel already enabled\n");
+ mutex_unlock(&md->mutex);
+ return 0;
+ }
+
+ /*
+ * We have to meet all the following delay requirements:
+ * 1. tRW: reset pulse width 10usec (7.12.1)
+ * 2. tRT: reset cancel time 5msec (7.12.1)
+ * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
+ * case (7.6.2)
+ * 4. 120msec before the sleep out command (7.12.1)
+ */
+ msleep(120);
+
+ set_sleep_mode(md, 0);
+ md->enabled = 1;
+
+ /* 5msec between sleep out and the next command. (8.2.16) */
+ msleep(5);
+ set_display_state(md, 1);
+ set_cabc_mode(md, md->cabc_mode);
+
+ mutex_unlock(&md->mutex);
+
+ return acx565akm_bl_update_status(md->bl_dev);
+fail:
+ omapdss_sdi_display_disable(dssdev);
+fail_unlock:
+ mutex_unlock(&md->mutex);
+ return r;
+}
+
+static void acx_panel_power_off(struct omap_dss_device *dssdev)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+
+ mutex_lock(&md->mutex);
+
+ if (!md->enabled) {
+ mutex_unlock(&md->mutex);
+ return;
+ }
+ set_display_state(md, 0);
+ set_sleep_mode(md, 1);
+ md->enabled = 0;
+ /*
+ * We have to provide PCLK,HS,VS signals for 2 frames (worst case
+ * ~50msec) after sending the sleep in command and asserting the
+ * reset signal. We probably could assert the reset w/o the delay
+ * but we still delay to avoid possible artifacts. (7.6.1)
+ */
+ msleep(50);
+
+ if (dssdev->platform_disable)
+ dssdev->platform_disable(dssdev);
+
+ /* FIXME need to tweak this delay */
+ msleep(100);
+
+ omapdss_sdi_display_disable(dssdev);
+
+ mutex_unlock(&md->mutex);
+}
+
+static int acx_panel_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static void acx_panel_disable(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static int acx_panel_suspend(struct omap_dss_device *dssdev)
+{
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ acx_panel_power_off(dssdev);
+ dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ return 0;
+}
+
+static int acx_panel_resume(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ dev_dbg(&dssdev->dev, "%s\n", __func__);
+ r = acx_panel_power_on(dssdev);
+ if (r)
+ return r;
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ return 0;
+}
+
+static void acx_panel_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ int r;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
+ omapdss_sdi_display_disable(dssdev);
+
+ dssdev->panel.timings = *timings;
+
+ if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
+ r = omapdss_sdi_display_enable(dssdev);
+ if (r)
+ dev_err(&dssdev->dev, "%s enable failed\n", __func__);
+ }
+}
+
+static void acx_panel_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ *timings = dssdev->panel.timings;
+}
+
+static int acx_panel_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ return 0;
+}
+
+
+static struct omap_dss_driver acx_panel_driver = {
+ .probe = acx_panel_probe,
+ .remove = acx_panel_remove,
+
+ .enable = acx_panel_enable,
+ .disable = acx_panel_disable,
+ .suspend = acx_panel_suspend,
+ .resume = acx_panel_resume,
+
+ .set_timings = acx_panel_set_timings,
+ .get_timings = acx_panel_get_timings,
+ .check_timings = acx_panel_check_timings,
+
+ .get_recommended_bpp = acx_get_recommended_bpp,
+
+ .driver = {
+ .name = "panel-acx565akm",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*--------------------SPI probe-------------------------*/
+
+static int acx565akm_spi_probe(struct spi_device *spi)
+{
+ struct acx565akm_device *md = &acx_dev;
+
+ dev_dbg(&spi->dev, "%s\n", __func__);
+
+ spi->mode = SPI_MODE_3;
+ md->spi = spi;
+ mutex_init(&md->mutex);
+ dev_set_drvdata(&spi->dev, md);
+
+ omap_dss_register_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static int acx565akm_spi_remove(struct spi_device *spi)
+{
+ struct acx565akm_device *md = dev_get_drvdata(&spi->dev);
+
+ dev_dbg(&md->spi->dev, "%s\n", __func__);
+ omap_dss_unregister_driver(&acx_panel_driver);
+
+ return 0;
+}
+
+static struct spi_driver acx565akm_spi_driver = {
+ .driver = {
+ .name = "acx565akm",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = acx565akm_spi_probe,
+ .remove = __devexit_p(acx565akm_spi_remove),
+};
+
+static int __init acx565akm_init(void)
+{
+ return spi_register_driver(&acx565akm_spi_driver);
+}
+
+static void __exit acx565akm_exit(void)
+{
+ spi_unregister_driver(&acx565akm_spi_driver);
+}
+
+module_init(acx565akm_init);
+module_exit(acx565akm_exit);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_DESCRIPTION("acx565akm LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
index 8d51a5e6341..7d9eb2b1f5a 100644
--- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -20,10 +20,17 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
#include <linux/err.h>
+#include <linux/slab.h>
#include <plat/display.h>
+struct sharp_data {
+ struct backlight_device *bl;
+};
+
static struct omap_video_timings sharp_ls_timings = {
.x_res = 480,
.y_res = 640,
@@ -39,18 +46,89 @@ static struct omap_video_timings sharp_ls_timings = {
.vbp = 1,
};
+static int sharp_ls_bl_update_status(struct backlight_device *bl)
+{
+ struct omap_dss_device *dssdev = dev_get_drvdata(&bl->dev);
+ int level;
+
+ if (!dssdev->set_backlight)
+ return -EINVAL;
+
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ level = bl->props.brightness;
+ else
+ level = 0;
+
+ return dssdev->set_backlight(dssdev, level);
+}
+
+static int sharp_ls_bl_get_brightness(struct backlight_device *bl)
+{
+ if (bl->props.fb_blank == FB_BLANK_UNBLANK &&
+ bl->props.power == FB_BLANK_UNBLANK)
+ return bl->props.brightness;
+
+ return 0;
+}
+
+static const struct backlight_ops sharp_ls_bl_ops = {
+ .get_brightness = sharp_ls_bl_get_brightness,
+ .update_status = sharp_ls_bl_update_status,
+};
+
+
+
static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+ struct sharp_data *sd;
+ int r;
+
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.acb = 0x28;
dssdev->panel.timings = sharp_ls_timings;
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
+
+ dev_set_drvdata(&dssdev->dev, sd);
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = dssdev->max_backlight_level;
+
+ bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev,
+ &sharp_ls_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ r = PTR_ERR(bl);
+ kfree(sd);
+ return r;
+ }
+ sd->bl = bl;
+
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.brightness = dssdev->max_backlight_level;
+ r = sharp_ls_bl_update_status(bl);
+ if (r < 0)
+ dev_err(&dssdev->dev, "failed to set lcd brightness\n");
+
return 0;
}
static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
{
+ struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
+ struct backlight_device *bl = sd->bl;
+
+ bl->props.power = FB_BLANK_POWERDOWN;
+ sharp_ls_bl_update_status(bl);
+ backlight_device_unregister(bl);
+
+ kfree(sd);
}
static int sharp_ls_power_on(struct omap_dss_device *dssdev)
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 4f3988a4108..aaf5d308a04 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -31,6 +31,7 @@
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <plat/display.h>
@@ -67,6 +68,8 @@
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
struct taal_data {
+ struct mutex lock;
+
struct backlight_device *bldev;
unsigned long hw_guard_end; /* next value of jiffies when we can
@@ -510,6 +513,8 @@ static int taal_probe(struct omap_dss_device *dssdev)
}
td->dssdev = dssdev;
+ mutex_init(&td->lock);
+
td->esd_wq = create_singlethread_workqueue("taal_esd");
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
@@ -697,10 +702,9 @@ static int taal_power_on(struct omap_dss_device *dssdev)
return 0;
err:
- dsi_bus_unlock();
-
omapdss_dsi_display_disable(dssdev);
err0:
+ dsi_bus_unlock();
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
@@ -733,54 +737,96 @@ static void taal_power_off(struct omap_dss_device *dssdev)
static int taal_enable(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+
dev_dbg(&dssdev->dev, "enable\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
+ r = -EINVAL;
+ goto err;
+ }
r = taal_power_on(dssdev);
if (r)
- return r;
+ goto err;
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+ mutex_unlock(&td->lock);
+
+ return 0;
+err:
+ dev_dbg(&dssdev->dev, "enable failed\n");
+ mutex_unlock(&td->lock);
return r;
}
static void taal_disable(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
dev_dbg(&dssdev->dev, "disable\n");
+ mutex_lock(&td->lock);
+
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
taal_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+
+ mutex_unlock(&td->lock);
}
static int taal_suspend(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ int r;
+
dev_dbg(&dssdev->dev, "suspend\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
+ r = -EINVAL;
+ goto err;
+ }
taal_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+ mutex_unlock(&td->lock);
+
return 0;
+err:
+ mutex_unlock(&td->lock);
+ return r;
}
static int taal_resume(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+
dev_dbg(&dssdev->dev, "resume\n");
- if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
- return -EINVAL;
+ mutex_lock(&td->lock);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
+ r = -EINVAL;
+ goto err;
+ }
r = taal_power_on(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ mutex_unlock(&td->lock);
+
+ return r;
+err:
+ mutex_unlock(&td->lock);
return r;
}
@@ -799,6 +845,7 @@ static int taal_update(struct omap_dss_device *dssdev,
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
+ mutex_lock(&td->lock);
dsi_bus_lock();
if (!td->enabled) {
@@ -820,18 +867,24 @@ static int taal_update(struct omap_dss_device *dssdev,
goto err;
/* note: no bus_unlock here. unlock is in framedone_cb */
+ mutex_unlock(&td->lock);
return 0;
err:
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return r;
}
static int taal_sync(struct omap_dss_device *dssdev)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+
dev_dbg(&dssdev->dev, "sync\n");
+ mutex_lock(&td->lock);
dsi_bus_lock();
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
dev_dbg(&dssdev->dev, "sync done\n");
@@ -861,13 +914,16 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
+ mutex_lock(&td->lock);
dsi_bus_lock();
r = _taal_enable_te(dssdev, enable);
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return r;
}
@@ -875,7 +931,13 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
static int taal_get_te(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->te_enabled;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->te_enabled;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
@@ -885,6 +947,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
+ mutex_lock(&td->lock);
dsi_bus_lock();
if (td->enabled) {
@@ -896,16 +959,24 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
td->rotate = rotate;
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return 0;
err:
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return r;
}
static u8 taal_get_rotate(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->rotate;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->rotate;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
@@ -915,6 +986,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
+ mutex_lock(&td->lock);
dsi_bus_lock();
if (td->enabled) {
r = taal_set_addr_mode(td->rotate, enable);
@@ -925,23 +997,33 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
td->mirror = enable;
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return 0;
err:
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return r;
}
static bool taal_get_mirror(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- return td->mirror;
+ int r;
+
+ mutex_lock(&td->lock);
+ r = td->mirror;
+ mutex_unlock(&td->lock);
+
+ return r;
}
static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
{
+ struct taal_data *td = dev_get_drvdata(&dssdev->dev);
u8 id1, id2, id3;
int r;
+ mutex_lock(&td->lock);
dsi_bus_lock();
r = taal_dcs_read_1(DCS_GET_ID1, &id1);
@@ -955,9 +1037,11 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
goto err;
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return 0;
err:
dsi_bus_unlock();
+ mutex_unlock(&td->lock);
return r;
}
@@ -971,12 +1055,16 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
unsigned buf_used = 0;
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
- if (!td->enabled)
- return -ENODEV;
-
if (size < w * h * 3)
return -ENOMEM;
+ mutex_lock(&td->lock);
+
+ if (!td->enabled) {
+ r = -ENODEV;
+ goto err1;
+ }
+
size = min(w * h * 3,
dssdev->panel.timings.x_res *
dssdev->panel.timings.y_res * 3);
@@ -995,7 +1083,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
r = dsi_vc_set_max_rx_packet_size(TCH, plen);
if (r)
- goto err0;
+ goto err2;
while (buf_used < size) {
u8 dcs_cmd = first ? 0x2e : 0x3e;
@@ -1006,7 +1094,7 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
if (r < 0) {
dev_err(&dssdev->dev, "read error\n");
- goto err;
+ goto err3;
}
buf_used += r;
@@ -1020,16 +1108,18 @@ static int taal_memory_read(struct omap_dss_device *dssdev,
dev_err(&dssdev->dev, "signal pending, "
"aborting memory read\n");
r = -ERESTARTSYS;
- goto err;
+ goto err3;
}
}
r = buf_used;
-err:
+err3:
dsi_vc_set_max_rx_packet_size(TCH, 1);
-err0:
+err2:
dsi_bus_unlock();
+err1:
+ mutex_unlock(&td->lock);
return r;
}
@@ -1041,8 +1131,12 @@ static void taal_esd_work(struct work_struct *work)
u8 state1, state2;
int r;
- if (!td->enabled)
+ mutex_lock(&td->lock);
+
+ if (!td->enabled) {
+ mutex_unlock(&td->lock);
return;
+ }
dsi_bus_lock();
@@ -1084,16 +1178,19 @@ static void taal_esd_work(struct work_struct *work)
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+ mutex_unlock(&td->lock);
return;
err:
dev_err(&dssdev->dev, "performing LCD reset\n");
- taal_disable(dssdev);
- taal_enable(dssdev);
+ taal_power_off(dssdev);
+ taal_power_on(dssdev);
dsi_bus_unlock();
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
+
+ mutex_unlock(&td->lock);
}
static int taal_set_update_mode(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index 87afb81b2c4..43b64403eaa 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -36,6 +36,12 @@ config OMAP2_DSS_COLLECT_IRQ_STATS
<debugfs>/omapdss/dispc_irq for DISPC interrupts, and
<debugfs>/omapdss/dsi_irq for DSI interrupts.
+config OMAP2_DSS_DPI
+ bool "DPI support"
+ default y
+ help
+ DPI Interface. This is the Parallel Display Interface.
+
config OMAP2_DSS_RFBI
bool "RFBI support"
default n
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
index 980c72c2db9..d71b5d9d71b 100644
--- a/drivers/video/omap2/dss/Makefile
+++ b/drivers/video/omap2/dss/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
-omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
+omapdss-y := core.o dss.o dispc.o display.o manager.o overlay.o
+omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 7ebe50b335e..b3a498f22d3 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -482,6 +482,14 @@ static void dss_uninitialize_debugfs(void)
if (dss_debugfs_dir)
debugfs_remove_recursive(dss_debugfs_dir);
}
+#else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
+static inline int dss_initialize_debugfs(void)
+{
+ return 0;
+}
+static inline void dss_uninitialize_debugfs(void)
+{
+}
#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
/* PLATFORM DEVICE */
@@ -499,7 +507,7 @@ static int omap_dss_probe(struct platform_device *pdev)
r = dss_get_clocks();
if (r)
- goto fail0;
+ goto err_clocks;
dss_clk_enable_all_no_ctx();
@@ -515,64 +523,64 @@ static int omap_dss_probe(struct platform_device *pdev)
r = dss_init(skip_init);
if (r) {
DSSERR("Failed to initialize DSS\n");
- goto fail0;
+ goto err_dss;
}
-#ifdef CONFIG_OMAP2_DSS_RFBI
r = rfbi_init();
if (r) {
DSSERR("Failed to initialize rfbi\n");
- goto fail0;
+ goto err_rfbi;
}
-#endif
r = dpi_init(pdev);
if (r) {
DSSERR("Failed to initialize dpi\n");
- goto fail0;
+ goto err_dpi;
}
r = dispc_init();
if (r) {
DSSERR("Failed to initialize dispc\n");
- goto fail0;
+ goto err_dispc;
}
-#ifdef CONFIG_OMAP2_DSS_VENC
+
r = venc_init(pdev);
if (r) {
DSSERR("Failed to initialize venc\n");
- goto fail0;
+ goto err_venc;
}
-#endif
+
if (cpu_is_omap34xx()) {
-#ifdef CONFIG_OMAP2_DSS_SDI
r = sdi_init(skip_init);
if (r) {
DSSERR("Failed to initialize SDI\n");
- goto fail0;
+ goto err_sdi;
}
-#endif
-#ifdef CONFIG_OMAP2_DSS_DSI
+
r = dsi_init(pdev);
if (r) {
DSSERR("Failed to initialize DSI\n");
- goto fail0;
+ goto err_dsi;
}
-#endif
}
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
r = dss_initialize_debugfs();
if (r)
- goto fail0;
-#endif
+ goto err_debugfs;
for (i = 0; i < pdata->num_devices; ++i) {
struct omap_dss_device *dssdev = pdata->devices[i];
r = omap_dss_register_device(dssdev);
- if (r)
- DSSERR("device reg failed %d\n", i);
+ if (r) {
+ DSSERR("device %d %s register failed %d\n", i,
+ dssdev->name ?: "unnamed", r);
+
+ while (--i >= 0)
+ omap_dss_unregister_device(pdata->devices[i]);
+
+ goto err_register;
+ }
if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
pdata->default_device = dssdev;
@@ -582,8 +590,29 @@ static int omap_dss_probe(struct platform_device *pdev)
return 0;
- /* XXX fail correctly */
-fail0:
+err_register:
+ dss_uninitialize_debugfs();
+err_debugfs:
+ if (cpu_is_omap34xx())
+ dsi_exit();
+err_dsi:
+ if (cpu_is_omap34xx())
+ sdi_exit();
+err_sdi:
+ venc_exit();
+err_venc:
+ dispc_exit();
+err_dispc:
+ dpi_exit();
+err_dpi:
+ rfbi_exit();
+err_rfbi:
+ dss_exit();
+err_dss:
+ dss_clk_disable_all_no_ctx();
+ dss_put_clocks();
+err_clocks:
+
return r;
}
@@ -593,25 +622,15 @@ static int omap_dss_remove(struct platform_device *pdev)
int i;
int c;
-#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
dss_uninitialize_debugfs();
-#endif
-#ifdef CONFIG_OMAP2_DSS_VENC
venc_exit();
-#endif
dispc_exit();
dpi_exit();
-#ifdef CONFIG_OMAP2_DSS_RFBI
rfbi_exit();
-#endif
if (cpu_is_omap34xx()) {
-#ifdef CONFIG_OMAP2_DSS_DSI
dsi_exit();
-#endif
-#ifdef CONFIG_OMAP2_DSS_SDI
sdi_exit();
-#endif
}
dss_exit();
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 6a74ea116d2..ef8c8529dda 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -392,7 +392,9 @@ void dss_init_device(struct platform_device *pdev,
int r;
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
#endif
@@ -413,9 +415,11 @@ void dss_init_device(struct platform_device *pdev,
}
switch (dssdev->type) {
+#ifdef CONFIG_OMAP2_DSS_DPI
case OMAP_DISPLAY_TYPE_DPI:
r = dpi_init_display(dssdev);
break;
+#endif
#ifdef CONFIG_OMAP2_DSS_RFBI
case OMAP_DISPLAY_TYPE_DBI:
r = rfbi_init_display(dssdev);
@@ -541,7 +545,10 @@ int dss_resume_all_devices(void)
static int dss_disable_device(struct device *dev, void *data)
{
struct omap_dss_device *dssdev = to_dss_device(dev);
- dssdev->driver->disable(dssdev);
+
+ if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)
+ dssdev->driver->disable(dssdev);
+
return 0;
}
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 54344184dd7..24b18258654 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -223,7 +223,13 @@ void dss_dump_clocks(struct seq_file *s)
seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
- seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
+ if (cpu_is_omap3630())
+ seq_printf(s, "dss1_alwon_fclk = %lu / %lu = %lu\n",
+ dpll4_ck_rate,
+ dpll4_ck_rate / dpll4_m4_ck_rate,
+ dss_clk_get_rate(DSS_CLK_FCK1));
+ else
+ seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
dpll4_ck_rate,
dpll4_ck_rate / dpll4_m4_ck_rate,
dss_clk_get_rate(DSS_CLK_FCK1));
@@ -293,7 +299,8 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo)
{
unsigned long prate;
- if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
+ if (cinfo->fck_div > (cpu_is_omap3630() ? 32 : 16) ||
+ cinfo->fck_div == 0)
return -EINVAL;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
@@ -329,7 +336,10 @@ int dss_get_clock_div(struct dss_clock_info *cinfo)
if (cpu_is_omap34xx()) {
unsigned long prate;
prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
- cinfo->fck_div = prate / (cinfo->fck / 2);
+ if (cpu_is_omap3630())
+ cinfo->fck_div = prate / (cinfo->fck);
+ else
+ cinfo->fck_div = prate / (cinfo->fck / 2);
} else {
cinfo->fck_div = 0;
}
@@ -402,10 +412,14 @@ retry:
goto found;
} else if (cpu_is_omap34xx()) {
- for (fck_div = 16; fck_div > 0; --fck_div) {
+ for (fck_div = (cpu_is_omap3630() ? 32 : 16);
+ fck_div > 0; --fck_div) {
struct dispc_clock_info cur_dispc;
- fck = prate / fck_div * 2;
+ if (cpu_is_omap3630())
+ fck = prate / fck_div;
+ else
+ fck = prate / fck_div * 2;
if (fck > DISPC_MAX_FCK)
continue;
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
index 24326a5fd29..786f433fd57 100644
--- a/drivers/video/omap2/dss/dss.h
+++ b/drivers/video/omap2/dss/dss.h
@@ -242,11 +242,22 @@ int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
struct dispc_clock_info *dispc_cinfo);
/* SDI */
+#ifdef CONFIG_OMAP2_DSS_SDI
int sdi_init(bool skip_init);
void sdi_exit(void);
int sdi_init_display(struct omap_dss_device *display);
+#else
+static inline int sdi_init(bool skip_init)
+{
+ return 0;
+}
+static inline void sdi_exit(void)
+{
+}
+#endif
/* DSI */
+#ifdef CONFIG_OMAP2_DSS_DSI
int dsi_init(struct platform_device *pdev);
void dsi_exit(void);
@@ -270,11 +281,30 @@ void dsi_pll_uninit(void);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high);
+#else
+static inline int dsi_init(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline void dsi_exit(void)
+{
+}
+#endif
/* DPI */
+#ifdef CONFIG_OMAP2_DSS_DPI
int dpi_init(struct platform_device *pdev);
void dpi_exit(void);
int dpi_init_display(struct omap_dss_device *dssdev);
+#else
+static inline int dpi_init(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline void dpi_exit(void)
+{
+}
+#endif
/* DISPC */
int dispc_init(void);
@@ -362,12 +392,23 @@ int dispc_get_clock_div(struct dispc_clock_info *cinfo);
/* VENC */
+#ifdef CONFIG_OMAP2_DSS_VENC
int venc_init(struct platform_device *pdev);
void venc_exit(void);
void venc_dump_regs(struct seq_file *s);
int venc_init_display(struct omap_dss_device *display);
+#else
+static inline int venc_init(struct platform_device *pdev)
+{
+ return 0;
+}
+static inline void venc_exit(void)
+{
+}
+#endif
/* RFBI */
+#ifdef CONFIG_OMAP2_DSS_RFBI
int rfbi_init(void);
void rfbi_exit(void);
void rfbi_dump_regs(struct seq_file *s);
@@ -379,6 +420,15 @@ void rfbi_transfer_area(u16 width, u16 height,
void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
unsigned long rfbi_get_max_tx_rate(void);
int rfbi_init_display(struct omap_dss_device *display);
+#else
+static inline int rfbi_init(void)
+{
+ return 0;
+}
+static inline void rfbi_exit(void)
+{
+}
+#endif
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index 0820986d4a6..9e1fbe531bf 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -843,6 +843,7 @@ static void configure_manager(enum omap_channel channel)
c = &dss_cache.manager_cache[channel];
+ dispc_set_default_color(channel, c->default_color);
dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
dispc_enable_trans_key(channel, c->trans_enabled);
dispc_enable_alpha_blending(channel, c->alpha_enabled);
@@ -940,6 +941,22 @@ static int configure_dispc(void)
return r;
}
+/* Make the coordinates even. There are some strange problems with OMAP and
+ * partial DSI update when the update widths are odd. */
+static void make_even(u16 *x, u16 *w)
+{
+ u16 x1, x2;
+
+ x1 = *x;
+ x2 = *x + *w;
+
+ x1 &= ~1;
+ x2 = ALIGN(x2, 2);
+
+ *x = x1;
+ *w = x2 - x1;
+}
+
/* Configure dispc for partial update. Return possibly modified update
* area */
void dss_setup_partial_planes(struct omap_dss_device *dssdev,
@@ -968,6 +985,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
return;
}
+ make_even(&x, &w);
+
spin_lock_irqsave(&dss_cache.lock, flags);
/* We need to show the whole overlay if it is scaled. So look for
@@ -1029,6 +1048,8 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
w = x2 - x1;
h = y2 - y1;
+ make_even(&x, &w);
+
DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
i, x, y, w, h);
}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
index 12eb4042dd8..ee07a3cc22e 100644
--- a/drivers/video/omap2/dss/sdi.c
+++ b/drivers/video/omap2/dss/sdi.c
@@ -23,13 +23,16 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
+#include <linux/regulator/consumer.h>
#include <plat/display.h>
+#include <plat/cpu.h>
#include "dss.h"
static struct {
bool skip_init;
bool update_enabled;
+ struct regulator *vdds_sdi_reg;
} sdi;
static void sdi_basic_init(void)
@@ -57,6 +60,10 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
+ r = regulator_enable(sdi.vdds_sdi_reg);
+ if (r)
+ goto err1;
+
/* In case of skip_init sdi_init has already enabled the clocks */
if (!sdi.skip_init)
dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
@@ -115,19 +122,12 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev)
dssdev->manager->enable(dssdev->manager);
- if (dssdev->driver->enable) {
- r = dssdev->driver->enable(dssdev);
- if (r)
- goto err3;
- }
-
sdi.skip_init = 0;
return 0;
-err3:
- dssdev->manager->disable(dssdev->manager);
err2:
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ regulator_disable(sdi.vdds_sdi_reg);
err1:
omap_dss_stop_device(dssdev);
err0:
@@ -137,15 +137,14 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable);
void omapdss_sdi_display_disable(struct omap_dss_device *dssdev)
{
- if (dssdev->driver->disable)
- dssdev->driver->disable(dssdev);
-
dssdev->manager->disable(dssdev->manager);
dss_sdi_disable();
dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+ regulator_disable(sdi.vdds_sdi_reg);
+
omap_dss_stop_device(dssdev);
}
EXPORT_SYMBOL(omapdss_sdi_display_disable);
@@ -162,6 +161,11 @@ int sdi_init(bool skip_init)
/* we store this for first display enable, then clear it */
sdi.skip_init = skip_init;
+ sdi.vdds_sdi_reg = dss_get_vdds_sdi();
+ if (IS_ERR(sdi.vdds_sdi_reg)) {
+ DSSERR("can't get VDDS_SDI regulator\n");
+ return PTR_ERR(sdi.vdds_sdi_reg);
+ }
/*
* Enable clocks already here, otherwise there would be a toggle
* of them until sdi_display_enable is called.
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
index f0ba5732d84..eff35050e28 100644
--- a/drivers/video/omap2/dss/venc.c
+++ b/drivers/video/omap2/dss/venc.c
@@ -479,12 +479,6 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
goto err1;
}
- if (dssdev->platform_enable) {
- r = dssdev->platform_enable(dssdev);
- if (r)
- goto err2;
- }
-
venc_power_on(dssdev);
venc.wss_data = 0;
@@ -494,13 +488,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev)
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- mutex_unlock(&venc.venc_lock);
-
- return r;
-err2:
- venc_power_off(dssdev);
err1:
mutex_unlock(&venc.venc_lock);
+
return r;
}
@@ -524,9 +514,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev)
/* wait at least 5 vsyncs after disabling the LCD */
msleep(100);
- if (dssdev->platform_disable)
- dssdev->platform_disable(dssdev);
-
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
end:
mutex_unlock(&venc.venc_lock);
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 1ffa760b854..9c7361871d7 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -183,13 +183,14 @@ int omapfb_update_window(struct fb_info *fbi,
struct omapfb2_device *fbdev = ofbi->fbdev;
int r;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
r = omapfb_update_window_nolock(fbi, x, y, w, h);
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return r;
}
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
index 62bb88f5c19..5179219128b 100644
--- a/drivers/video/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -57,7 +57,8 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
return -EINVAL;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
r = 0;
if (rot_type == ofbi->rotation_type)
@@ -105,7 +106,8 @@ static ssize_t store_mirror(struct device *dev,
if (mirror != 0 && mirror != 1)
return -EINVAL;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
ofbi->mirror = mirror;
@@ -137,8 +139,9 @@ static ssize_t show_overlays(struct device *dev,
ssize_t l = 0;
int t;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
for (t = 0; t < ofbi->num_overlays; t++) {
struct omap_overlay *ovl = ofbi->overlays[t];
@@ -154,8 +157,8 @@ static ssize_t show_overlays(struct device *dev,
l += snprintf(buf + l, PAGE_SIZE - l, "\n");
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return l;
}
@@ -195,8 +198,9 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
if (buf[len - 1] == '\n')
len = len - 1;
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
omapfb_lock(fbdev);
- lock_fb_info(fbi);
if (len > 0) {
char *p = (char *)buf;
@@ -303,8 +307,8 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
r = count;
out:
- unlock_fb_info(fbi);
omapfb_unlock(fbdev);
+ unlock_fb_info(fbi);
return r;
}
@@ -317,7 +321,8 @@ static ssize_t show_overlays_rotate(struct device *dev,
ssize_t l = 0;
int t;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
for (t = 0; t < ofbi->num_overlays; t++) {
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
@@ -345,7 +350,8 @@ static ssize_t store_overlays_rotate(struct device *dev,
if (buf[len - 1] == '\n')
len = len - 1;
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
if (len > 0) {
char *p = (char *)buf;
@@ -416,7 +422,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
- lock_fb_info(fbi);
+ if (!lock_fb_info(fbi))
+ return -ENODEV;
for (i = 0; i < ofbi->num_overlays; i++) {
if (ofbi->overlays[i]->info.enabled) {
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
index 3b1237ad85e..f6fdc2085f3 100644
--- a/drivers/video/omap2/vram.c
+++ b/drivers/video/omap2/vram.c
@@ -25,7 +25,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
-#include <linux/bootmem.h>
+#include <linux/memblock.h>
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/jiffies.h>
@@ -525,10 +525,8 @@ early_param("vram", omap_vram_early_vram);
* Called from map_io. We need to call to this early enough so that we
* can reserve the fixed SDRAM regions before VM could get hold of them.
*/
-void __init omap_vram_reserve_sdram(void)
+void __init omap_vram_reserve_sdram_memblock(void)
{
- struct bootmem_data *bdata;
- unsigned long sdram_start, sdram_size;
u32 paddr;
u32 size = 0;
@@ -555,29 +553,28 @@ void __init omap_vram_reserve_sdram(void)
size = PAGE_ALIGN(size);
- bdata = NODE_DATA(0)->bdata;
- sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
- sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
-
if (paddr) {
- if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
- paddr + size > sdram_start + sdram_size) {
+ struct memblock_property res;
+
+ res.base = paddr;
+ res.size = size;
+ if ((paddr & ~PAGE_MASK) || memblock_find(&res) ||
+ res.base != paddr || res.size != size) {
pr_err("Illegal SDRAM region for VRAM\n");
return;
}
- if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
- pr_err("FB: failed to reserve VRAM\n");
+ if (memblock_is_region_reserved(paddr, size)) {
+ pr_err("FB: failed to reserve VRAM - busy\n");
return;
}
- } else {
- if (size > sdram_size) {
- pr_err("Illegal SDRAM size for VRAM\n");
+
+ if (memblock_reserve(paddr, size) < 0) {
+ pr_err("FB: failed to reserve VRAM - no memory\n");
return;
}
-
- paddr = virt_to_phys(alloc_bootmem_pages(size));
- BUG_ON(paddr & ~PAGE_MASK);
+ } else {
+ paddr = memblock_alloc_base(size, PAGE_SIZE, MEMBLOCK_REAL_LIMIT);
}
omap_vram_add_region(paddr, size);
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 81440f2b909..6552751e81a 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -251,7 +251,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no
static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct p9100_par *par;
int linebytes, err;
@@ -353,8 +353,11 @@ static const struct of_device_id p9100_match[] = {
MODULE_DEVICE_TABLE(of, p9100_match);
static struct of_platform_driver p9100_driver = {
- .name = "p9100",
- .match_table = p9100_match,
+ .driver = {
+ .name = "p9100",
+ .owner = THIS_MODULE,
+ .of_match_table = p9100_match,
+ },
.probe = p9100_probe,
.remove = __devexit_p(p9100_remove),
};
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 8a204e7a5b5..72a1f4c0473 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -536,7 +536,7 @@ static int __init platinumfb_setup(char *options)
static int __devinit platinumfb_probe(struct of_device* odev,
const struct of_device_id *match)
{
- struct device_node *dp = odev->node;
+ struct device_node *dp = odev->dev.of_node;
struct fb_info *info;
struct fb_info_platinum *pinfo;
volatile __u8 *fbuffer;
@@ -679,8 +679,11 @@ static struct of_device_id platinumfb_match[] =
static struct of_platform_driver platinum_driver =
{
- .name = "platinumfb",
- .match_table = platinumfb_match,
+ .driver = {
+ .name = "platinumfb",
+ .owner = THIS_MODULE,
+ .of_match_table = platinumfb_match,
+ },
.probe = platinumfb_probe,
.remove = platinumfb_remove,
};
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index 0f361b6100d..0c69fa20251 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -44,7 +44,7 @@ struct pmagbafb_par {
};
-static struct fb_var_screeninfo pmagbafb_defined __initdata = {
+static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
.xres = 1024,
.yres = 864,
.xres_virtual = 1024,
@@ -68,7 +68,7 @@ static struct fb_var_screeninfo pmagbafb_defined __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbafb_fix __initdata = {
+static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = {
.id = "PMAG-BA",
.smem_len = (1024 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
@@ -142,7 +142,7 @@ static void __init pmagbafb_erase_cursor(struct fb_info *info)
}
-static int __init pmagbafb_probe(struct device *dev)
+static int __devinit pmagbafb_probe(struct device *dev)
{
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 2de0806421b..22fcb9a3d5c 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -45,7 +45,7 @@ struct pmagbbfb_par {
};
-static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
+static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = {
.bits_per_pixel = 8,
.red.length = 8,
.green.length = 8,
@@ -58,7 +58,7 @@ static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbbfb_fix __initdata = {
+static struct fb_fix_screeninfo pmagbbfb_fix __devinitdata = {
.id = "PMAGB-BA",
.smem_len = (2048 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
@@ -148,7 +148,7 @@ static void __init pmagbbfb_erase_cursor(struct fb_info *info)
/*
* Set up screen parameters.
*/
-static void __init pmagbbfb_screen_setup(struct fb_info *info)
+static void __devinit pmagbbfb_screen_setup(struct fb_info *info)
{
struct pmagbbfb_par *par = info->par;
@@ -180,9 +180,9 @@ static void __init pmagbbfb_screen_setup(struct fb_info *info)
/*
* Determine oscillator configuration.
*/
-static void __init pmagbbfb_osc_setup(struct fb_info *info)
+static void __devinit pmagbbfb_osc_setup(struct fb_info *info)
{
- static unsigned int pmagbbfb_freqs[] __initdata = {
+ static unsigned int pmagbbfb_freqs[] __devinitdata = {
130808, 119843, 104000, 92980, 74370, 72800,
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
@@ -247,7 +247,7 @@ static void __init pmagbbfb_osc_setup(struct fb_info *info)
};
-static int __init pmagbbfb_probe(struct device *dev)
+static int __devinit pmagbbfb_probe(struct device *dev)
{
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 2b094dec4a5..46b430978bc 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -631,7 +631,7 @@ static struct fb_ops s3c2410fb_ops = {
* cache. Once this area is remapped, all virtual memory
* access to the video memory should occur at the new region.
*/
-static int __init s3c2410fb_map_video_memory(struct fb_info *info)
+static int __devinit s3c2410fb_map_video_memory(struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
dma_addr_t map_dma;
@@ -814,7 +814,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
static char driver_name[] = "s3c2410fb";
-static int __init s3c24xxfb_probe(struct platform_device *pdev,
+static int __devinit s3c24xxfb_probe(struct platform_device *pdev,
enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
@@ -1018,7 +1018,7 @@ static int __devinit s3c2412fb_probe(struct platform_device *pdev)
/*
* Cleanup
*/
-static int s3c2410fb_remove(struct platform_device *pdev)
+static int __devexit s3c2410fb_remove(struct platform_device *pdev)
{
struct fb_info *fbinfo = platform_get_drvdata(pdev);
struct s3c2410fb_info *info = fbinfo->par;
@@ -1096,7 +1096,7 @@ static int s3c2410fb_resume(struct platform_device *dev)
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
- .remove = s3c2410fb_remove,
+ .remove = __devexit_p(s3c2410fb_remove),
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
@@ -1107,7 +1107,7 @@ static struct platform_driver s3c2410fb_driver = {
static struct platform_driver s3c2412fb_driver = {
.probe = s3c2412fb_probe,
- .remove = s3c2410fb_remove,
+ .remove = __devexit_p(s3c2410fb_remove),
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index d4471b4c037..dce8c97b433 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -71,7 +71,8 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
"S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX",
"S3 Plato/PX", "S3 Aurora64VP", "S3 Virge",
"S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
- "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P"};
+ "S3 Virge/GX2", "S3 Virge/GX2P", "S3 Virge/GX2P",
+ "S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X"};
#define CHIP_UNKNOWN 0x00
#define CHIP_732_TRIO32 0x01
@@ -89,10 +90,14 @@ static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64",
#define CHIP_356_VIRGE_GX2 0x0D
#define CHIP_357_VIRGE_GX2P 0x0E
#define CHIP_359_VIRGE_GX2P 0x0F
+#define CHIP_360_TRIO3D_1X 0x10
+#define CHIP_362_TRIO3D_2X 0x11
+#define CHIP_368_TRIO3D_2X 0x12
#define CHIP_XXX_TRIO 0x80
#define CHIP_XXX_TRIO64V2_DXGX 0x81
#define CHIP_XXX_VIRGE_DXGX 0x82
+#define CHIP_36X_TRIO3D_1X_2X 0x83
#define CHIP_UNDECIDED_FLAG 0x80
#define CHIP_MASK 0xFF
@@ -324,6 +329,7 @@ static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
{
+ struct s3fb_info *par = info->par;
u16 m, n, r;
u8 regval;
int rv;
@@ -339,7 +345,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
/* Set S3 clock registers */
- vga_wseq(NULL, 0x12, ((n - 2) | (r << 5)));
+ if (par->chip == CHIP_360_TRIO3D_1X ||
+ par->chip == CHIP_362_TRIO3D_2X ||
+ par->chip == CHIP_368_TRIO3D_2X) {
+ vga_wseq(NULL, 0x12, (n - 2) | ((r & 3) << 6)); /* n and two bits of r */
+ vga_wseq(NULL, 0x29, r >> 2); /* remaining highest bit of r */
+ } else
+ vga_wseq(NULL, 0x12, (n - 2) | (r << 5));
vga_wseq(NULL, 0x13, m - 2);
udelay(1000);
@@ -456,7 +468,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
static int s3fb_set_par(struct fb_info *info)
{
struct s3fb_info *par = info->par;
- u32 value, mode, hmul, offset_value, screen_size, multiplex;
+ u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
u32 bpp = info->var.bits_per_pixel;
if (bpp != 0) {
@@ -518,7 +530,7 @@ static int s3fb_set_par(struct fb_info *info)
svga_wcrt_mask(0x33, 0x00, 0x08); /* no DDR ? */
svga_wcrt_mask(0x43, 0x00, 0x01); /* no DDR ? */
- svga_wcrt_mask(0x5D, 0x00, 0x28); // Clear strange HSlen bits
+ svga_wcrt_mask(0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
/* svga_wcrt_mask(0x58, 0x03, 0x03); */
@@ -530,10 +542,14 @@ static int s3fb_set_par(struct fb_info *info)
pr_debug("fb%d: offset register : %d\n", info->node, offset_value);
svga_wcrt_multi(s3_offset_regs, offset_value);
- vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
- vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
- vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
- vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+ if (par->chip != CHIP_360_TRIO3D_1X &&
+ par->chip != CHIP_362_TRIO3D_2X &&
+ par->chip != CHIP_368_TRIO3D_2X) {
+ vga_wcrt(NULL, 0x54, 0x18); /* M parameter */
+ vga_wcrt(NULL, 0x60, 0xff); /* N parameter */
+ vga_wcrt(NULL, 0x61, 0xff); /* L parameter */
+ vga_wcrt(NULL, 0x62, 0xff); /* L parameter */
+ }
vga_wcrt(NULL, 0x3A, 0x35);
svga_wattr(0x33, 0x00);
@@ -570,6 +586,16 @@ static int s3fb_set_par(struct fb_info *info)
vga_wcrt(NULL, 0x66, 0x90);
}
+ if (par->chip == CHIP_360_TRIO3D_1X ||
+ par->chip == CHIP_362_TRIO3D_2X ||
+ par->chip == CHIP_368_TRIO3D_2X) {
+ dbytes = info->var.xres * ((bpp+7)/8);
+ vga_wcrt(NULL, 0x91, (dbytes + 7) / 8);
+ vga_wcrt(NULL, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
+
+ vga_wcrt(NULL, 0x66, 0x81);
+ }
+
svga_wcrt_mask(0x31, 0x00, 0x40);
multiplex = 0;
hmul = 1;
@@ -615,11 +641,13 @@ static int s3fb_set_par(struct fb_info *info)
break;
case 3:
pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
- if (info->var.pixclock > 20000) {
- svga_wcrt_mask(0x50, 0x00, 0x30);
+ svga_wcrt_mask(0x50, 0x00, 0x30);
+ if (info->var.pixclock > 20000 ||
+ par->chip == CHIP_360_TRIO3D_1X ||
+ par->chip == CHIP_362_TRIO3D_2X ||
+ par->chip == CHIP_368_TRIO3D_2X)
svga_wcrt_mask(0x67, 0x00, 0xF0);
- } else {
- svga_wcrt_mask(0x50, 0x00, 0x30);
+ else {
svga_wcrt_mask(0x67, 0x10, 0xF0);
multiplex = 1;
}
@@ -634,7 +662,10 @@ static int s3fb_set_par(struct fb_info *info)
} else {
svga_wcrt_mask(0x50, 0x10, 0x30);
svga_wcrt_mask(0x67, 0x30, 0xF0);
- hmul = 2;
+ if (par->chip != CHIP_360_TRIO3D_1X &&
+ par->chip != CHIP_362_TRIO3D_2X &&
+ par->chip != CHIP_368_TRIO3D_2X)
+ hmul = 2;
}
break;
case 5:
@@ -647,7 +678,10 @@ static int s3fb_set_par(struct fb_info *info)
} else {
svga_wcrt_mask(0x50, 0x10, 0x30);
svga_wcrt_mask(0x67, 0x50, 0xF0);
- hmul = 2;
+ if (par->chip != CHIP_360_TRIO3D_1X &&
+ par->chip != CHIP_362_TRIO3D_2X &&
+ par->chip != CHIP_368_TRIO3D_2X)
+ hmul = 2;
}
break;
case 6:
@@ -866,6 +900,17 @@ static int __devinit s3_identification(int chip)
return CHIP_385_VIRGE_GX;
}
+ if (chip == CHIP_36X_TRIO3D_1X_2X) {
+ switch (vga_rcrt(NULL, 0x2f)) {
+ case 0x00:
+ return CHIP_360_TRIO3D_1X;
+ case 0x01:
+ return CHIP_362_TRIO3D_2X;
+ case 0x02:
+ return CHIP_368_TRIO3D_2X;
+ }
+ }
+
return CHIP_UNKNOWN;
}
@@ -930,17 +975,32 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i
vga_wcrt(NULL, 0x38, 0x48);
vga_wcrt(NULL, 0x39, 0xA5);
- /* Find how many physical memory there is on card */
- /* 0x36 register is accessible even if other registers are locked */
- regval = vga_rcrt(NULL, 0x36);
- info->screen_size = s3_memsizes[regval >> 5] << 10;
- info->fix.smem_len = info->screen_size;
-
+ /* Identify chip type */
par->chip = id->driver_data & CHIP_MASK;
par->rev = vga_rcrt(NULL, 0x2f);
if (par->chip & CHIP_UNDECIDED_FLAG)
par->chip = s3_identification(par->chip);
+ /* Find how many physical memory there is on card */
+ /* 0x36 register is accessible even if other registers are locked */
+ regval = vga_rcrt(NULL, 0x36);
+ if (par->chip == CHIP_360_TRIO3D_1X ||
+ par->chip == CHIP_362_TRIO3D_2X ||
+ par->chip == CHIP_368_TRIO3D_2X) {
+ switch ((regval & 0xE0) >> 5) {
+ case 0: /* 8MB -- only 4MB usable for display */
+ case 1: /* 4MB with 32-bit bus */
+ case 2: /* 4MB */
+ info->screen_size = 4 << 20;
+ break;
+ case 6: /* 2MB */
+ info->screen_size = 2 << 20;
+ break;
+ }
+ } else
+ info->screen_size = s3_memsizes[regval >> 5] << 10;
+ info->fix.smem_len = info->screen_size;
+
/* Find MCLK frequency */
regval = vga_rseq(NULL, 0x10);
par->mclk_freq = ((vga_rseq(NULL, 0x11) + 2) * 14318) / ((regval & 0x1F) + 2);
@@ -1131,6 +1191,7 @@ static struct pci_device_id s3_devices[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_356_VIRGE_GX2},
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_357_VIRGE_GX2P},
{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
+ {PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
{0, 0, 0, 0, 0, 0, 0}
};
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index 7a3a5e28eca..53455f29551 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -47,7 +47,7 @@ static int ywrap = 0;
static int flatpanel_id = -1;
-static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
+static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
.id = "SGI Vis WS FB",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -57,7 +57,7 @@ static struct fb_fix_screeninfo sgivwfb_fix __initdata = {
.line_length = 640,
};
-static struct fb_var_screeninfo sgivwfb_var __initdata = {
+static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
/* 640x480, 8 bpp */
.xres = 640,
.yres = 480,
@@ -79,7 +79,7 @@ static struct fb_var_screeninfo sgivwfb_var __initdata = {
.vmode = FB_VMODE_NONINTERLACED
};
-static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = {
+static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
@@ -825,7 +825,7 @@ fail_ioremap_regs:
return -ENXIO;
}
-static int sgivwfb_remove(struct platform_device *dev)
+static int __devexit sgivwfb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
@@ -845,7 +845,7 @@ static int sgivwfb_remove(struct platform_device *dev)
static struct platform_driver sgivwfb_driver = {
.probe = sgivwfb_probe,
- .remove = sgivwfb_remove,
+ .remove = __devexit_p(sgivwfb_remove),
.driver = {
.name = "sgivwfb",
},
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e8c76994481..12c451a711e 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -991,13 +991,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->ch[j].lcdc = priv;
memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
- error = sh_mobile_lcdc_check_interface(&priv->ch[i]);
+ error = sh_mobile_lcdc_check_interface(&priv->ch[j]);
if (error) {
dev_err(&pdev->dev, "unsupported interface type\n");
goto err1;
}
- init_waitqueue_head(&priv->ch[i].frame_end_wait);
- init_completion(&priv->ch[i].vsync_completion);
+ init_waitqueue_head(&priv->ch[j].frame_end_wait);
+ init_completion(&priv->ch[j].vsync_completion);
priv->ch[j].pan_offset = 0;
switch (pdata->ch[i].chan) {
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index a531a0f7cdf..559bf1727a2 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1845,7 +1845,7 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, ivideo->myid);
+ strlcpy(fix->id, ivideo->myid, sizeof(fix->id));
mutex_lock(&info->mm_lock);
fix->smem_start = ivideo->video_base + ivideo->video_offset;
diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c
index 23e69e834a1..489b44e8db8 100644
--- a/drivers/video/sunxvr1000.c
+++ b/drivers/video/sunxvr1000.c
@@ -114,7 +114,7 @@ static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
static int __devinit gfb_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct gfb_info *gp;
int err;
@@ -199,10 +199,13 @@ static const struct of_device_id gfb_match[] = {
MODULE_DEVICE_TABLE(of, ffb_match);
static struct of_platform_driver gfb_driver = {
- .name = "gfb",
- .match_table = gfb_match,
.probe = gfb_probe,
.remove = __devexit_p(gfb_remove),
+ .driver = {
+ .name = "gfb",
+ .owner = THIS_MODULE,
+ .of_match_table = gfb_match,
+ },
};
static int __init gfb_init(void)
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index c0c2b18fcdc..cc039b33d2d 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -365,7 +365,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit tcx_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct tcx_par *par;
int linebytes, i, err;
@@ -512,8 +512,11 @@ static const struct of_device_id tcx_match[] = {
MODULE_DEVICE_TABLE(of, tcx_match);
static struct of_platform_driver tcx_driver = {
- .name = "tcx",
- .match_table = tcx_match,
+ .driver = {
+ .name = "tcx",
+ .owner = THIS_MODULE,
+ .of_match_table = tcx_match,
+ },
.probe = tcx_probe,
.remove = __devexit_p(tcx_remove),
};
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 0cadf7aee27..090aa1a9be6 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -177,7 +177,7 @@ static void vesafb_destroy(struct fb_info *info)
{
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(info->aperture_base, info->aperture_size);
+ release_mem_region(info->apertures->ranges[0].base, info->apertures->ranges[0].size);
framebuffer_release(info);
}
@@ -295,8 +295,13 @@ static int __init vesafb_probe(struct platform_device *dev)
info->par = NULL;
/* set vesafb aperture size for generic probing */
- info->aperture_base = screen_info.lfb_base;
- info->aperture_size = size_total;
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ err = -ENOMEM;
+ goto err;
+ }
+ info->apertures->ranges[0].base = screen_info.lfb_base;
+ info->apertures->ranges[0].size = size_total;
info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
if (!info->screen_base) {
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 9b5532b4de3..bc67251f1a2 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -78,7 +78,7 @@ static void rvfree(void *mem, unsigned long size)
vfree(mem);
}
-static struct fb_var_screeninfo vfb_default __initdata = {
+static struct fb_var_screeninfo vfb_default __devinitdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
@@ -100,7 +100,7 @@ static struct fb_var_screeninfo vfb_default __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo vfb_fix __initdata = {
+static struct fb_fix_screeninfo vfb_fix __devinitdata = {
.id = "Virtual FB",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index bf638a47a5b..28ccab44a39 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -65,7 +65,7 @@ struct vga16fb_par {
/* --------------------------------------------------------------------- */
-static struct fb_var_screeninfo vga16fb_defined __initdata = {
+static struct fb_var_screeninfo vga16fb_defined __devinitdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
@@ -85,7 +85,7 @@ static struct fb_var_screeninfo vga16fb_defined __initdata = {
};
/* name should not depend on EGA/VGA */
-static struct fb_fix_screeninfo vga16fb_fix __initdata = {
+static struct fb_fix_screeninfo vga16fb_fix __devinitdata = {
.id = "VGA16 VGA",
.smem_start = VGA_FB_PHYS,
.smem_len = VGA_FB_PHYS_LEN,
@@ -1263,10 +1263,19 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
vga_imageblit_color(info, image);
}
+static void vga16fb_destroy(struct fb_info *info)
+{
+ iounmap(info->screen_base);
+ fb_dealloc_cmap(&info->cmap);
+ /* XXX unshare VGA regions */
+ framebuffer_release(info);
+}
+
static struct fb_ops vga16fb_ops = {
.owner = THIS_MODULE,
.fb_open = vga16fb_open,
.fb_release = vga16fb_release,
+ .fb_destroy = vga16fb_destroy,
.fb_check_var = vga16fb_check_var,
.fb_set_par = vga16fb_set_par,
.fb_setcolreg = vga16fb_setcolreg,
@@ -1278,7 +1287,7 @@ static struct fb_ops vga16fb_ops = {
};
#ifndef MODULE
-static int vga16fb_setup(char *options)
+static int __init vga16fb_setup(char *options)
{
char *this_opt;
@@ -1306,6 +1315,11 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
ret = -ENOMEM;
goto err_fb_alloc;
}
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
/* XXX share VGA_FB_PHYS and I/O region with vgacon and others */
info->screen_base = (void __iomem *)VGA_MAP_MEM(VGA_FB_PHYS, 0);
@@ -1335,7 +1349,7 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
info->fix = vga16fb_fix;
/* supports rectangles with widths of multiples of 8 */
info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
- info->flags = FBINFO_FLAG_DEFAULT |
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
FBINFO_HWACCEL_YPAN;
i = (info->var.bits_per_pixel == 8) ? 256 : 16;
@@ -1354,6 +1368,9 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
vga16fb_update_fix(info);
+ info->apertures->ranges[0].base = VGA_FB_PHYS;
+ info->apertures->ranges[0].size = VGA_FB_PHYS_LEN;
+
if (register_framebuffer(info) < 0) {
printk(KERN_ERR "vga16fb: unable to register framebuffer\n");
ret = -EINVAL;
@@ -1376,24 +1393,19 @@ static int __devinit vga16fb_probe(struct platform_device *dev)
return ret;
}
-static int vga16fb_remove(struct platform_device *dev)
+static int __devexit vga16fb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
- if (info) {
+ if (info)
unregister_framebuffer(info);
- iounmap(info->screen_base);
- fb_dealloc_cmap(&info->cmap);
- /* XXX unshare VGA regions */
- framebuffer_release(info);
- }
return 0;
}
static struct platform_driver vga16fb_driver = {
.probe = vga16fb_probe,
- .remove = vga16fb_remove,
+ .remove = __devexit_p(vga16fb_remove),
.driver = {
.name = "vga16fb",
},
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index eeed238ad6a..d496adb0f83 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -4,4 +4,6 @@
obj-$(CONFIG_FB_VIA) += viafb.o
-viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
+viafb-y :=viafbdev.o hw.o via_i2c.o dvi.o lcd.o ioctl.o accel.o \
+ via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o \
+ via-core.o via-gpio.o via_modesetting.o
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index d5077dfa9e0..e44893ea590 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -18,14 +18,45 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
#include "global.h"
+/*
+ * Figure out an appropriate bytes-per-pixel setting.
+ */
+static int viafb_set_bpp(void __iomem *engine, u8 bpp)
+{
+ u32 gemode;
+
+ /* Preserve the reserved bits */
+ /* Lowest 2 bits to zero gives us no rotation */
+ gemode = readl(engine + VIA_REG_GEMODE) & 0xfffffcfc;
+ switch (bpp) {
+ case 8:
+ gemode |= VIA_GEM_8bpp;
+ break;
+ case 16:
+ gemode |= VIA_GEM_16bpp;
+ break;
+ case 32:
+ gemode |= VIA_GEM_32bpp;
+ break;
+ default:
+ printk(KERN_WARNING "viafb_set_bpp: Unsupported bpp %d\n", bpp);
+ return -EINVAL;
+ }
+ writel(gemode, engine + VIA_REG_GEMODE);
+ return 0;
+}
+
+
static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
u8 dst_bpp, u32 dst_addr, u32 dst_pitch, u32 dst_x, u32 dst_y,
u32 *src_mem, u32 src_addr, u32 src_pitch, u32 src_x, u32 src_y,
u32 fg_color, u32 bg_color, u8 fill_rop)
{
u32 ge_cmd = 0, tmp, i;
+ int ret;
if (!op || op > 3) {
printk(KERN_WARNING "hw_bitblt_1: Invalid operation: %d\n", op);
@@ -59,22 +90,9 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
}
}
- switch (dst_bpp) {
- case 8:
- tmp = 0x00000000;
- break;
- case 16:
- tmp = 0x00000100;
- break;
- case 32:
- tmp = 0x00000300;
- break;
- default:
- printk(KERN_WARNING "hw_bitblt_1: Unsupported bpp %d\n",
- dst_bpp);
- return -EINVAL;
- }
- writel(tmp, engine + 0x04);
+ ret = viafb_set_bpp(engine, dst_bpp);
+ if (ret)
+ return ret;
if (op != VIA_BITBLT_FILL) {
if (src_x & (op == VIA_BITBLT_MONO ? 0xFFFF8000 : 0xFFFFF000)
@@ -171,6 +189,7 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
u32 fg_color, u32 bg_color, u8 fill_rop)
{
u32 ge_cmd = 0, tmp, i;
+ int ret;
if (!op || op > 3) {
printk(KERN_WARNING "hw_bitblt_2: Invalid operation: %d\n", op);
@@ -204,22 +223,9 @@ static int hw_bitblt_2(void __iomem *engine, u8 op, u32 width, u32 height,
}
}
- switch (dst_bpp) {
- case 8:
- tmp = 0x00000000;
- break;
- case 16:
- tmp = 0x00000100;
- break;
- case 32:
- tmp = 0x00000300;
- break;
- default:
- printk(KERN_WARNING "hw_bitblt_2: Unsupported bpp %d\n",
- dst_bpp);
- return -EINVAL;
- }
- writel(tmp, engine + 0x04);
+ ret = viafb_set_bpp(engine, dst_bpp);
+ if (ret)
+ return ret;
if (op == VIA_BITBLT_FILL)
tmp = 0;
@@ -312,17 +318,29 @@ int viafb_init_engine(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
void __iomem *engine;
+ int highest_reg, i;
u32 vq_start_addr, vq_end_addr, vq_start_low, vq_end_low, vq_high,
vq_len, chip_name = viapar->shared->chip_info.gfx_chip_name;
- engine = ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
- viapar->shared->engine_mmio = engine;
+ engine = viapar->shared->vdev->engine_mmio;
if (!engine) {
printk(KERN_WARNING "viafb_init_accel: ioremap failed, "
"hardware acceleration disabled\n");
return -ENOMEM;
}
+ /* Initialize registers to reset the 2D engine */
+ switch (viapar->shared->chip_info.twod_engine) {
+ case VIA_2D_ENG_M1:
+ highest_reg = 0x5c;
+ break;
+ default:
+ highest_reg = 0x40;
+ break;
+ }
+ for (i = 0; i <= highest_reg; i += 4)
+ writel(0x0, engine + i);
+
switch (chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
@@ -352,13 +370,28 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;
- /* Init 2D engine reg to reset 2D engine */
- writel(0x0, engine + VIA_REG_KEYCONTROL);
+#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+ /*
+ * Set aside a chunk of framebuffer memory for the camera
+ * driver. Someday this driver probably needs a proper allocator
+ * for fbmem; for now, we just have to do this before the
+ * framebuffer initializes itself.
+ *
+ * As for the size: the engine can handle three frames,
+ * 16 bits deep, up to VGA resolution.
+ */
+ viapar->shared->vdev->camera_fbmem_size = 3*VGA_HEIGHT*VGA_WIDTH*2;
+ viapar->fbmem_free -= viapar->shared->vdev->camera_fbmem_size;
+ viapar->fbmem_used += viapar->shared->vdev->camera_fbmem_size;
+ viapar->shared->vdev->camera_fbmem_offset = viapar->fbmem_free;
+#endif
/* Init AGP and VQ regs */
switch (chip_name) {
case UNICHROME_K8M890:
case UNICHROME_P4M900:
+ case UNICHROME_VX800:
+ case UNICHROME_VX855:
writel(0x00100000, engine + VIA_REG_CR_TRANSET);
writel(0x680A0000, engine + VIA_REG_CR_TRANSPACE);
writel(0x02000000, engine + VIA_REG_CR_TRANSPACE);
@@ -393,6 +426,8 @@ int viafb_init_engine(struct fb_info *info)
switch (chip_name) {
case UNICHROME_K8M890:
case UNICHROME_P4M900:
+ case UNICHROME_VX800:
+ case UNICHROME_VX855:
vq_start_low |= 0x20000000;
vq_end_low |= 0x20000000;
vq_high |= 0x20000000;
@@ -446,7 +481,7 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
struct viafb_par *viapar = info->par;
u32 temp, iga_path = viapar->iga_path;
- temp = readl(viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
+ temp = readl(viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
switch (Status) {
case HW_Cursor_ON:
temp |= 0x1;
@@ -463,23 +498,33 @@ void viafb_show_hw_cursor(struct fb_info *info, int Status)
default:
temp &= 0x7FFFFFFF;
}
- writel(temp, viapar->shared->engine_mmio + VIA_REG_CURSOR_MODE);
+ writel(temp, viapar->shared->vdev->engine_mmio + VIA_REG_CURSOR_MODE);
}
void viafb_wait_engine_idle(struct fb_info *info)
{
struct viafb_par *viapar = info->par;
int loop = 0;
-
- while (!(readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
- VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
- loop++;
- cpu_relax();
+ u32 mask;
+ void __iomem *engine = viapar->shared->vdev->engine_mmio;
+
+ switch (viapar->shared->chip_info.twod_engine) {
+ case VIA_2D_ENG_H5:
+ case VIA_2D_ENG_M1:
+ mask = VIA_CMD_RGTR_BUSY_M1 | VIA_2D_ENG_BUSY_M1 |
+ VIA_3D_ENG_BUSY_M1;
+ break;
+ default:
+ while (!(readl(engine + VIA_REG_STATUS) &
+ VIA_VR_QUEUE_BUSY) && (loop < MAXLOOP)) {
+ loop++;
+ cpu_relax();
+ }
+ mask = VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY;
+ break;
}
- while ((readl(viapar->shared->engine_mmio + VIA_REG_STATUS) &
- (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
- (loop < MAXLOOP)) {
+ while ((readl(engine + VIA_REG_STATUS) & mask) && (loop < MAXLOOP)) {
loop++;
cpu_relax();
}
diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h
index 615c84ad0f0..2c122d29236 100644
--- a/drivers/video/via/accel.h
+++ b/drivers/video/via/accel.h
@@ -67,6 +67,34 @@
/* from 0x100 to 0x1ff */
#define VIA_REG_COLORPAT 0x100
+/* defines for VIA 2D registers for vt3353/3409 (M1 engine)*/
+#define VIA_REG_GECMD_M1 0x000
+#define VIA_REG_GEMODE_M1 0x004
+#define VIA_REG_GESTATUS_M1 0x004 /* as same as VIA_REG_GEMODE */
+#define VIA_REG_PITCH_M1 0x008 /* pitch of src and dst */
+#define VIA_REG_DIMENSION_M1 0x00C /* width and height */
+#define VIA_REG_DSTPOS_M1 0x010
+#define VIA_REG_LINE_XY_M1 0x010
+#define VIA_REG_DSTBASE_M1 0x014
+#define VIA_REG_SRCPOS_M1 0x018
+#define VIA_REG_LINE_K1K2_M1 0x018
+#define VIA_REG_SRCBASE_M1 0x01C
+#define VIA_REG_PATADDR_M1 0x020
+#define VIA_REG_MONOPAT0_M1 0x024
+#define VIA_REG_MONOPAT1_M1 0x028
+#define VIA_REG_OFFSET_M1 0x02C
+#define VIA_REG_LINE_ERROR_M1 0x02C
+#define VIA_REG_CLIPTL_M1 0x040 /* top and left of clipping */
+#define VIA_REG_CLIPBR_M1 0x044 /* bottom and right of clipping */
+#define VIA_REG_KEYCONTROL_M1 0x048 /* color key control */
+#define VIA_REG_FGCOLOR_M1 0x04C
+#define VIA_REG_DSTCOLORKEY_M1 0x04C /* as same as VIA_REG_FG */
+#define VIA_REG_BGCOLOR_M1 0x050
+#define VIA_REG_SRCCOLORKEY_M1 0x050 /* as same as VIA_REG_BG */
+#define VIA_REG_MONOPATFGC_M1 0x058 /* Add BG color of Pattern. */
+#define VIA_REG_MONOPATBGC_M1 0x05C /* Add FG color of Pattern. */
+#define VIA_REG_COLORPAT_M1 0x100 /* from 0x100 to 0x1ff */
+
/* VIA_REG_PITCH(0x38): Pitch Setting */
#define VIA_PITCH_ENABLE 0x80000000
@@ -157,6 +185,18 @@
/* Virtual Queue is busy */
#define VIA_VR_QUEUE_BUSY 0x00020000
+/* VIA_REG_STATUS(0x400): Engine Status for H5 */
+#define VIA_CMD_RGTR_BUSY_H5 0x00000010 /* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY_H5 0x00000002 /* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY_H5 0x00001FE1 /* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY_H5 0x00000004 /* Virtual Queue is busy */
+
+/* VIA_REG_STATUS(0x400): Engine Status for VT3353/3409 */
+#define VIA_CMD_RGTR_BUSY_M1 0x00000010 /* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY_M1 0x00000002 /* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY_M1 0x00001FE1 /* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY_M1 0x00000004 /* Virtual Queue is busy */
+
#define MAXLOOP 0xFFFFFF
#define VIA_BITBLT_COLOR 1
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
index 8c06bd3c0b4..d9b6e06e070 100644
--- a/drivers/video/via/chip.h
+++ b/drivers/video/via/chip.h
@@ -121,9 +121,17 @@ struct lvds_chip_information {
int i2c_port;
};
+/* The type of 2D engine */
+enum via_2d_engine {
+ VIA_2D_ENG_H2,
+ VIA_2D_ENG_H5,
+ VIA_2D_ENG_M1,
+};
+
struct chip_information {
int gfx_chip_name;
int gfx_chip_revision;
+ enum via_2d_engine twod_engine;
struct tmds_chip_information tmds_chip_info;
struct lvds_chip_information lvds_chip_info;
struct lvds_chip_information lvds_chip_info2;
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index abe59b8c7a0..39b040bb381 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -18,6 +18,8 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
#include "global.h"
static void tmds_register_write(int index, u8 data);
@@ -96,7 +98,7 @@ int viafb_tmds_trasmitter_identify(void)
viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
viaparinfo->chip_info->
tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
- viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX;
+ viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_31;
if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) {
/*
* Currently only support 12bits,dual edge,add 24bits mode later
@@ -110,7 +112,7 @@ int viafb_tmds_trasmitter_identify(void)
viaparinfo->chip_info->tmds_chip_info.i2c_port);
return OK;
} else {
- viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX;
+ viaparinfo->chip_info->tmds_chip_info.i2c_port = VIA_PORT_2C;
if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)
!= FAIL) {
tmds_register_write(0x08, 0x3b);
@@ -160,32 +162,26 @@ int viafb_tmds_trasmitter_identify(void)
static void tmds_register_write(int index, u8 data)
{
- viaparinfo->shared->i2c_stuff.i2c_port =
- viaparinfo->chip_info->tmds_chip_info.i2c_port;
-
- viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.
- tmds_chip_slave_addr, index,
- data);
+ viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+ index, data);
}
static int tmds_register_read(int index)
{
u8 data;
- viaparinfo->shared->i2c_stuff.i2c_port =
- viaparinfo->chip_info->tmds_chip_info.i2c_port;
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->
- tmds_chip_info.tmds_chip_slave_addr,
- (u8) index, &data);
+ viafb_i2c_readbyte(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+ (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+ (u8) index, &data);
return data;
}
static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
{
- viaparinfo->shared->i2c_stuff.i2c_port =
- viaparinfo->chip_info->tmds_chip_info.i2c_port;
- viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info.
- tmds_chip_slave_addr, (u8) index, buff, buff_len);
+ viafb_i2c_readbytes(viaparinfo->chip_info->tmds_chip_info.i2c_port,
+ (u8) viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr,
+ (u8) index, buff, buff_len);
return 0;
}
@@ -541,9 +537,10 @@ void viafb_dvi_enable(void)
else
data = 0x37;
viafb_i2c_writebyte(viaparinfo->chip_info->
- tmds_chip_info.
- tmds_chip_slave_addr,
- 0x08, data);
+ tmds_chip_info.i2c_port,
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_slave_addr,
+ 0x08, data);
}
}
}
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
index 8d95d5fd138..28221a062dd 100644
--- a/drivers/video/via/global.h
+++ b/drivers/video/via/global.h
@@ -41,7 +41,6 @@
#include "share.h"
#include "dvi.h"
#include "viamode.h"
-#include "via_i2c.h"
#include "hw.h"
#include "lcd.h"
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index f2583b1b527..b996803ae2c 100644
--- a/drivers/video/via/hw.c
+++ b/drivers/video/via/hw.c
@@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
#include "global.h"
static struct pll_map pll_value[] = {
@@ -62,6 +63,7 @@ static struct pll_map pll_value[] = {
CX700_52_977M, VX855_52_977M},
{CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M,
CX700_56_250M, VX855_56_250M},
+ {CLK_57_275M, 0, 0, 0, VX855_57_275M},
{CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M,
CX700_60_466M, VX855_60_466M},
{CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M,
@@ -525,8 +527,7 @@ static void dvi_patch_skew_dvp_low(void);
static void set_dvi_output_path(int set_iga, int output_interface);
static void set_lcd_output_path(int set_iga, int output_interface);
static void load_fix_bit_crtc_reg(void);
-static void init_gfx_chip_info(struct pci_dev *pdev,
- const struct pci_device_id *pdi);
+static void init_gfx_chip_info(int chip_type);
static void init_tmds_chip_info(void);
static void init_lvds_chip_info(void);
static void device_screen_off(void);
@@ -537,18 +538,6 @@ static void device_on(void);
static void enable_second_display_channel(void);
static void disable_second_display_channel(void);
-void viafb_write_reg(u8 index, u16 io_port, u8 data)
-{
- outb(index, io_port);
- outb(data, io_port + 1);
- /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */
-}
-u8 viafb_read_reg(int io_port, u8 index)
-{
- outb(index, io_port);
- return inb(io_port + 1);
-}
-
void viafb_lock_crt(void)
{
viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7);
@@ -560,16 +549,6 @@ void viafb_unlock_crt(void)
viafb_write_reg_mask(CR47, VIACR, 0, BIT0);
}
-void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask)
-{
- u8 tmp;
-
- outb(index, io_port);
- tmp = inb(io_port + 1);
- outb((data & mask) | (tmp & (~mask)), io_port + 1);
- /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */
-}
-
void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
{
outb(index, LUT_INDEX_WRITE);
@@ -646,102 +625,6 @@ void viafb_set_iga_path(void)
}
}
-void viafb_set_primary_address(u32 addr)
-{
- DEBUG_MSG(KERN_DEBUG "viafb_set_primary_address(0x%08X)\n", addr);
- viafb_write_reg(CR0D, VIACR, addr & 0xFF);
- viafb_write_reg(CR0C, VIACR, (addr >> 8) & 0xFF);
- viafb_write_reg(CR34, VIACR, (addr >> 16) & 0xFF);
- viafb_write_reg_mask(CR48, VIACR, (addr >> 24) & 0x1F, 0x1F);
-}
-
-void viafb_set_secondary_address(u32 addr)
-{
- DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_address(0x%08X)\n", addr);
- /* secondary display supports only quadword aligned memory */
- viafb_write_reg_mask(CR62, VIACR, (addr >> 2) & 0xFE, 0xFE);
- viafb_write_reg(CR63, VIACR, (addr >> 10) & 0xFF);
- viafb_write_reg(CR64, VIACR, (addr >> 18) & 0xFF);
- viafb_write_reg_mask(CRA3, VIACR, (addr >> 26) & 0x07, 0x07);
-}
-
-void viafb_set_primary_pitch(u32 pitch)
-{
- DEBUG_MSG(KERN_DEBUG "viafb_set_primary_pitch(0x%08X)\n", pitch);
- /* spec does not say that first adapter skips 3 bits but old
- * code did it and seems to be reasonable in analogy to 2nd adapter
- */
- pitch = pitch >> 3;
- viafb_write_reg(0x13, VIACR, pitch & 0xFF);
- viafb_write_reg_mask(0x35, VIACR, (pitch >> (8 - 5)) & 0xE0, 0xE0);
-}
-
-void viafb_set_secondary_pitch(u32 pitch)
-{
- DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_pitch(0x%08X)\n", pitch);
- pitch = pitch >> 3;
- viafb_write_reg(0x66, VIACR, pitch & 0xFF);
- viafb_write_reg_mask(0x67, VIACR, (pitch >> 8) & 0x03, 0x03);
- viafb_write_reg_mask(0x71, VIACR, (pitch >> (10 - 7)) & 0x80, 0x80);
-}
-
-void viafb_set_primary_color_depth(u8 depth)
-{
- u8 value;
-
- DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth);
- switch (depth) {
- case 8:
- value = 0x00;
- break;
- case 15:
- value = 0x04;
- break;
- case 16:
- value = 0x14;
- break;
- case 24:
- value = 0x0C;
- break;
- case 30:
- value = 0x08;
- break;
- default:
- printk(KERN_WARNING "viafb_set_primary_color_depth: "
- "Unsupported depth: %d\n", depth);
- return;
- }
-
- viafb_write_reg_mask(0x15, VIASR, value, 0x1C);
-}
-
-void viafb_set_secondary_color_depth(u8 depth)
-{
- u8 value;
-
- DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth);
- switch (depth) {
- case 8:
- value = 0x00;
- break;
- case 16:
- value = 0x40;
- break;
- case 24:
- value = 0xC0;
- break;
- case 30:
- value = 0x80;
- break;
- default:
- printk(KERN_WARNING "viafb_set_secondary_color_depth: "
- "Unsupported depth: %d\n", depth);
- return;
- }
-
- viafb_write_reg_mask(0x67, VIACR, value, 0xC0);
-}
-
static void set_color_register(u8 index, u8 red, u8 green, u8 blue)
{
outb(0xFF, 0x3C6); /* bit mask of palette */
@@ -1126,16 +1009,12 @@ void viafb_load_reg(int timing_value, int viafb_load_reg_num,
void viafb_write_regx(struct io_reg RegTable[], int ItemNum)
{
int i;
- unsigned char RegTemp;
/*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */
- for (i = 0; i < ItemNum; i++) {
- outb(RegTable[i].index, RegTable[i].port);
- RegTemp = inb(RegTable[i].port + 1);
- RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value;
- outb(RegTemp, RegTable[i].port + 1);
- }
+ for (i = 0; i < ItemNum; i++)
+ via_write_reg_mask(RegTable[i].port, RegTable[i].index,
+ RegTable[i].value, RegTable[i].mask);
}
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
@@ -1516,8 +1395,6 @@ u32 viafb_get_clk_value(int clk)
/* Set VCLK*/
void viafb_set_vclock(u32 CLK, int set_iga)
{
- unsigned char RegTemp;
-
/* H.W. Reset : ON */
viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
@@ -1590,8 +1467,7 @@ void viafb_set_vclock(u32 CLK, int set_iga)
}
/* Fire! */
- RegTemp = inb(VIARMisc);
- outb(RegTemp | (BIT2 + BIT3), VIAWMisc);
+ via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */
}
void viafb_load_crtc_timing(struct display_timing device_timing,
@@ -1835,6 +1711,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
int index = 0;
int h_addr, v_addr;
u32 pll_D_N;
+ u8 polarity = 0;
for (i = 0; i < video_mode->mode_array; i++) {
index = i;
@@ -1863,20 +1740,11 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
v_addr = crt_reg.ver_addr;
/* update polarity for CRT timing */
- if (crt_table[index].h_sync_polarity == NEGATIVE) {
- if (crt_table[index].v_sync_polarity == NEGATIVE)
- outb((inb(VIARMisc) & (~(BIT6 + BIT7))) |
- (BIT6 + BIT7), VIAWMisc);
- else
- outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6),
- VIAWMisc);
- } else {
- if (crt_table[index].v_sync_polarity == NEGATIVE)
- outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7),
- VIAWMisc);
- else
- outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc);
- }
+ if (crt_table[index].h_sync_polarity == NEGATIVE)
+ polarity |= BIT6;
+ if (crt_table[index].v_sync_polarity == NEGATIVE)
+ polarity |= BIT7;
+ via_write_misc_reg_mask(polarity, BIT6 | BIT7);
if (set_iga == IGA1) {
viafb_unlock_crt();
@@ -1910,10 +1778,9 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
}
-void viafb_init_chip_info(struct pci_dev *pdev,
- const struct pci_device_id *pdi)
+void viafb_init_chip_info(int chip_type)
{
- init_gfx_chip_info(pdev, pdi);
+ init_gfx_chip_info(chip_type);
init_tmds_chip_info();
init_lvds_chip_info();
@@ -1980,12 +1847,11 @@ void viafb_update_device_setting(int hres, int vres,
}
}
-static void init_gfx_chip_info(struct pci_dev *pdev,
- const struct pci_device_id *pdi)
+static void init_gfx_chip_info(int chip_type)
{
u8 tmp;
- viaparinfo->chip_info->gfx_chip_name = pdi->driver_data;
+ viaparinfo->chip_info->gfx_chip_name = chip_type;
/* Check revision of CLE266 Chip */
if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
@@ -2016,6 +1882,21 @@ static void init_gfx_chip_info(struct pci_dev *pdev,
CX700_REVISION_700;
}
}
+
+ /* Determine which 2D engine we have */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_VX800:
+ case UNICHROME_VX855:
+ viaparinfo->chip_info->twod_engine = VIA_2D_ENG_M1;
+ break;
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H5;
+ break;
+ default:
+ viaparinfo->chip_info->twod_engine = VIA_2D_ENG_H2;
+ break;
+ }
}
static void init_tmds_chip_info(void)
@@ -2232,13 +2113,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
/* Fill VPIT Parameters */
/* Write Misc Register */
- outb(VPIT.Misc, VIAWMisc);
+ outb(VPIT.Misc, VIA_MISC_REG_WRITE);
/* Write Sequencer */
- for (i = 1; i <= StdSR; i++) {
- outb(i, VIASR);
- outb(VPIT.SR[i - 1], VIASR + 1);
- }
+ for (i = 1; i <= StdSR; i++)
+ via_write_reg(VIASR, i, VPIT.SR[i - 1]);
viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2);
viafb_set_iga_path();
@@ -2247,10 +2126,8 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1);
/* Write Graphic Controller */
- for (i = 0; i < StdGR; i++) {
- outb(i, VIAGR);
- outb(VPIT.GR[i], VIAGR + 1);
- }
+ for (i = 0; i < StdGR; i++)
+ via_write_reg(VIAGR, i, VPIT.GR[i]);
/* Write Attribute Controller */
for (i = 0; i < StdAR; i++) {
@@ -2277,11 +2154,11 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp,
}
}
- viafb_set_primary_pitch(viafbinfo->fix.line_length);
- viafb_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
+ via_set_primary_pitch(viafbinfo->fix.line_length);
+ via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length
: viafbinfo->fix.line_length);
- viafb_set_primary_color_depth(viaparinfo->depth);
- viafb_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
+ via_set_primary_color_depth(viaparinfo->depth);
+ via_set_secondary_color_depth(viafb_dual_fb ? viaparinfo1->depth
: viaparinfo->depth);
/* Update Refresh Rate Setting */
@@ -2473,108 +2350,6 @@ static void disable_second_display_channel(void)
viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
}
-int viafb_get_fb_size_from_pci(void)
-{
- unsigned long configid, deviceid, FBSize = 0;
- int VideoMemSize;
- int DeviceFound = false;
-
- for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) {
- outl(configid, (unsigned long)0xCF8);
- deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff;
-
- switch (deviceid) {
- case CLE266:
- case KM400:
- outl(configid + 0xE0, (unsigned long)0xCF8);
- FBSize = inl((unsigned long)0xCFC);
- DeviceFound = true; /* Found device id */
- break;
-
- case CN400_FUNCTION3:
- case CN700_FUNCTION3:
- case CX700_FUNCTION3:
- case KM800_FUNCTION3:
- case KM890_FUNCTION3:
- case P4M890_FUNCTION3:
- case P4M900_FUNCTION3:
- case VX800_FUNCTION3:
- case VX855_FUNCTION3:
- /*case CN750_FUNCTION3: */
- outl(configid + 0xA0, (unsigned long)0xCF8);
- FBSize = inl((unsigned long)0xCFC);
- DeviceFound = true; /* Found device id */
- break;
-
- default:
- break;
- }
-
- if (DeviceFound)
- break;
- }
-
- DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid);
-
- FBSize = FBSize & 0x00007000;
- DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
-
- if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) {
- switch (FBSize) {
- case 0x00004000:
- VideoMemSize = (16 << 20); /*16M */
- break;
-
- case 0x00005000:
- VideoMemSize = (32 << 20); /*32M */
- break;
-
- case 0x00006000:
- VideoMemSize = (64 << 20); /*64M */
- break;
-
- default:
- VideoMemSize = (32 << 20); /*32M */
- break;
- }
- } else {
- switch (FBSize) {
- case 0x00001000:
- VideoMemSize = (8 << 20); /*8M */
- break;
-
- case 0x00002000:
- VideoMemSize = (16 << 20); /*16M */
- break;
-
- case 0x00003000:
- VideoMemSize = (32 << 20); /*32M */
- break;
-
- case 0x00004000:
- VideoMemSize = (64 << 20); /*64M */
- break;
-
- case 0x00005000:
- VideoMemSize = (128 << 20); /*128M */
- break;
-
- case 0x00006000:
- VideoMemSize = (256 << 20); /*256M */
- break;
-
- case 0x00007000: /* Only on VX855/875 */
- VideoMemSize = (512 << 20); /*512M */
- break;
-
- default:
- VideoMemSize = (32 << 20); /*32M */
- break;
- }
- }
-
- return VideoMemSize;
-}
void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
*p_gfx_dpa_setting)
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
index 12ef32d334c..a109de37981 100644
--- a/drivers/video/via/hw.h
+++ b/drivers/video/via/hw.h
@@ -24,6 +24,11 @@
#include "viamode.h"
#include "global.h"
+#include "via_modesetting.h"
+
+#define viafb_read_reg(p, i) via_read_reg(p, i)
+#define viafb_write_reg(i, p, d) via_write_reg(p, i, d)
+#define viafb_write_reg_mask(i, p, d, m) via_write_reg_mask(p, i, d, m)
/***************************************************
* Definition IGA1 Design Method of CRTC Registers *
@@ -823,8 +828,8 @@ struct iga2_crtc_timing {
};
/* device ID */
-#define CLE266 0x3123
-#define KM400 0x3205
+#define CLE266_FUNCTION3 0x3123
+#define KM400_FUNCTION3 0x3205
#define CN400_FUNCTION2 0x2259
#define CN400_FUNCTION3 0x3259
/* support VT3314 chipset */
@@ -870,7 +875,6 @@ extern int viafb_LCD_ON;
extern int viafb_DVI_ON;
extern int viafb_hotplug;
-void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
void viafb_set_output_path(int device, int set_iga,
int output_interface);
@@ -885,8 +889,6 @@ void viafb_crt_disable(void);
void viafb_crt_enable(void);
void init_ad9389(void);
/* Access I/O Function */
-void viafb_write_reg(u8 index, u16 io_port, u8 data);
-u8 viafb_read_reg(int io_port, u8 index);
void viafb_lock_crt(void);
void viafb_unlock_crt(void);
void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
@@ -900,20 +902,14 @@ 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_init_chip_info(struct pci_dev *pdev,
- const struct pci_device_id *pdi);
+void viafb_init_chip_info(int chip_type);
void 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 vmode_refresh, int flag);
-int viafb_get_fb_size_from_pci(void);
void viafb_set_iga_path(void);
-void viafb_set_primary_address(u32 addr);
-void viafb_set_secondary_address(u32 addr);
-void viafb_set_primary_pitch(u32 pitch);
-void viafb_set_secondary_pitch(u32 pitch);
void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);
diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h
index de899807ead..c430fa23008 100644
--- a/drivers/video/via/ioctl.h
+++ b/drivers/video/via/ioctl.h
@@ -75,7 +75,7 @@
/*SAMM operation flag*/
#define OP_SAMM 0x80
-#define LCD_PANEL_ID_MAXIMUM 22
+#define LCD_PANEL_ID_MAXIMUM 23
#define STATE_ON 0x1
#define STATE_OFF 0x0
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index 1b1ccdc2d83..2ab0f156439 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -18,7 +18,8 @@
* Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
#include "global.h"
#include "lcdtbl.h"
@@ -172,18 +173,16 @@ static bool lvds_identify_integratedlvds(void)
int viafb_lvds_trasmitter_identify(void)
{
- viaparinfo->shared->i2c_stuff.i2c_port = I2CPORTINDEX;
- if (viafb_lvds_identify_vt1636()) {
- viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX;
+ if (viafb_lvds_identify_vt1636(VIA_PORT_31)) {
+ viaparinfo->chip_info->lvds_chip_info.i2c_port = VIA_PORT_31;
DEBUG_MSG(KERN_INFO
- "Found VIA VT1636 LVDS on port i2c 0x31 \n");
+ "Found VIA VT1636 LVDS on port i2c 0x31\n");
} else {
- viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
- if (viafb_lvds_identify_vt1636()) {
+ if (viafb_lvds_identify_vt1636(VIA_PORT_2C)) {
viaparinfo->chip_info->lvds_chip_info.i2c_port =
- GPIOPORTINDEX;
+ VIA_PORT_2C;
DEBUG_MSG(KERN_INFO
- "Found VIA VT1636 LVDS on port gpio 0x2c \n");
+ "Found VIA VT1636 LVDS on port gpio 0x2c\n");
}
}
@@ -398,6 +397,15 @@ static void fp_id_to_vindex(int panel_id)
viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
viaparinfo->lvds_setting_info->LCDDithering = 1;
break;
+ case 0x17:
+ /* OLPC XO-1.5 panel */
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1200;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 900;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_IDD_1200X900;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ break;
default:
viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
@@ -412,9 +420,8 @@ static int lvds_register_read(int index)
{
u8 data;
- viaparinfo->shared->i2c_stuff.i2c_port = GPIOPORTINDEX;
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->
- lvds_chip_info.lvds_chip_slave_addr,
+ viafb_i2c_readbyte(VIA_PORT_2C,
+ (u8) viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr,
(u8) index, &data);
return data;
}
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
index 071f47cf5be..9762ec62b49 100644
--- a/drivers/video/via/lcd.h
+++ b/drivers/video/via/lcd.h
@@ -60,6 +60,8 @@
#define LCD_PANEL_IDB_1360X768 0x0B
/* Resolution: 480x640, Channel: single, Dithering: Enable */
#define LCD_PANEL_IDC_480X640 0x0C
+/* Resolution: 1200x900, Channel: single, Dithering: Disable */
+#define LCD_PANEL_IDD_1200X900 0x0D
extern int viafb_LCD2_ON;
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
index d55aaa7b912..7f0de7f006a 100644
--- a/drivers/video/via/share.h
+++ b/drivers/video/via/share.h
@@ -43,16 +43,9 @@
/* Video Memory Size */
#define VIDEO_MEMORY_SIZE_16M 0x1000000
-/* standard VGA IO port
-*/
-#define VIARMisc 0x3CC
-#define VIAWMisc 0x3C2
-#define VIAStatus 0x3DA
-#define VIACR 0x3D4
-#define VIASR 0x3C4
-#define VIAGR 0x3CE
-#define VIAAR 0x3C0
-
+/*
+ * Lengths of the VPIT structure arrays.
+ */
#define StdCR 0x19
#define StdSR 0x04
#define StdGR 0x09
@@ -570,6 +563,10 @@
#define M1200X720_R60_HSP NEGATIVE
#define M1200X720_R60_VSP POSITIVE
+/* 1200x900@60 Sync Polarity (DCON) */
+#define M1200X900_R60_HSP NEGATIVE
+#define M1200X900_R60_VSP NEGATIVE
+
/* 1280x600@60 Sync Polarity (GTF Mode) */
#define M1280x600_R60_HSP NEGATIVE
#define M1280x600_R60_VSP POSITIVE
@@ -651,6 +648,7 @@
#define CLK_52_406M 52406000
#define CLK_52_977M 52977000
#define CLK_56_250M 56250000
+#define CLK_57_275M 57275000
#define CLK_60_466M 60466000
#define CLK_61_500M 61500000
#define CLK_65_000M 65000000
@@ -939,6 +937,7 @@
#define VX855_52_406M 0x00580C03
#define VX855_52_977M 0x00940C05
#define VX855_56_250M 0x009D0C05
+#define VX855_57_275M 0x009D8C85 /* Used by XO panel */
#define VX855_60_466M 0x00A90C05
#define VX855_61_500M 0x00AC0C05
#define VX855_65_000M 0x006D0C03
@@ -1065,6 +1064,7 @@
#define RES_1600X1200_60HZ_PIXCLOCK 6172
#define RES_1600X1200_75HZ_PIXCLOCK 4938
#define RES_1280X720_60HZ_PIXCLOCK 13426
+#define RES_1200X900_60HZ_PIXCLOCK 17459
#define RES_1920X1080_60HZ_PIXCLOCK 5787
#define RES_1400X1050_60HZ_PIXCLOCK 8214
#define RES_1400X1050_75HZ_PIXCLOCK 6410
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
new file mode 100644
index 00000000000..e8cfe839211
--- /dev/null
+++ b/drivers/video/via/via-core.c
@@ -0,0 +1,668 @@
+/*
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+ */
+
+/*
+ * Core code for the Via multifunction framebuffer device.
+ */
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
+#include <linux/via-gpio.h>
+#include "global.h"
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+/*
+ * The default port config.
+ */
+static struct via_port_cfg adap_configs[] = {
+ [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_OFF, VIASR, 0x26 },
+ [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 },
+ [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 },
+ [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_I2C, VIASR, 0x2c },
+ [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d },
+ { 0, 0, 0, 0 }
+};
+
+/*
+ * We currently only support one viafb device (will there ever be
+ * more than one?), so just declare it globally here.
+ */
+static struct viafb_dev global_dev;
+
+
+/*
+ * Basic register access; spinlock required.
+ */
+static inline void viafb_mmio_write(int reg, u32 v)
+{
+ iowrite32(v, global_dev.engine_mmio + reg);
+}
+
+static inline int viafb_mmio_read(int reg)
+{
+ return ioread32(global_dev.engine_mmio + reg);
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Interrupt management. We have a single IRQ line for a lot of
+ * different functions, so we need to share it. The design here
+ * is that we don't want to reimplement the shared IRQ code here;
+ * we also want to avoid having contention for a single handler thread.
+ * So each subdev driver which needs interrupts just requests
+ * them directly from the kernel. We just have what's needed for
+ * overall access to the interrupt control register.
+ */
+
+/*
+ * Which interrupts are enabled now?
+ */
+static u32 viafb_enabled_ints;
+
+static void viafb_int_init(void)
+{
+ viafb_enabled_ints = 0;
+
+ viafb_mmio_write(VDE_INTERRUPT, 0);
+}
+
+/*
+ * Allow subdevs to ask for specific interrupts to be enabled. These
+ * functions must be called with reg_lock held
+ */
+void viafb_irq_enable(u32 mask)
+{
+ viafb_enabled_ints |= mask;
+ viafb_mmio_write(VDE_INTERRUPT, viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_enable);
+
+void viafb_irq_disable(u32 mask)
+{
+ viafb_enabled_ints &= ~mask;
+ if (viafb_enabled_ints == 0)
+ viafb_mmio_write(VDE_INTERRUPT, 0); /* Disable entirely */
+ else
+ viafb_mmio_write(VDE_INTERRUPT,
+ viafb_enabled_ints | VDE_I_ENABLE);
+}
+EXPORT_SYMBOL_GPL(viafb_irq_disable);
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Access to the DMA engine. This currently provides what the camera
+ * driver needs (i.e. outgoing only) but is easily expandable if need
+ * be.
+ */
+
+/*
+ * There are four DMA channels in the vx855. For now, we only
+ * use one of them, though. Most of the time, the DMA channel
+ * will be idle, so we keep the IRQ handler unregistered except
+ * when some subsystem has indicated an interest.
+ */
+static int viafb_dma_users;
+static DECLARE_COMPLETION(viafb_dma_completion);
+/*
+ * This mutex protects viafb_dma_users and our global interrupt
+ * registration state; it also serializes access to the DMA
+ * engine.
+ */
+static DEFINE_MUTEX(viafb_dma_lock);
+
+/*
+ * The VX855 DMA descriptor (used for s/g transfers) looks
+ * like this.
+ */
+struct viafb_vx855_dma_descr {
+ u32 addr_low; /* Low part of phys addr */
+ u32 addr_high; /* High 12 bits of addr */
+ u32 fb_offset; /* Offset into FB memory */
+ u32 seg_size; /* Size, 16-byte units */
+ u32 tile_mode; /* "tile mode" setting */
+ u32 next_desc_low; /* Next descriptor addr */
+ u32 next_desc_high;
+ u32 pad; /* Fill out to 64 bytes */
+};
+
+/*
+ * Flags added to the "next descriptor low" pointers
+ */
+#define VIAFB_DMA_MAGIC 0x01 /* ??? Just has to be there */
+#define VIAFB_DMA_FINAL_SEGMENT 0x02 /* Final segment */
+
+/*
+ * The completion IRQ handler.
+ */
+static irqreturn_t viafb_dma_irq(int irq, void *data)
+{
+ int csr;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&global_dev.reg_lock);
+ csr = viafb_mmio_read(VDMA_CSR0);
+ if (csr & VDMA_C_DONE) {
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
+ complete(&viafb_dma_completion);
+ ret = IRQ_HANDLED;
+ }
+ spin_unlock(&global_dev.reg_lock);
+ return ret;
+}
+
+/*
+ * Indicate a need for DMA functionality.
+ */
+int viafb_request_dma(void)
+{
+ int ret = 0;
+
+ /*
+ * Only VX855 is supported currently.
+ */
+ if (global_dev.chip_type != UNICHROME_VX855)
+ return -ENODEV;
+ /*
+ * Note the new user and set up our interrupt handler
+ * if need be.
+ */
+ mutex_lock(&viafb_dma_lock);
+ viafb_dma_users++;
+ if (viafb_dma_users == 1) {
+ ret = request_irq(global_dev.pdev->irq, viafb_dma_irq,
+ IRQF_SHARED, "via-dma", &viafb_dma_users);
+ if (ret)
+ viafb_dma_users--;
+ else
+ viafb_irq_enable(VDE_I_DMA0TDEN);
+ }
+ mutex_unlock(&viafb_dma_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(viafb_request_dma);
+
+void viafb_release_dma(void)
+{
+ mutex_lock(&viafb_dma_lock);
+ viafb_dma_users--;
+ if (viafb_dma_users == 0) {
+ viafb_irq_disable(VDE_I_DMA0TDEN);
+ free_irq(global_dev.pdev->irq, &viafb_dma_users);
+ }
+ mutex_unlock(&viafb_dma_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_release_dma);
+
+
+#if 0
+/*
+ * Copy a single buffer from FB memory, synchronously. This code works
+ * but is not currently used.
+ */
+void viafb_dma_copy_out(unsigned int offset, dma_addr_t paddr, int len)
+{
+ unsigned long flags;
+ int csr;
+
+ mutex_lock(&viafb_dma_lock);
+ init_completion(&viafb_dma_completion);
+ /*
+ * Program the controller.
+ */
+ spin_lock_irqsave(&global_dev.reg_lock, flags);
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
+ /* Enable ints; must happen after CSR0 write! */
+ viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE);
+ viafb_mmio_write(VDMA_MARL0, (int) (paddr & 0xfffffff0));
+ viafb_mmio_write(VDMA_MARH0, (int) ((paddr >> 28) & 0xfff));
+ /* Data sheet suggests DAR0 should be <<4, but it lies */
+ viafb_mmio_write(VDMA_DAR0, offset);
+ viafb_mmio_write(VDMA_DQWCR0, len >> 4);
+ viafb_mmio_write(VDMA_TMR0, 0);
+ viafb_mmio_write(VDMA_DPRL0, 0);
+ viafb_mmio_write(VDMA_DPRH0, 0);
+ viafb_mmio_write(VDMA_PMR0, 0);
+ csr = viafb_mmio_read(VDMA_CSR0);
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
+ spin_unlock_irqrestore(&global_dev.reg_lock, flags);
+ /*
+ * Now we just wait until the interrupt handler says
+ * we're done.
+ */
+ wait_for_completion_interruptible(&viafb_dma_completion);
+ viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
+ mutex_unlock(&viafb_dma_lock);
+}
+EXPORT_SYMBOL_GPL(viafb_dma_copy_out);
+#endif
+
+/*
+ * Do a scatter/gather DMA copy from FB memory. You must have done
+ * a successful call to viafb_request_dma() first.
+ */
+int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
+{
+ struct viafb_vx855_dma_descr *descr;
+ void *descrpages;
+ dma_addr_t descr_handle;
+ unsigned long flags;
+ int i;
+ struct scatterlist *sgentry;
+ dma_addr_t nextdesc;
+
+ /*
+ * Get a place to put the descriptors.
+ */
+ descrpages = dma_alloc_coherent(&global_dev.pdev->dev,
+ nsg*sizeof(struct viafb_vx855_dma_descr),
+ &descr_handle, GFP_KERNEL);
+ if (descrpages == NULL) {
+ dev_err(&global_dev.pdev->dev, "Unable to get descr page.\n");
+ return -ENOMEM;
+ }
+ mutex_lock(&viafb_dma_lock);
+ /*
+ * Fill them in.
+ */
+ descr = descrpages;
+ nextdesc = descr_handle + sizeof(struct viafb_vx855_dma_descr);
+ for_each_sg(sg, sgentry, nsg, i) {
+ dma_addr_t paddr = sg_dma_address(sgentry);
+ descr->addr_low = paddr & 0xfffffff0;
+ descr->addr_high = ((u64) paddr >> 32) & 0x0fff;
+ descr->fb_offset = offset;
+ descr->seg_size = sg_dma_len(sgentry) >> 4;
+ descr->tile_mode = 0;
+ descr->next_desc_low = (nextdesc&0xfffffff0) | VIAFB_DMA_MAGIC;
+ descr->next_desc_high = ((u64) nextdesc >> 32) & 0x0fff;
+ descr->pad = 0xffffffff; /* VIA driver does this */
+ offset += sg_dma_len(sgentry);
+ nextdesc += sizeof(struct viafb_vx855_dma_descr);
+ descr++;
+ }
+ descr[-1].next_desc_low = VIAFB_DMA_FINAL_SEGMENT|VIAFB_DMA_MAGIC;
+ /*
+ * Program the engine.
+ */
+ spin_lock_irqsave(&global_dev.reg_lock, flags);
+ init_completion(&viafb_dma_completion);
+ viafb_mmio_write(VDMA_DQWCR0, 0);
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_DONE);
+ viafb_mmio_write(VDMA_MR0, VDMA_MR_TDIE | VDMA_MR_CHAIN);
+ viafb_mmio_write(VDMA_DPRL0, descr_handle | VIAFB_DMA_MAGIC);
+ viafb_mmio_write(VDMA_DPRH0,
+ (((u64)descr_handle >> 32) & 0x0fff) | 0xf0000);
+ (void) viafb_mmio_read(VDMA_CSR0);
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_ENABLE|VDMA_C_START);
+ spin_unlock_irqrestore(&global_dev.reg_lock, flags);
+ /*
+ * Now we just wait until the interrupt handler says
+ * we're done. Except that, actually, we need to wait a little
+ * longer: the interrupts seem to jump the gun a little and we
+ * get corrupted frames sometimes.
+ */
+ wait_for_completion_timeout(&viafb_dma_completion, 1);
+ msleep(1);
+ if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0)
+ printk(KERN_ERR "VIA DMA timeout!\n");
+ /*
+ * Clean up and we're done.
+ */
+ viafb_mmio_write(VDMA_CSR0, VDMA_C_DONE);
+ viafb_mmio_write(VDMA_MR0, 0); /* Reset int enable */
+ mutex_unlock(&viafb_dma_lock);
+ dma_free_coherent(&global_dev.pdev->dev,
+ nsg*sizeof(struct viafb_vx855_dma_descr), descrpages,
+ descr_handle);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
+
+
+/* ---------------------------------------------------------------------- */
+/*
+ * Figure out how big our framebuffer memory is. Kind of ugly,
+ * but evidently we can't trust the information found in the
+ * fbdev configuration area.
+ */
+static u16 via_function3[] = {
+ CLE266_FUNCTION3, KM400_FUNCTION3, CN400_FUNCTION3, CN700_FUNCTION3,
+ CX700_FUNCTION3, KM800_FUNCTION3, KM890_FUNCTION3, P4M890_FUNCTION3,
+ P4M900_FUNCTION3, VX800_FUNCTION3, VX855_FUNCTION3,
+};
+
+/* Get the BIOS-configured framebuffer size from PCI configuration space
+ * of function 3 in the respective chipset */
+static int viafb_get_fb_size_from_pci(int chip_type)
+{
+ int i;
+ u8 offset = 0;
+ u32 FBSize;
+ u32 VideoMemSize;
+
+ /* search for the "FUNCTION3" device in this chipset */
+ for (i = 0; i < ARRAY_SIZE(via_function3); i++) {
+ struct pci_dev *pdev;
+
+ pdev = pci_get_device(PCI_VENDOR_ID_VIA, via_function3[i],
+ NULL);
+ if (!pdev)
+ continue;
+
+ DEBUG_MSG(KERN_INFO "Device ID = %x\n", pdev->device);
+
+ switch (pdev->device) {
+ case CLE266_FUNCTION3:
+ case KM400_FUNCTION3:
+ offset = 0xE0;
+ break;
+ case CN400_FUNCTION3:
+ case CN700_FUNCTION3:
+ case CX700_FUNCTION3:
+ case KM800_FUNCTION3:
+ case KM890_FUNCTION3:
+ case P4M890_FUNCTION3:
+ case P4M900_FUNCTION3:
+ case VX800_FUNCTION3:
+ case VX855_FUNCTION3:
+ /*case CN750_FUNCTION3: */
+ offset = 0xA0;
+ break;
+ }
+
+ if (!offset)
+ break;
+
+ pci_read_config_dword(pdev, offset, &FBSize);
+ pci_dev_put(pdev);
+ }
+
+ if (!offset) {
+ printk(KERN_ERR "cannot determine framebuffer size\n");
+ return -EIO;
+ }
+
+ FBSize = FBSize & 0x00007000;
+ DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
+
+ if (chip_type < UNICHROME_CX700) {
+ switch (FBSize) {
+ case 0x00004000:
+ VideoMemSize = (16 << 20); /*16M */
+ break;
+
+ case 0x00005000:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+
+ case 0x00006000:
+ VideoMemSize = (64 << 20); /*64M */
+ break;
+
+ default:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+ }
+ } else {
+ switch (FBSize) {
+ case 0x00001000:
+ VideoMemSize = (8 << 20); /*8M */
+ break;
+
+ case 0x00002000:
+ VideoMemSize = (16 << 20); /*16M */
+ break;
+
+ case 0x00003000:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+
+ case 0x00004000:
+ VideoMemSize = (64 << 20); /*64M */
+ break;
+
+ case 0x00005000:
+ VideoMemSize = (128 << 20); /*128M */
+ break;
+
+ case 0x00006000:
+ VideoMemSize = (256 << 20); /*256M */
+ break;
+
+ case 0x00007000: /* Only on VX855/875 */
+ VideoMemSize = (512 << 20); /*512M */
+ break;
+
+ default:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+ }
+ }
+
+ return VideoMemSize;
+}
+
+
+/*
+ * Figure out and map our MMIO regions.
+ */
+static int __devinit via_pci_setup_mmio(struct viafb_dev *vdev)
+{
+ int ret;
+ /*
+ * Hook up to the device registers. Note that we soldier
+ * on if it fails; the framebuffer can operate (without
+ * acceleration) without this region.
+ */
+ vdev->engine_start = pci_resource_start(vdev->pdev, 1);
+ vdev->engine_len = pci_resource_len(vdev->pdev, 1);
+ vdev->engine_mmio = ioremap_nocache(vdev->engine_start,
+ vdev->engine_len);
+ if (vdev->engine_mmio == NULL)
+ dev_err(&vdev->pdev->dev,
+ "Unable to map engine MMIO; operation will be "
+ "slow and crippled.\n");
+ /*
+ * Map in framebuffer memory. For now, failure here is
+ * fatal. Unfortunately, in the absence of significant
+ * vmalloc space, failure here is also entirely plausible.
+ * Eventually we want to move away from mapping this
+ * entire region.
+ */
+ vdev->fbmem_start = pci_resource_start(vdev->pdev, 0);
+ ret = vdev->fbmem_len = viafb_get_fb_size_from_pci(vdev->chip_type);
+ if (ret < 0)
+ goto out_unmap;
+ vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len);
+ if (vdev->fbmem == NULL) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+ return 0;
+out_unmap:
+ iounmap(vdev->engine_mmio);
+ return ret;
+}
+
+static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
+{
+ iounmap(vdev->fbmem);
+ iounmap(vdev->engine_mmio);
+}
+
+/*
+ * Create our subsidiary devices.
+ */
+static struct viafb_subdev_info {
+ char *name;
+ struct platform_device *platdev;
+} viafb_subdevs[] = {
+ {
+ .name = "viafb-gpio",
+ },
+ {
+ .name = "viafb-i2c",
+ }
+};
+#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
+
+static int __devinit via_create_subdev(struct viafb_dev *vdev,
+ struct viafb_subdev_info *info)
+{
+ int ret;
+
+ info->platdev = platform_device_alloc(info->name, -1);
+ if (!info->platdev) {
+ dev_err(&vdev->pdev->dev, "Unable to allocate pdev %s\n",
+ info->name);
+ return -ENOMEM;
+ }
+ info->platdev->dev.parent = &vdev->pdev->dev;
+ info->platdev->dev.platform_data = vdev;
+ ret = platform_device_add(info->platdev);
+ if (ret) {
+ dev_err(&vdev->pdev->dev, "Unable to add pdev %s\n",
+ info->name);
+ platform_device_put(info->platdev);
+ info->platdev = NULL;
+ }
+ return ret;
+}
+
+static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
+{
+ int i;
+
+ /*
+ * Ignore return values. Even if some of the devices
+ * fail to be created, we'll still be able to use some
+ * of the rest.
+ */
+ for (i = 0; i < N_SUBDEVS; i++)
+ via_create_subdev(vdev, viafb_subdevs + i);
+ return 0;
+}
+
+static void __devexit via_teardown_subdevs(void)
+{
+ int i;
+
+ for (i = 0; i < N_SUBDEVS; i++)
+ if (viafb_subdevs[i].platdev) {
+ viafb_subdevs[i].platdev->dev.platform_data = NULL;
+ platform_device_unregister(viafb_subdevs[i].platdev);
+ }
+}
+
+
+static int __devinit via_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ /*
+ * Global device initialization.
+ */
+ memset(&global_dev, 0, sizeof(global_dev));
+ global_dev.pdev = pdev;
+ global_dev.chip_type = ent->driver_data;
+ global_dev.port_cfg = adap_configs;
+ spin_lock_init(&global_dev.reg_lock);
+ ret = via_pci_setup_mmio(&global_dev);
+ if (ret)
+ goto out_disable;
+ /*
+ * Set up interrupts and create our subdevices. Continue even if
+ * some things fail.
+ */
+ viafb_int_init();
+ via_setup_subdevs(&global_dev);
+ /*
+ * Set up the framebuffer device
+ */
+ ret = via_fb_pci_probe(&global_dev);
+ if (ret)
+ goto out_subdevs;
+ return 0;
+
+out_subdevs:
+ via_teardown_subdevs();
+ via_pci_teardown_mmio(&global_dev);
+out_disable:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void __devexit via_pci_remove(struct pci_dev *pdev)
+{
+ via_teardown_subdevs();
+ via_fb_pci_remove(pdev);
+ via_pci_teardown_mmio(&global_dev);
+ pci_disable_device(pdev);
+}
+
+
+static struct pci_device_id via_pci_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
+ .driver_data = UNICHROME_CLE266 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
+ .driver_data = UNICHROME_PM800 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
+ .driver_data = UNICHROME_K400 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
+ .driver_data = UNICHROME_K800 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
+ .driver_data = UNICHROME_CN700 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
+ .driver_data = UNICHROME_K8M890 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
+ .driver_data = UNICHROME_CX700 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
+ .driver_data = UNICHROME_P4M900 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
+ .driver_data = UNICHROME_CN750 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
+ .driver_data = UNICHROME_VX800 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
+ .driver_data = UNICHROME_VX855 },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, via_pci_table);
+
+static struct pci_driver via_driver = {
+ .name = "viafb",
+ .id_table = via_pci_table,
+ .probe = via_pci_probe,
+ .remove = __devexit_p(via_pci_remove),
+};
+
+static int __init via_core_init(void)
+{
+ int ret;
+
+ ret = viafb_init();
+ if (ret)
+ return ret;
+ viafb_i2c_init();
+ viafb_gpio_init();
+ return pci_register_driver(&via_driver);
+}
+
+static void __exit via_core_exit(void)
+{
+ pci_unregister_driver(&via_driver);
+ viafb_gpio_exit();
+ viafb_i2c_exit();
+ viafb_exit();
+}
+
+module_init(via_core_init);
+module_exit(via_core_exit);
diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c
new file mode 100644
index 00000000000..595516aea69
--- /dev/null
+++ b/drivers/video/via/via-gpio.c
@@ -0,0 +1,285 @@
+/*
+ * Support for viafb GPIO ports.
+ *
+ * Copyright 2009 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under version 2 of the GNU General Public License.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+
+/*
+ * The ports we know about. Note that the port-25 gpios are not
+ * mentioned in the datasheet.
+ */
+
+struct viafb_gpio {
+ char *vg_name; /* Data sheet name */
+ u16 vg_io_port;
+ u8 vg_port_index;
+ int vg_mask_shift;
+};
+
+static struct viafb_gpio viafb_all_gpios[] = {
+ {
+ .vg_name = "VGPIO0", /* Guess - not in datasheet */
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x25,
+ .vg_mask_shift = 1
+ },
+ {
+ .vg_name = "VGPIO1",
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x25,
+ .vg_mask_shift = 0
+ },
+ {
+ .vg_name = "VGPIO2", /* aka DISPCLKI0 */
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x2c,
+ .vg_mask_shift = 1
+ },
+ {
+ .vg_name = "VGPIO3", /* aka DISPCLKO0 */
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x2c,
+ .vg_mask_shift = 0
+ },
+ {
+ .vg_name = "VGPIO4", /* DISPCLKI1 */
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x3d,
+ .vg_mask_shift = 1
+ },
+ {
+ .vg_name = "VGPIO5", /* DISPCLKO1 */
+ .vg_io_port = VIASR,
+ .vg_port_index = 0x3d,
+ .vg_mask_shift = 0
+ },
+};
+
+#define VIAFB_NUM_GPIOS ARRAY_SIZE(viafb_all_gpios)
+
+/*
+ * This structure controls the active GPIOs, which may be a subset
+ * of those which are known.
+ */
+
+struct viafb_gpio_cfg {
+ struct gpio_chip gpio_chip;
+ struct viafb_dev *vdev;
+ struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
+ char *gpio_names[VIAFB_NUM_GPIOS];
+};
+
+/*
+ * GPIO access functions
+ */
+static void via_gpio_set(struct gpio_chip *chip, unsigned int nr,
+ int value)
+{
+ struct viafb_gpio_cfg *cfg = container_of(chip,
+ struct viafb_gpio_cfg,
+ gpio_chip);
+ u8 reg;
+ struct viafb_gpio *gpio;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+ gpio = cfg->active_gpios[nr];
+ reg = via_read_reg(VIASR, gpio->vg_port_index);
+ reg |= 0x40 << gpio->vg_mask_shift; /* output enable */
+ if (value)
+ reg |= 0x10 << gpio->vg_mask_shift;
+ else
+ reg &= ~(0x10 << gpio->vg_mask_shift);
+ via_write_reg(VIASR, gpio->vg_port_index, reg);
+ spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+}
+
+static int via_gpio_dir_out(struct gpio_chip *chip, unsigned int nr,
+ int value)
+{
+ via_gpio_set(chip, nr, value);
+ return 0;
+}
+
+/*
+ * Set the input direction. I'm not sure this is right; we should
+ * be able to do input without disabling output.
+ */
+static int via_gpio_dir_input(struct gpio_chip *chip, unsigned int nr)
+{
+ struct viafb_gpio_cfg *cfg = container_of(chip,
+ struct viafb_gpio_cfg,
+ gpio_chip);
+ struct viafb_gpio *gpio;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+ gpio = cfg->active_gpios[nr];
+ via_write_reg_mask(VIASR, gpio->vg_port_index, 0,
+ 0x40 << gpio->vg_mask_shift);
+ spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+ return 0;
+}
+
+static int via_gpio_get(struct gpio_chip *chip, unsigned int nr)
+{
+ struct viafb_gpio_cfg *cfg = container_of(chip,
+ struct viafb_gpio_cfg,
+ gpio_chip);
+ u8 reg;
+ struct viafb_gpio *gpio;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cfg->vdev->reg_lock, flags);
+ gpio = cfg->active_gpios[nr];
+ reg = via_read_reg(VIASR, gpio->vg_port_index);
+ spin_unlock_irqrestore(&cfg->vdev->reg_lock, flags);
+ return reg & (0x04 << gpio->vg_mask_shift);
+}
+
+
+static struct viafb_gpio_cfg gpio_config = {
+ .gpio_chip = {
+ .label = "VIAFB onboard GPIO",
+ .owner = THIS_MODULE,
+ .direction_output = via_gpio_dir_out,
+ .set = via_gpio_set,
+ .direction_input = via_gpio_dir_input,
+ .get = via_gpio_get,
+ .base = -1,
+ .ngpio = 0,
+ .can_sleep = 0
+ }
+};
+
+/*
+ * Manage the software enable bit.
+ */
+static void viafb_gpio_enable(struct viafb_gpio *gpio)
+{
+ via_write_reg_mask(VIASR, gpio->vg_port_index, 0x02, 0x02);
+}
+
+static void viafb_gpio_disable(struct viafb_gpio *gpio)
+{
+ via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02);
+}
+
+/*
+ * Look up a specific gpio and return the number it was assigned.
+ */
+int viafb_gpio_lookup(const char *name)
+{
+ int i;
+
+ for (i = 0; i < gpio_config.gpio_chip.ngpio; i++)
+ if (!strcmp(name, gpio_config.active_gpios[i]->vg_name))
+ return gpio_config.gpio_chip.base + i;
+ return -1;
+}
+EXPORT_SYMBOL_GPL(viafb_gpio_lookup);
+
+/*
+ * Platform device stuff.
+ */
+static __devinit int viafb_gpio_probe(struct platform_device *platdev)
+{
+ struct viafb_dev *vdev = platdev->dev.platform_data;
+ struct via_port_cfg *port_cfg = vdev->port_cfg;
+ int i, ngpio = 0, ret;
+ struct viafb_gpio *gpio;
+ unsigned long flags;
+
+ /*
+ * Set up entries for all GPIOs which have been configured to
+ * operate as such (as opposed to as i2c ports).
+ */
+ for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+ if (port_cfg[i].mode != VIA_MODE_GPIO)
+ continue;
+ for (gpio = viafb_all_gpios;
+ gpio < viafb_all_gpios + VIAFB_NUM_GPIOS; gpio++)
+ if (gpio->vg_port_index == port_cfg[i].ioport_index) {
+ gpio_config.active_gpios[ngpio] = gpio;
+ gpio_config.gpio_names[ngpio] = gpio->vg_name;
+ ngpio++;
+ }
+ }
+ gpio_config.gpio_chip.ngpio = ngpio;
+ gpio_config.gpio_chip.names = gpio_config.gpio_names;
+ gpio_config.vdev = vdev;
+ if (ngpio == 0) {
+ printk(KERN_INFO "viafb: no GPIOs configured\n");
+ return 0;
+ }
+ /*
+ * Enable the ports. They come in pairs, with a single
+ * enable bit for both.
+ */
+ spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
+ for (i = 0; i < ngpio; i += 2)
+ viafb_gpio_enable(gpio_config.active_gpios[i]);
+ spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+ /*
+ * Get registered.
+ */
+ gpio_config.gpio_chip.base = -1; /* Dynamic */
+ ret = gpiochip_add(&gpio_config.gpio_chip);
+ if (ret) {
+ printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret);
+ gpio_config.gpio_chip.ngpio = 0;
+ }
+ return ret;
+}
+
+
+static int viafb_gpio_remove(struct platform_device *platdev)
+{
+ unsigned long flags;
+ int ret = 0, i;
+
+ /*
+ * Get unregistered.
+ */
+ if (gpio_config.gpio_chip.ngpio > 0) {
+ ret = gpiochip_remove(&gpio_config.gpio_chip);
+ if (ret) { /* Somebody still using it? */
+ printk(KERN_ERR "Viafb: GPIO remove failed\n");
+ return ret;
+ }
+ }
+ /*
+ * Disable the ports.
+ */
+ spin_lock_irqsave(&gpio_config.vdev->reg_lock, flags);
+ for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2)
+ viafb_gpio_disable(gpio_config.active_gpios[i]);
+ gpio_config.gpio_chip.ngpio = 0;
+ spin_unlock_irqrestore(&gpio_config.vdev->reg_lock, flags);
+ return ret;
+}
+
+static struct platform_driver via_gpio_driver = {
+ .driver = {
+ .name = "viafb-gpio",
+ },
+ .probe = viafb_gpio_probe,
+ .remove = viafb_gpio_remove,
+};
+
+int viafb_gpio_init(void)
+{
+ return platform_driver_register(&via_gpio_driver);
+}
+
+void viafb_gpio_exit(void)
+{
+ platform_driver_unregister(&via_gpio_driver);
+}
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index 15543e96824..da9e4ca94b1 100644
--- a/drivers/video/via/via_i2c.c
+++ b/drivers/video/via/via_i2c.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* This program is free software; you can redistribute it and/or
@@ -19,77 +19,106 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "global.h"
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
+
+/*
+ * There can only be one set of these, so there's no point in having
+ * them be dynamically allocated...
+ */
+#define VIAFB_NUM_I2C 5
+static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
+struct viafb_dev *i2c_vdev; /* Passed in from core */
static void via_i2c_setscl(void *data, int state)
{
u8 val;
- struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+ struct via_port_cfg *adap_data = data;
+ unsigned long flags;
- val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+ spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+ val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
if (state)
val |= 0x20;
else
val &= ~0x20;
- switch (via_i2c_chan->i2c_port) {
- case I2CPORTINDEX:
+ switch (adap_data->type) {
+ case VIA_PORT_I2C:
val |= 0x01;
break;
- case GPIOPORTINDEX:
+ case VIA_PORT_GPIO:
val |= 0x80;
break;
default:
- DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+ printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
}
- viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+ via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
+ spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
}
static int via_i2c_getscl(void *data)
{
- struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+ struct via_port_cfg *adap_data = data;
+ unsigned long flags;
+ int ret = 0;
- if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08)
- return 1;
- return 0;
+ spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+ if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
+ ret = 1;
+ spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
+ return ret;
}
static int via_i2c_getsda(void *data)
{
- struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+ struct via_port_cfg *adap_data = data;
+ unsigned long flags;
+ int ret = 0;
- if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04)
- return 1;
- return 0;
+ spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+ if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
+ ret = 1;
+ spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
+ return ret;
}
static void via_i2c_setsda(void *data, int state)
{
u8 val;
- struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+ struct via_port_cfg *adap_data = data;
+ unsigned long flags;
- val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+ spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
+ val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
if (state)
val |= 0x10;
else
val &= ~0x10;
- switch (via_i2c_chan->i2c_port) {
- case I2CPORTINDEX:
+ switch (adap_data->type) {
+ case VIA_PORT_I2C:
val |= 0x01;
break;
- case GPIOPORTINDEX:
+ case VIA_PORT_GPIO:
val |= 0x40;
break;
default:
- DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+ printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
}
- viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+ via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
+ spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
}
-int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
+int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
{
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
+ if (!via_i2c_par[adap].is_active)
+ return -ENODEV;
*pdata = 0;
msgs[0].flags = 0;
msgs[1].flags = I2C_M_RD;
@@ -97,81 +126,144 @@ int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = 1;
msgs[0].buf = mm1; msgs[1].buf = pdata;
- i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
-
- return 0;
+ return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
}
-int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data)
+int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
{
u8 msg[2] = { index, data };
struct i2c_msg msgs;
+ if (!via_i2c_par[adap].is_active)
+ return -ENODEV;
msgs.flags = 0;
msgs.addr = slave_addr / 2;
msgs.len = 2;
msgs.buf = msg;
- return i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, &msgs, 1);
+ return i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
}
-int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len)
+int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
{
u8 mm1[] = {0x00};
struct i2c_msg msgs[2];
+ if (!via_i2c_par[adap].is_active)
+ return -ENODEV;
msgs[0].flags = 0;
msgs[1].flags = I2C_M_RD;
msgs[0].addr = msgs[1].addr = slave_addr / 2;
mm1[0] = index;
msgs[0].len = 1; msgs[1].len = buff_len;
msgs[0].buf = mm1; msgs[1].buf = buff;
- i2c_transfer(&viaparinfo->shared->i2c_stuff.adapter, msgs, 2);
- return 0;
+ return i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
}
-int viafb_create_i2c_bus(void *viapar)
+/*
+ * Allow other viafb subdevices to look up a specific adapter
+ * by port name.
+ */
+struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
{
- int ret;
- struct via_i2c_stuff *i2c_stuff =
- &((struct viafb_par *)viapar)->shared->i2c_stuff;
-
- strcpy(i2c_stuff->adapter.name, "via_i2c");
- i2c_stuff->i2c_port = 0x0;
- i2c_stuff->adapter.owner = THIS_MODULE;
- i2c_stuff->adapter.id = 0x01FFFF;
- i2c_stuff->adapter.class = 0;
- i2c_stuff->adapter.algo_data = &i2c_stuff->algo;
- i2c_stuff->adapter.dev.parent = NULL;
- i2c_stuff->algo.setsda = via_i2c_setsda;
- i2c_stuff->algo.setscl = via_i2c_setscl;
- i2c_stuff->algo.getsda = via_i2c_getsda;
- i2c_stuff->algo.getscl = via_i2c_getscl;
- i2c_stuff->algo.udelay = 40;
- i2c_stuff->algo.timeout = 20;
- i2c_stuff->algo.data = i2c_stuff;
-
- i2c_set_adapdata(&i2c_stuff->adapter, i2c_stuff);
+ struct via_i2c_stuff *stuff = &via_i2c_par[which];
- /* Raise SCL and SDA */
- i2c_stuff->i2c_port = I2CPORTINDEX;
- via_i2c_setsda(i2c_stuff, 1);
- via_i2c_setscl(i2c_stuff, 1);
+ return &stuff->adapter;
+}
+EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
- i2c_stuff->i2c_port = GPIOPORTINDEX;
- via_i2c_setsda(i2c_stuff, 1);
- via_i2c_setscl(i2c_stuff, 1);
- udelay(20);
- ret = i2c_bit_add_bus(&i2c_stuff->adapter);
- if (ret == 0)
- DEBUG_MSG("I2C bus %s registered.\n", i2c_stuff->adapter.name);
+static int create_i2c_bus(struct i2c_adapter *adapter,
+ struct i2c_algo_bit_data *algo,
+ struct via_port_cfg *adap_cfg,
+ struct pci_dev *pdev)
+{
+ algo->setsda = via_i2c_setsda;
+ algo->setscl = via_i2c_setscl;
+ algo->getsda = via_i2c_getsda;
+ algo->getscl = via_i2c_getscl;
+ algo->udelay = 40;
+ algo->timeout = 20;
+ algo->data = adap_cfg;
+
+ sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
+ adap_cfg->ioport_index);
+ adapter->owner = THIS_MODULE;
+ adapter->id = 0x01FFFF;
+ adapter->class = I2C_CLASS_DDC;
+ adapter->algo_data = algo;
+ if (pdev)
+ adapter->dev.parent = &pdev->dev;
else
- DEBUG_MSG("Failed to register I2C bus %s.\n",
- i2c_stuff->adapter.name);
- return ret;
+ adapter->dev.parent = NULL;
+ /* i2c_set_adapdata(adapter, adap_cfg); */
+
+ /* Raise SCL and SDA */
+ via_i2c_setsda(adap_cfg, 1);
+ via_i2c_setscl(adap_cfg, 1);
+ udelay(20);
+
+ return i2c_bit_add_bus(adapter);
+}
+
+static int viafb_i2c_probe(struct platform_device *platdev)
+{
+ int i, ret;
+ struct via_port_cfg *configs;
+
+ i2c_vdev = platdev->dev.platform_data;
+ configs = i2c_vdev->port_cfg;
+
+ for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+ struct via_port_cfg *adap_cfg = configs++;
+ struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
+
+ i2c_stuff->is_active = 0;
+ if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C)
+ continue;
+ ret = create_i2c_bus(&i2c_stuff->adapter,
+ &i2c_stuff->algo, adap_cfg,
+ NULL); /* FIXME: PCIDEV */
+ if (ret < 0) {
+ printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n",
+ i, ret);
+ continue; /* Still try to make the rest */
+ }
+ i2c_stuff->is_active = 1;
+ }
+
+ return 0;
+}
+
+static int viafb_i2c_remove(struct platform_device *platdev)
+{
+ int i;
+
+ for (i = 0; i < VIAFB_NUM_PORTS; i++) {
+ struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
+ /*
+ * Only remove those entries in the array that we've
+ * actually used (and thus initialized algo_data)
+ */
+ if (i2c_stuff->is_active)
+ i2c_del_adapter(&i2c_stuff->adapter);
+ }
+ return 0;
+}
+
+static struct platform_driver via_i2c_driver = {
+ .driver = {
+ .name = "viafb-i2c",
+ },
+ .probe = viafb_i2c_probe,
+ .remove = viafb_i2c_remove,
+};
+
+int viafb_i2c_init(void)
+{
+ return platform_driver_register(&via_i2c_driver);
}
-void viafb_delete_i2c_buss(void *par)
+void viafb_i2c_exit(void)
{
- i2c_del_adapter(&((struct viafb_par *)par)->shared->i2c_stuff.adapter);
+ platform_driver_unregister(&via_i2c_driver);
}
diff --git a/drivers/video/via/via_modesetting.c b/drivers/video/via/via_modesetting.c
new file mode 100644
index 00000000000..3cddcff88ab
--- /dev/null
+++ b/drivers/video/via/via_modesetting.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
+ * 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, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ * basic modesetting functions
+ */
+
+#include <linux/kernel.h>
+#include <linux/via-core.h>
+#include "via_modesetting.h"
+#include "share.h"
+#include "debug.h"
+
+void via_set_primary_address(u32 addr)
+{
+ DEBUG_MSG(KERN_DEBUG "via_set_primary_address(0x%08X)\n", addr);
+ via_write_reg(VIACR, 0x0D, addr & 0xFF);
+ via_write_reg(VIACR, 0x0C, (addr >> 8) & 0xFF);
+ via_write_reg(VIACR, 0x34, (addr >> 16) & 0xFF);
+ via_write_reg_mask(VIACR, 0x48, (addr >> 24) & 0x1F, 0x1F);
+}
+
+void via_set_secondary_address(u32 addr)
+{
+ DEBUG_MSG(KERN_DEBUG "via_set_secondary_address(0x%08X)\n", addr);
+ /* secondary display supports only quadword aligned memory */
+ via_write_reg_mask(VIACR, 0x62, (addr >> 2) & 0xFE, 0xFE);
+ via_write_reg(VIACR, 0x63, (addr >> 10) & 0xFF);
+ via_write_reg(VIACR, 0x64, (addr >> 18) & 0xFF);
+ via_write_reg_mask(VIACR, 0xA3, (addr >> 26) & 0x07, 0x07);
+}
+
+void via_set_primary_pitch(u32 pitch)
+{
+ DEBUG_MSG(KERN_DEBUG "via_set_primary_pitch(0x%08X)\n", pitch);
+ /* spec does not say that first adapter skips 3 bits but old
+ * code did it and seems to be reasonable in analogy to 2nd adapter
+ */
+ pitch = pitch >> 3;
+ via_write_reg(VIACR, 0x13, pitch & 0xFF);
+ via_write_reg_mask(VIACR, 0x35, (pitch >> (8 - 5)) & 0xE0, 0xE0);
+}
+
+void via_set_secondary_pitch(u32 pitch)
+{
+ DEBUG_MSG(KERN_DEBUG "via_set_secondary_pitch(0x%08X)\n", pitch);
+ pitch = pitch >> 3;
+ via_write_reg(VIACR, 0x66, pitch & 0xFF);
+ via_write_reg_mask(VIACR, 0x67, (pitch >> 8) & 0x03, 0x03);
+ via_write_reg_mask(VIACR, 0x71, (pitch >> (10 - 7)) & 0x80, 0x80);
+}
+
+void via_set_primary_color_depth(u8 depth)
+{
+ u8 value;
+
+ DEBUG_MSG(KERN_DEBUG "via_set_primary_color_depth(%d)\n", depth);
+ switch (depth) {
+ case 8:
+ value = 0x00;
+ break;
+ case 15:
+ value = 0x04;
+ break;
+ case 16:
+ value = 0x14;
+ break;
+ case 24:
+ value = 0x0C;
+ break;
+ case 30:
+ value = 0x08;
+ break;
+ default:
+ printk(KERN_WARNING "via_set_primary_color_depth: "
+ "Unsupported depth: %d\n", depth);
+ return;
+ }
+
+ via_write_reg_mask(VIASR, 0x15, value, 0x1C);
+}
+
+void via_set_secondary_color_depth(u8 depth)
+{
+ u8 value;
+
+ DEBUG_MSG(KERN_DEBUG "via_set_secondary_color_depth(%d)\n", depth);
+ switch (depth) {
+ case 8:
+ value = 0x00;
+ break;
+ case 16:
+ value = 0x40;
+ break;
+ case 24:
+ value = 0xC0;
+ break;
+ case 30:
+ value = 0x80;
+ break;
+ default:
+ printk(KERN_WARNING "via_set_secondary_color_depth: "
+ "Unsupported depth: %d\n", depth);
+ return;
+ }
+
+ via_write_reg_mask(VIACR, 0x67, value, 0xC0);
+}
diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_modesetting.h
index 3a13242a315..ae35cfdeb37 100644
--- a/drivers/video/via/via_i2c.h
+++ b/drivers/video/via/via_modesetting.h
@@ -1,46 +1,38 @@
/*
* Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
-
+ * Copyright 2010 Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+ *
* 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, or (at your option) any later version.
-
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; 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.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef __VIA_I2C_H__
-#define __VIA_I2C_H__
+/*
+ * basic modesetting functions
+ */
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
+#ifndef __VIA_MODESETTING_H__
+#define __VIA_MODESETTING_H__
-struct via_i2c_stuff {
- u16 i2c_port; /* GPIO or I2C port */
- struct i2c_adapter adapter;
- struct i2c_algo_bit_data algo;
-};
+#include <linux/types.h>
-#define I2CPORT 0x3c4
-#define I2CPORTINDEX 0x31
-#define GPIOPORT 0x3C4
-#define GPIOPORTINDEX 0x2C
-#define I2C_BUS 1
-#define GPIO_BUS 2
-#define DELAYPORT 0x3C3
+void via_set_primary_address(u32 addr);
+void via_set_secondary_address(u32 addr);
+void via_set_primary_pitch(u32 pitch);
+void via_set_secondary_pitch(u32 pitch);
+void via_set_primary_color_depth(u8 depth);
+void via_set_secondary_color_depth(u8 depth);
-int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata);
-int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data);
-int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len);
-int viafb_create_i2c_bus(void *par);
-void viafb_delete_i2c_buss(void *par);
-#endif /* __VIA_I2C_H__ */
+#endif /* __VIA_MODESETTING_H__ */
diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c
index aefdeeec89b..d05ccb62b55 100644
--- a/drivers/video/via/via_utility.c
+++ b/drivers/video/via/via_utility.c
@@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
#include "global.h"
void viafb_get_device_support_state(u32 *support_state)
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 777b38a06d4..1082541358f 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
* Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
* This program is free software; you can redistribute it and/or
@@ -23,8 +23,9 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
-#define _MASTER_FILE
+#include <linux/via-core.h>
+#define _MASTER_FILE
#include "global.h"
static char *viafb_name = "Via";
@@ -221,7 +222,7 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
/* Adjust var according to our driver's own table */
viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
if (info->var.accel_flags & FB_ACCELF_TEXT &&
- !ppar->shared->engine_mmio)
+ !ppar->shared->vdev->engine_mmio)
info->var.accel_flags = 0;
return 0;
@@ -317,12 +318,12 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
if (!viafb_dual_fb) {
- viafb_set_primary_address(vram_addr);
- viafb_set_secondary_address(vram_addr);
+ via_set_primary_address(vram_addr);
+ via_set_secondary_address(vram_addr);
} else if (viapar->iga_path == IGA1)
- viafb_set_primary_address(vram_addr);
+ via_set_primary_address(vram_addr);
else
- viafb_set_secondary_address(vram_addr);
+ via_set_secondary_address(vram_addr);
return 0;
}
@@ -577,14 +578,9 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
break;
case VIAFB_SET_GAMMA_LUT:
- viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
- if (!viafb_gamma_table)
- return -ENOMEM;
- if (copy_from_user(viafb_gamma_table, argp,
- 256 * sizeof(u32))) {
- kfree(viafb_gamma_table);
- return -EFAULT;
- }
+ viafb_gamma_table = memdup_user(argp, 256 * sizeof(u32));
+ if (IS_ERR(viafb_gamma_table))
+ return PTR_ERR(viafb_gamma_table);
viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
kfree(viafb_gamma_table);
break;
@@ -696,7 +692,7 @@ static void viafb_fillrect(struct fb_info *info,
rop = 0xF0;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: fillrect\n");
- if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_FILL,
+ if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_FILL,
rect->width, rect->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, rect->dx, rect->dy,
NULL, 0, 0, 0, 0, fg_color, 0, rop))
@@ -718,7 +714,7 @@ static void viafb_copyarea(struct fb_info *info,
return;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: copyarea\n");
- if (shared->hw_bitblt(shared->engine_mmio, VIA_BITBLT_COLOR,
+ if (shared->hw_bitblt(shared->vdev->engine_mmio, VIA_BITBLT_COLOR,
area->width, area->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, area->dx, area->dy,
NULL, viapar->vram_addr, info->fix.line_length,
@@ -755,7 +751,7 @@ static void viafb_imageblit(struct fb_info *info,
op = VIA_BITBLT_COLOR;
DEBUG_MSG(KERN_DEBUG "viafb 2D engine: imageblit\n");
- if (shared->hw_bitblt(shared->engine_mmio, op,
+ if (shared->hw_bitblt(shared->vdev->engine_mmio, op,
image->width, image->height, info->var.bits_per_pixel,
viapar->vram_addr, info->fix.line_length, image->dx, image->dy,
(u32 *)image->data, 0, 0, 0, 0, fg_color, bg_color, 0))
@@ -765,7 +761,7 @@ static void viafb_imageblit(struct fb_info *info,
static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct viafb_par *viapar = info->par;
- void __iomem *engine = viapar->shared->engine_mmio;
+ void __iomem *engine = viapar->shared->vdev->engine_mmio;
u32 temp, xx, yy, bg_color = 0, fg_color = 0,
chip_name = viapar->shared->chip_info.gfx_chip_name;
int i, j = 0, cur_size = 64;
@@ -1018,8 +1014,8 @@ static void viafb_set_device(struct device_t active_dev)
viafb_SAMM_ON = active_dev.samm;
viafb_primary_dev = active_dev.primary_dev;
- viafb_set_primary_address(0);
- viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+ via_set_primary_address(0);
+ via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
viafb_set_iga_path();
}
@@ -1165,8 +1161,9 @@ static int apply_device_setting(struct viafb_ioctl_setting setting_info,
if (viafb_SAMM_ON)
viafb_primary_dev = setting_info.primary_device;
- viafb_set_primary_address(0);
- viafb_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
+ via_set_primary_address(0);
+ via_set_secondary_address(viafb_SAMM_ON ?
+ viafb_second_offset : 0);
viafb_set_iga_path();
}
need_set_mode = 1;
@@ -1325,6 +1322,8 @@ static void parse_dvi_port(void)
output_interface);
}
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
+
/*
* The proc filesystem read/write function, a simple proc implement to
* get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
@@ -1701,16 +1700,21 @@ static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
}
static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
{
- /* no problem if it was not registered */
+ struct chip_information *chip_info = &viaparinfo->shared->chip_info;
+
remove_proc_entry("dvp0", viafb_entry);/* parent dir */
remove_proc_entry("dvp1", viafb_entry);
remove_proc_entry("dfph", viafb_entry);
remove_proc_entry("dfpl", viafb_entry);
- remove_proc_entry("vt1636", viafb_entry);
- remove_proc_entry("vt1625", viafb_entry);
+ if (chip_info->lvds_chip_info.lvds_chip_name == VT1636_LVDS
+ || chip_info->lvds_chip_info2.lvds_chip_name == VT1636_LVDS)
+ remove_proc_entry("vt1636", viafb_entry);
+
remove_proc_entry("viafb", NULL);
}
+#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
+
static int parse_mode(const char *str, u32 *xres, u32 *yres)
{
char *ptr;
@@ -1732,12 +1736,13 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres)
return 0;
}
-static int __devinit via_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+
+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;
DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
@@ -1749,14 +1754,15 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
*/
viafbinfo = framebuffer_alloc(viafb_par_length +
ALIGN(sizeof(struct viafb_shared), BITS_PER_LONG/8),
- &pdev->dev);
+ &vdev->pdev->dev);
if (!viafbinfo) {
printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
- return -ENODEV;
+ return -ENOMEM;
}
viaparinfo = (struct viafb_par *)viafbinfo->par;
viaparinfo->shared = viafbinfo->par + viafb_par_length;
+ viaparinfo->shared->vdev = vdev;
viaparinfo->vram_addr = 0;
viaparinfo->tmds_setting_info = &viaparinfo->shared->tmds_setting_info;
viaparinfo->lvds_setting_info = &viaparinfo->shared->lvds_setting_info;
@@ -1774,23 +1780,20 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
if (!viafb_SAMM_ON)
viafb_dual_fb = 0;
- /* Set up I2C bus stuff */
- viafb_create_i2c_bus(viaparinfo);
-
- viafb_init_chip_info(pdev, ent);
- viaparinfo->fbmem = pci_resource_start(pdev, 0);
- viaparinfo->memsize = viafb_get_fb_size_from_pci();
+ viafb_init_chip_info(vdev->chip_type);
+ /*
+ * The framebuffer will have been successfully mapped by
+ * the core (or we'd not be here), but we still need to
+ * set up our own accounting.
+ */
+ viaparinfo->fbmem = vdev->fbmem_start;
+ viaparinfo->memsize = vdev->fbmem_len;
viaparinfo->fbmem_free = viaparinfo->memsize;
viaparinfo->fbmem_used = 0;
- viafbinfo->screen_base = ioremap_nocache(viaparinfo->fbmem,
- viaparinfo->memsize);
- if (!viafbinfo->screen_base) {
- printk(KERN_INFO "ioremap failed\n");
- return -ENOMEM;
- }
+ viafbinfo->screen_base = vdev->fbmem;
- viafbinfo->fix.mmio_start = pci_resource_start(pdev, 1);
- viafbinfo->fix.mmio_len = pci_resource_len(pdev, 1);
+ viafbinfo->fix.mmio_start = vdev->engine_start;
+ viafbinfo->fix.mmio_len = vdev->engine_len;
viafbinfo->node = 0;
viafbinfo->fbops = &viafb_ops;
viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
@@ -1858,12 +1861,13 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
viafbinfo->var = default_var;
if (viafb_dual_fb) {
- viafbinfo1 = framebuffer_alloc(viafb_par_length, &pdev->dev);
+ viafbinfo1 = framebuffer_alloc(viafb_par_length,
+ &vdev->pdev->dev);
if (!viafbinfo1) {
printk(KERN_ERR
"allocate the second framebuffer struct error\n");
- framebuffer_release(viafbinfo);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out_fb_release;
}
viaparinfo1 = viafbinfo1->par;
memcpy(viaparinfo1, viaparinfo, viafb_par_length);
@@ -1914,48 +1918,66 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
viaparinfo->depth = fb_get_color_depth(&viafbinfo->var,
&viafbinfo->fix);
default_var.activate = FB_ACTIVATE_NOW;
- fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+ rc = fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+ if (rc)
+ goto out_fb1_release;
if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
&& (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
- if (register_framebuffer(viafbinfo1) < 0)
- return -EINVAL;
+ rc = register_framebuffer(viafbinfo1);
+ if (rc)
+ goto out_dealloc_cmap;
}
- if (register_framebuffer(viafbinfo) < 0)
- return -EINVAL;
+ rc = register_framebuffer(viafbinfo);
+ if (rc)
+ goto out_fb1_unreg_lcd_cle266;
if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
|| (viaparinfo->chip_info->gfx_chip_name !=
UNICHROME_CLE266))) {
- if (register_framebuffer(viafbinfo1) < 0)
- return -EINVAL;
+ rc = register_framebuffer(viafbinfo1);
+ if (rc)
+ goto out_fb_unreg;
}
DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
viafbinfo->node, viafbinfo->fix.id, default_var.xres,
default_var.yres, default_var.bits_per_pixel);
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
viafb_init_proc(&viaparinfo->shared->proc_entry);
+#endif
viafb_init_dac(IGA2);
return 0;
+
+out_fb_unreg:
+ unregister_framebuffer(viafbinfo);
+out_fb1_unreg_lcd_cle266:
+ if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
+ && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
+ unregister_framebuffer(viafbinfo1);
+out_dealloc_cmap:
+ fb_dealloc_cmap(&viafbinfo->cmap);
+out_fb1_release:
+ if (viafbinfo1)
+ framebuffer_release(viafbinfo1);
+out_fb_release:
+ framebuffer_release(viafbinfo);
+ return rc;
}
-static void __devexit via_pci_remove(struct pci_dev *pdev)
+void __devexit via_fb_pci_remove(struct pci_dev *pdev)
{
DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
fb_dealloc_cmap(&viafbinfo->cmap);
unregister_framebuffer(viafbinfo);
if (viafb_dual_fb)
unregister_framebuffer(viafbinfo1);
- iounmap((void *)viafbinfo->screen_base);
- iounmap(viaparinfo->shared->engine_mmio);
-
- viafb_delete_i2c_buss(viaparinfo);
-
+#ifdef CONFIG_FB_VIA_DIRECT_PROCFS
+ viafb_remove_proc(viaparinfo->shared->proc_entry);
+#endif
framebuffer_release(viafbinfo);
if (viafb_dual_fb)
framebuffer_release(viafbinfo1);
-
- viafb_remove_proc(viaparinfo->shared->proc_entry);
}
#ifndef MODULE
@@ -2031,41 +2053,10 @@ static int __init viafb_setup(char *options)
}
#endif
-static struct pci_device_id viafb_pci_table[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
- .driver_data = UNICHROME_CLE266 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
- .driver_data = UNICHROME_PM800 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
- .driver_data = UNICHROME_K400 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
- .driver_data = UNICHROME_K800 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
- .driver_data = UNICHROME_CN700 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
- .driver_data = UNICHROME_K8M890 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
- .driver_data = UNICHROME_CX700 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
- .driver_data = UNICHROME_P4M900 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
- .driver_data = UNICHROME_CN750 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
- .driver_data = UNICHROME_VX800 },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),
- .driver_data = UNICHROME_VX855 },
- { }
-};
-MODULE_DEVICE_TABLE(pci, viafb_pci_table);
-
-static struct pci_driver viafb_driver = {
- .name = "viafb",
- .id_table = viafb_pci_table,
- .probe = via_pci_probe,
- .remove = __devexit_p(via_pci_remove),
-};
-
-static int __init viafb_init(void)
+/*
+ * These are called out of via-core for now.
+ */
+int __init viafb_init(void)
{
u32 dummy;
#ifndef MODULE
@@ -2084,13 +2075,12 @@ static int __init viafb_init(void)
printk(KERN_INFO
"VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
VERSION_MAJOR, VERSION_MINOR);
- return pci_register_driver(&viafb_driver);
+ return 0;
}
-static void __exit viafb_exit(void)
+void __exit viafb_exit(void)
{
DEBUG_MSG(KERN_INFO "viafb_exit!\n");
- pci_unregister_driver(&viafb_driver);
}
static struct fb_ops viafb_ops = {
@@ -2110,8 +2100,6 @@ static struct fb_ops viafb_ops = {
.fb_sync = viafb_sync,
};
-module_init(viafb_init);
-module_exit(viafb_exit);
#ifdef MODULE
module_param(viafb_mode, charp, S_IRUSR);
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
index 61b5953cd15..52a35fabba9 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -24,12 +24,12 @@
#include <linux/proc_fs.h>
#include <linux/fb.h>
+#include <linux/spinlock.h>
#include "ioctl.h"
#include "share.h"
#include "chip.h"
#include "hw.h"
-#include "via_i2c.h"
#define VERSION_MAJOR 2
#define VERSION_KERNEL 6 /* For kernel 2.6 */
@@ -37,11 +37,11 @@
#define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */
#define VERSION_MINOR 4
+#define VIAFB_NUM_I2C 5
+
struct viafb_shared {
struct proc_dir_entry *proc_entry; /*viafb proc entry */
-
- /* I2C stuff */
- struct via_i2c_stuff i2c_stuff;
+ struct viafb_dev *vdev; /* Global dev info */
/* All the information will be needed to set engine */
struct tmds_setting_information tmds_setting_info;
@@ -51,7 +51,6 @@ struct viafb_shared {
struct chip_information chip_info;
/* hardware acceleration stuff */
- void __iomem *engine_mmio;
u32 cursor_vram_addr;
u32 vq_vram_addr; /* virtual queue address in video ram */
int (*hw_bitblt)(void __iomem *engine, u8 op, u32 width, u32 height,
@@ -99,4 +98,9 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information
*plvds_chip_info, struct IODATA io_data);
+int via_fb_pci_probe(struct viafb_dev *vdev);
+void via_fb_pci_remove(struct pci_dev *pdev);
+/* Temporary */
+int viafb_init(void);
+void viafb_exit(void);
#endif /* __VIAFBDEV_H__ */
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
index af50e244016..2dbad3c0f67 100644
--- a/drivers/video/via/viamode.c
+++ b/drivers/video/via/viamode.c
@@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
#include "global.h"
struct res_map_refresh res_map_refresh_tbl[] = {
/*hres, vres, vclock, vmode_refresh*/
@@ -66,6 +67,7 @@ struct res_map_refresh res_map_refresh_tbl[] = {
{1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60},
{1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60},
{1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60},
+ {1200, 900, RES_1200X900_60HZ_PIXCLOCK, 60},
{1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60},
{1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50},
{1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50},
@@ -759,6 +761,16 @@ struct crt_mode_table CRTM1200x720[] = {
{1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
};
+/* 1200x900 (DCON) */
+struct crt_mode_table DCON1200x900[] = {
+ /* r_rate, vclk, hsp, vsp */
+ {REFRESH_60, CLK_57_275M, M1200X900_R60_HSP, M1200X900_R60_VSP,
+ /* The correct htotal is 1240, but this doesn't raster on VX855. */
+ /* Via suggested changing to a multiple of 16, hence 1264. */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {1264, 1200, 1200, 64, 1211, 32, 912, 900, 900, 12, 901, 10} }
+};
+
/* 1280x600 (GTF) */
struct crt_mode_table CRTM1280x600[] = {
/* r_rate, vclk, hsp, vsp */
@@ -937,6 +949,9 @@ struct VideoModeTable viafb_modes[] = {
/* Display : 1200x720 (GTF) */
{CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
+ /* Display : 1200x900 (DCON) */
+ {DCON1200x900, ARRAY_SIZE(DCON1200x900)},
+
/* Display : 1280x600 (GTF) */
{CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c
index a6b37494e79..d65bf1aee87 100644
--- a/drivers/video/via/vt1636.c
+++ b/drivers/video/via/vt1636.c
@@ -19,6 +19,8 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/via-core.h>
+#include <linux/via_i2c.h>
#include "global.h"
u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
@@ -27,9 +29,8 @@ u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
{
u8 data;
- viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
- viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data);
-
+ viafb_i2c_readbyte(plvds_chip_info->i2c_port,
+ plvds_chip_info->lvds_chip_slave_addr, index, &data);
return data;
}
@@ -39,14 +40,13 @@ void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
{
int index, data;
- viaparinfo->shared->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
-
index = io_data.Index;
data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info,
index);
data = (data & (~io_data.Mask)) | io_data.Data;
- viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data);
+ viafb_i2c_writebyte(plvds_chip_info->i2c_port,
+ plvds_chip_info->lvds_chip_slave_addr, index, data);
}
void viafb_init_lvds_vt1636(struct lvds_setting_information
@@ -159,7 +159,7 @@ void viafb_disable_lvds_vt1636(struct lvds_setting_information
}
}
-bool viafb_lvds_identify_vt1636(void)
+bool viafb_lvds_identify_vt1636(u8 i2c_adapter)
{
u8 Buffer[2];
@@ -167,26 +167,20 @@ bool viafb_lvds_identify_vt1636(void)
/* Sense VT1636 LVDS Transmiter */
viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
- VT1636_LVDS_I2C_ADDR;
+ VT1636_LVDS_I2C_ADDR;
/* Check vendor ID first: */
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
- lvds_chip_slave_addr,
- 0x00, &Buffer[0]);
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
- lvds_chip_slave_addr,
- 0x01, &Buffer[1]);
+ if (viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR,
+ 0x00, &Buffer[0]))
+ return false;
+ viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x01, &Buffer[1]);
if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11)))
return false;
/* Check Chip ID: */
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
- lvds_chip_slave_addr,
- 0x02, &Buffer[0]);
- viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
- lvds_chip_slave_addr,
- 0x03, &Buffer[1]);
+ viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x02, &Buffer[0]);
+ viafb_i2c_readbyte(i2c_adapter, VT1636_LVDS_I2C_ADDR, 0x03, &Buffer[1]);
if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) {
viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
VT1636_LVDS;
diff --git a/drivers/video/via/vt1636.h b/drivers/video/via/vt1636.h
index 2a150c58c7e..4c1314e5746 100644
--- a/drivers/video/via/vt1636.h
+++ b/drivers/video/via/vt1636.h
@@ -22,7 +22,7 @@
#ifndef _VT1636_H_
#define _VT1636_H_
#include "chip.h"
-bool viafb_lvds_identify_vt1636(void);
+bool viafb_lvds_identify_vt1636(u8 i2c_adapter);
void viafb_init_lvds_vt1636(struct lvds_setting_information
*plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
void viafb_enable_lvds_vt1636(struct lvds_setting_information
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c
index 31b0e17ed09..e66b8b19ce5 100644
--- a/drivers/video/w100fb.c
+++ b/drivers/video/w100fb.c
@@ -53,7 +53,7 @@ static void w100_update_enable(void);
static void w100_update_disable(void);
static void calc_hsync(struct w100fb_par *par);
static void w100_init_graphic_engine(struct w100fb_par *par);
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq);
+struct w100_pll_info *w100_get_xtal_table(unsigned int freq) __devinit;
/* Pseudo palette size */
#define MAX_PALETTES 16
@@ -782,7 +782,7 @@ out:
}
-static int w100fb_remove(struct platform_device *pdev)
+static int __devexit w100fb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
struct w100fb_par *par=info->par;
@@ -1020,7 +1020,7 @@ static struct pll_entries {
{ 0 },
};
-struct w100_pll_info *w100_get_xtal_table(unsigned int freq)
+struct w100_pll_info __devinit *w100_get_xtal_table(unsigned int freq)
{
struct pll_entries *pll_entry = w100_pll_tables;
@@ -1611,7 +1611,7 @@ static void w100_vsync(void)
static struct platform_driver w100fb_driver = {
.probe = w100fb_probe,
- .remove = w100fb_remove,
+ .remove = __devexit_p(w100fb_remove),
.suspend = w100fb_suspend,
.resume = w100fb_resume,
.driver = {
@@ -1619,7 +1619,7 @@ static struct platform_driver w100fb_driver = {
},
};
-int __devinit w100fb_init(void)
+int __init w100fb_init(void)
{
return platform_driver_register(&w100fb_driver);
}
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 3fcb83f0388..574dc54e12d 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -423,7 +423,7 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
* To check whether the core is connected directly to DCR or PLB
* interface and initialize the tft_access accordingly.
*/
- p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL);
+ p = (u32 *)of_get_property(op->dev.of_node, "xlnx,dcr-splb-slave-if", NULL);
tft_access = p ? *p : 0;
/*
@@ -432,41 +432,41 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
*/
if (tft_access) {
drvdata->flags |= PLB_ACCESS_FLAG;
- rc = of_address_to_resource(op->node, 0, &res);
+ rc = of_address_to_resource(op->dev.of_node, 0, &res);
if (rc) {
dev_err(&op->dev, "invalid address\n");
goto err;
}
} else {
res.start = 0;
- start = dcr_resource_start(op->node, 0);
- drvdata->dcr_len = dcr_resource_len(op->node, 0);
- drvdata->dcr_host = dcr_map(op->node, start, drvdata->dcr_len);
+ start = dcr_resource_start(op->dev.of_node, 0);
+ drvdata->dcr_len = dcr_resource_len(op->dev.of_node, 0);
+ drvdata->dcr_host = dcr_map(op->dev.of_node, start, drvdata->dcr_len);
if (!DCR_MAP_OK(drvdata->dcr_host)) {
dev_err(&op->dev, "invalid DCR address\n");
goto err;
}
}
- prop = of_get_property(op->node, "phys-size", &size);
+ prop = of_get_property(op->dev.of_node, "phys-size", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.screen_width_mm = prop[0];
pdata.screen_height_mm = prop[1];
}
- prop = of_get_property(op->node, "resolution", &size);
+ prop = of_get_property(op->dev.of_node, "resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xres = prop[0];
pdata.yres = prop[1];
}
- prop = of_get_property(op->node, "virtual-resolution", &size);
+ prop = of_get_property(op->dev.of_node, "virtual-resolution", &size);
if ((prop) && (size >= sizeof(u32)*2)) {
pdata.xvirt = prop[0];
pdata.yvirt = prop[1];
}
- if (of_find_property(op->node, "rotate-display", NULL))
+ if (of_find_property(op->dev.of_node, "rotate-display", NULL))
pdata.rotate_screen = 1;
dev_set_drvdata(&op->dev, drvdata);
@@ -492,13 +492,12 @@ static struct of_device_id xilinxfb_of_match[] __devinitdata = {
MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
static struct of_platform_driver xilinxfb_of_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .match_table = xilinxfb_of_match,
.probe = xilinxfb_of_probe,
.remove = __devexit_p(xilinxfb_of_remove),
.driver = {
.name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = xilinxfb_of_match,
},
};