diff options
Diffstat (limited to 'drivers/video')
51 files changed, 2303 insertions, 441 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index bfc62d1ee2f7..e6a8d8c0101d 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2321,6 +2321,15 @@ config FB_JZ4740 help Framebuffer support for the JZ4740 SoC. +config FB_MXS + tristate "MXS LCD framebuffer support" + depends on FB && ARCH_MXS + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Framebuffer support for the MXS SoC. + config FB_PUV3_UNIGFX tristate "PKUnity v3 Unigfx framebuffer support" depends on FB && UNICORE32 && ARCH_PUV3 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index b0eb3da24670..2ea44b6625fe 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -154,6 +154,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o +obj-$(CONFIG_FB_MXS) += mxsfb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index bac163450216..4b4e8dadd6b2 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -127,6 +127,7 @@ static void init_backlight(struct atmel_lcdfb_info *sinfo) return; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; bl = backlight_device_register("backlight", &sinfo->pdev->dev, sinfo, &atmel_lcdc_bl_ops, &props); diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 4cb6a576c567..b0b2ac335347 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -1818,6 +1818,7 @@ static void aty128_bl_init(struct aty128fb_par *par) snprintf(name, sizeof(name), "aty128bl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &aty128_bl_data, &props); diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 94e293fce1d2..d437b3daf1f5 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -2241,6 +2241,7 @@ static void aty_bl_init(struct atyfb_par *par) snprintf(name, sizeof(name), "atybl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &aty_bl_data, &props); diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c index 9b811ddbce83..db572df7e1ef 100644 --- a/drivers/video/aty/radeon_backlight.c +++ b/drivers/video/aty/radeon_backlight.c @@ -158,6 +158,7 @@ void radeonfb_bl_init(struct radeonfb_info *rinfo) snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, rinfo->info->dev, pdata, &radeon_bl_data, &props); diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index b224396b86d5..e59623a15f3f 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -227,6 +227,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; bl = backlight_device_register(name, &pdev->dev, data, &pm860x_backlight_ops, &props); diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e54a337227ea..0c9373bedd1f 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -109,6 +109,14 @@ config LCD_S6E63M0 If you have an S6E63M0 LCD Panel, say Y to enable its LCD control driver. +config LCD_LD9040 + tristate "LD9040 AMOLED LCD Driver" + depends on SPI && BACKLIGHT_CLASS_DEVICE + default n + help + If you have an LD9040 Panel, say Y to enable its + control driver. + endif # LCD_CLASS_DEVICE # @@ -236,12 +244,12 @@ config BACKLIGHT_MAX8925 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 X86 +config BACKLIGHT_APPLE + tristate "Apple Backlight Driver" + depends on X86 && ACPI help - If you have an Apple Macbook Pro with Nvidia graphics hardware say Y - to enable a driver for its backlight + If you have an Intel-based Apple say Y to enable a driver for its + backlight. config BACKLIGHT_TOSA tristate "Sharp SL-6000 Backlight Driver" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 44c0f81ad85d..b9ca8490df87 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -12,6 +12,7 @@ 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_LCD_LD9040) += ld9040.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o @@ -26,7 +27,7 @@ obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o -obj-$(CONFIG_BACKLIGHT_MBP_NVIDIA) += mbp_nvidia_bl.o +obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index 9f436e014f85..af3119707dbf 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -303,6 +303,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) mutex_init(&data->lock); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = ADP5020_MAX_BRIGHTNESS; bl = backlight_device_register(pdev->name, data->master, data, &adp5520_bl_ops, &props); diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 734c650a47c4..d2a96a421ffd 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -709,6 +709,7 @@ static int __devinit adp8860_probe(struct i2c_client *client, i2c_set_clientdata(client, data); memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; props.max_brightness = ADP8860_MAX_BRIGHTNESS; mutex_init(&data->lock); diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c index fe9af129c5dd..c861c41af442 100644 --- a/drivers/video/backlight/adx_bl.c +++ b/drivers/video/backlight/adx_bl.c @@ -104,6 +104,7 @@ static int __devinit adx_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 0xff; bldev = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, bl, &adx_backlight_ops, &props); diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c new file mode 100644 index 000000000000..be98d152b7fd --- /dev/null +++ b/drivers/video/backlight/apple_bl.c @@ -0,0 +1,241 @@ +/* + * Backlight Driver for Intel-based Apples + * + * Copyright (c) Red Hat <mjg@redhat.com> + * Based on code from Pommed: + * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch> + * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org> + * Copyright (C) 2007 Julien BLACHE <jb@jblache.org> + * + * 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 triggers SMIs which cause the firmware to change the + * backlight brightness. This is icky in many ways, but it's impractical to + * get at the firmware code in order to figure out what it's actually doing. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/pci.h> +#include <linux/acpi.h> + +static struct backlight_device *apple_backlight_device; + +struct hw_data { + /* I/O resource to allocate. */ + unsigned long iostart; + unsigned long iolen; + /* Backlight operations structure. */ + const struct backlight_ops backlight_ops; + void (*set_brightness)(int); +}; + +static const struct hw_data *hw_data; + +#define DRIVER "apple_backlight: " + +/* Module parameters. */ +static int debug; +module_param_named(debug, debug, int, 0644); +MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); + +/* + * Implementation for machines with Intel chipset. + */ +static void intel_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0xb3); + outb(0xbf, 0xb2); +} + +static int intel_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", + intensity); + + intel_chipset_set_brightness(intensity); + return 0; +} + +static int intel_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0xb3); + outb(0xbf, 0xb2); + intensity = inb(0xb3) >> 4; + + if (debug) + printk(KERN_DEBUG DRIVER "read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct hw_data intel_chipset_data = { + .iostart = 0xb2, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = intel_chipset_get_intensity, + .update_status = intel_chipset_send_intensity, + }, + .set_brightness = intel_chipset_set_brightness, +}; + +/* + * Implementation for machines with Nvidia chipset. + */ +static void nvidia_chipset_set_brightness(int intensity) +{ + outb(0x04 | (intensity << 4), 0x52f); + outb(0xbf, 0x52e); +} + +static int nvidia_chipset_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (debug) + printk(KERN_DEBUG DRIVER "setting brightness to %d\n", + intensity); + + nvidia_chipset_set_brightness(intensity); + return 0; +} + +static int nvidia_chipset_get_intensity(struct backlight_device *bd) +{ + int intensity; + + outb(0x03, 0x52f); + outb(0xbf, 0x52e); + intensity = inb(0x52f) >> 4; + + if (debug) + printk(KERN_DEBUG DRIVER "read brightness of %d\n", + intensity); + + return intensity; +} + +static const struct hw_data nvidia_chipset_data = { + .iostart = 0x52e, + .iolen = 2, + .backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = nvidia_chipset_get_intensity, + .update_status = nvidia_chipset_send_intensity + }, + .set_brightness = nvidia_chipset_set_brightness, +}; + +static int __devinit apple_bl_add(struct acpi_device *dev) +{ + struct backlight_properties props; + struct pci_dev *host; + int intensity; + + host = pci_get_bus_and_slot(0, 0); + + if (!host) { + printk(KERN_ERR DRIVER "unable to find PCI host\n"); + return -ENODEV; + } + + if (host->vendor == PCI_VENDOR_ID_INTEL) + hw_data = &intel_chipset_data; + else if (host->vendor == PCI_VENDOR_ID_NVIDIA) + hw_data = &nvidia_chipset_data; + + pci_dev_put(host); + + if (!hw_data) { + printk(KERN_ERR DRIVER "unknown hardware\n"); + return -ENODEV; + } + + /* Check that the hardware responds - this may not work under EFI */ + + intensity = hw_data->backlight_ops.get_brightness(NULL); + + if (!intensity) { + hw_data->set_brightness(1); + if (!hw_data->backlight_ops.get_brightness(NULL)) + return -ENODEV; + + hw_data->set_brightness(0); + } + + if (!request_region(hw_data->iostart, hw_data->iolen, + "Apple backlight")) + return -ENXIO; + + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = 15; + apple_backlight_device = backlight_device_register("apple_backlight", + NULL, NULL, &hw_data->backlight_ops, &props); + + if (IS_ERR(apple_backlight_device)) { + release_region(hw_data->iostart, hw_data->iolen); + return PTR_ERR(apple_backlight_device); + } + + apple_backlight_device->props.brightness = + hw_data->backlight_ops.get_brightness(apple_backlight_device); + backlight_update_status(apple_backlight_device); + + return 0; +} + +static int __devexit apple_bl_remove(struct acpi_device *dev, int type) +{ + backlight_device_unregister(apple_backlight_device); + + release_region(hw_data->iostart, hw_data->iolen); + hw_data = NULL; + return 0; +} + +static const struct acpi_device_id apple_bl_ids[] = { + {"APP0002", 0}, + {"", 0}, +}; + +static struct acpi_driver apple_bl_driver = { + .name = "Apple backlight", + .ids = apple_bl_ids, + .ops = { + .add = apple_bl_add, + .remove = apple_bl_remove, + }, +}; + +static int __init apple_bl_init(void) +{ + return acpi_bus_register_driver(&apple_bl_driver); +} + +static void __exit apple_bl_exit(void) +{ + acpi_bus_unregister_driver(&apple_bl_driver); +} + +module_init(apple_bl_init); +module_exit(apple_bl_exit); + +MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); +MODULE_DESCRIPTION("Apple Backlight Driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(acpi, apple_bl_ids); +MODULE_ALIAS("mbp_nvidia_bl"); diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c index e6a66dab088c..0443a4f71858 100644 --- a/drivers/video/backlight/atmel-pwm-bl.c +++ b/drivers/video/backlight/atmel-pwm-bl.c @@ -168,6 +168,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = pdata->pwm_duty_max - pdata->pwm_duty_min; bldev = backlight_device_register("atmel-pwm-bl", &pdev->dev, pwmbl, &atmel_pwm_bl_ops, &props); diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 08703299ef61..80d292fb92d8 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -19,6 +19,12 @@ #include <asm/backlight.h> #endif +static const char const *backlight_types[] = { + [BACKLIGHT_RAW] = "raw", + [BACKLIGHT_PLATFORM] = "platform", + [BACKLIGHT_FIRMWARE] = "firmware", +}; + #if defined(CONFIG_FB) || (defined(CONFIG_FB_MODULE) && \ defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)) /* This callback gets called when something important happens inside a @@ -169,6 +175,14 @@ static ssize_t backlight_store_brightness(struct device *dev, return rc; } +static ssize_t backlight_show_type(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct backlight_device *bd = to_backlight_device(dev); + + return sprintf(buf, "%s\n", backlight_types[bd->props.type]); +} + static ssize_t backlight_show_max_brightness(struct device *dev, struct device_attribute *attr, char *buf) { @@ -234,6 +248,7 @@ static struct device_attribute bl_device_attributes[] = { __ATTR(actual_brightness, 0444, backlight_show_actual_brightness, NULL), __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL), + __ATTR(type, 0444, backlight_show_type, NULL), __ATTR_NULL, }; @@ -292,9 +307,16 @@ struct backlight_device *backlight_device_register(const char *name, dev_set_drvdata(&new_bd->dev, devdata); /* Set default properties */ - if (props) + if (props) { memcpy(&new_bd->props, props, sizeof(struct backlight_properties)); + if (props->type <= 0 || props->type >= BACKLIGHT_TYPE_MAX) { + WARN(1, "%s: invalid backlight type", name); + new_bd->props.type = BACKLIGHT_RAW; + } + } else { + new_bd->props.type = BACKLIGHT_RAW; + } rc = device_register(&new_bd->dev); if (rc) { diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index 1e71c35083bb..af6098396fe6 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -562,6 +562,7 @@ static int __devinit corgi_lcd_probe(struct spi_device *spi) lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = pdata->max_intensity; lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, lcd, &corgi_bl_ops, &props); diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 397d15eb1ea8..6c8c54041fae 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -193,6 +193,7 @@ static int cr_backlight_probe(struct platform_device *pdev) } memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; bdp = backlight_device_register("cr-backlight", &pdev->dev, NULL, &cr_backlight_ops, &props); if (IS_ERR(bdp)) { diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c index 87659ed79bd7..62043f12a5a4 100644 --- a/drivers/video/backlight/da903x_bl.c +++ b/drivers/video/backlight/da903x_bl.c @@ -136,6 +136,7 @@ static int da903x_backlight_probe(struct platform_device *pdev) da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2, DA9034_WLED_ISET(pdata->output_current)); + props.type = BACKLIGHT_RAW; props.max_brightness = max_brightness; bl = backlight_device_register(pdev->name, data->da903x_dev, data, &da903x_backlight_ops, &props); diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index b0cc49184803..9f1e389d51d2 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -87,6 +87,7 @@ static int __init ep93xxbl_probe(struct platform_device *dev) ep93xxbl->mmio = EP93XX_RASTER_BRIGHTNESS; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = EP93XX_MAX_BRIGHT; bl = backlight_device_register(dev->name, &dev->dev, ep93xxbl, &ep93xxbl_ops, &props); diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c index 312ca619735d..8c6befd65a33 100644 --- a/drivers/video/backlight/generic_bl.c +++ b/drivers/video/backlight/generic_bl.c @@ -91,6 +91,7 @@ static int genericbl_probe(struct platform_device *pdev) name = machinfo->name; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; bd = backlight_device_register(name, &pdev->dev, NULL, &genericbl_ops, &props); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 267d23f8d645..38aa00272141 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -109,6 +109,7 @@ static int __devinit hp680bl_probe(struct platform_device *pdev) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = HP680_MAX_INTENSITY; bd = backlight_device_register("hp680-bl", &pdev->dev, NULL, &hp680bl_ops, &props); diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c index 2f177b3a4885..de65d80159be 100644 --- a/drivers/video/backlight/jornada720_bl.c +++ b/drivers/video/backlight/jornada720_bl.c @@ -106,6 +106,7 @@ static int jornada_bl_probe(struct platform_device *pdev) struct backlight_device *bd; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = BL_MAX_BRIGHT; bd = backlight_device_register(S1D_DEVICENAME, &pdev->dev, NULL, &jornada_bl_ops, &props); @@ -146,12 +147,12 @@ static struct platform_driver jornada_bl_driver = { }, }; -int __init jornada_bl_init(void) +static int __init jornada_bl_init(void) { return platform_driver_register(&jornada_bl_driver); } -void __exit jornada_bl_exit(void) +static void __exit jornada_bl_exit(void) { platform_driver_unregister(&jornada_bl_driver); } diff --git a/drivers/video/backlight/jornada720_lcd.c b/drivers/video/backlight/jornada720_lcd.c index cbbb167fd268..d2ff658b4144 100644 --- a/drivers/video/backlight/jornada720_lcd.c +++ b/drivers/video/backlight/jornada720_lcd.c @@ -135,12 +135,12 @@ static struct platform_driver jornada_lcd_driver = { }, }; -int __init jornada_lcd_init(void) +static int __init jornada_lcd_init(void) { return platform_driver_register(&jornada_lcd_driver); } -void __exit jornada_lcd_exit(void) +static void __exit jornada_lcd_exit(void) { platform_driver_unregister(&jornada_lcd_driver); } diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c index f439a8632287..72dd5556a35b 100644 --- a/drivers/video/backlight/kb3886_bl.c +++ b/drivers/video/backlight/kb3886_bl.c @@ -149,6 +149,7 @@ static int kb3886bl_probe(struct platform_device *pdev) machinfo->limit_mask = -1; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = machinfo->max_intensity; kb3886_backlight_device = backlight_device_register("kb3886-bl", &pdev->dev, NULL, diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c new file mode 100644 index 000000000000..7281b2506a67 --- /dev/null +++ b/drivers/video/backlight/ld9040.c @@ -0,0 +1,819 @@ +/* + * ld9040 AMOLED LCD panel driver. + * + * Copyright (c) 2011 Samsung Electronics + * Author: Donghwa Lee <dh09.lee@samsung.com> + * Derived from drivers/video/backlight/s6e63m0.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 "ld9040_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 24 +#define power_is_on(pwr) ((pwr) <= FB_BLANK_NORMAL) + +struct ld9040 { + struct device *dev; + struct spi_device *spi; + unsigned int power; + unsigned int current_brightness; + + struct lcd_device *ld; + struct backlight_device *bd; + struct lcd_platform_data *lcd_pd; +}; + +static const unsigned short seq_swreset[] = { + 0x01, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_user_setting[] = { + 0xF0, 0x5A, + + DATA_ONLY, 0x5A, + ENDDEF, 0x00 +}; + +static const unsigned short seq_elvss_on[] = { + 0xB1, 0x0D, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x16, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gtcon[] = { + 0xF7, 0x09, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + ENDDEF, 0x00 +}; + +static const unsigned short seq_panel_condition[] = { + 0xF8, 0x05, + + DATA_ONLY, 0x65, + DATA_ONLY, 0x96, + DATA_ONLY, 0x71, + DATA_ONLY, 0x7D, + DATA_ONLY, 0x19, + DATA_ONLY, 0x3B, + DATA_ONLY, 0x0D, + DATA_ONLY, 0x19, + DATA_ONLY, 0x7E, + DATA_ONLY, 0x0D, + DATA_ONLY, 0xE2, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x7E, + DATA_ONLY, 0x7D, + DATA_ONLY, 0x07, + DATA_ONLY, 0x07, + DATA_ONLY, 0x20, + DATA_ONLY, 0x20, + DATA_ONLY, 0x20, + DATA_ONLY, 0x02, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_set1[] = { + 0xF9, 0x00, + + DATA_ONLY, 0xA7, + DATA_ONLY, 0xB4, + DATA_ONLY, 0xAE, + DATA_ONLY, 0xBF, + DATA_ONLY, 0x00, + DATA_ONLY, 0x91, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB2, + DATA_ONLY, 0xB4, + DATA_ONLY, 0xAA, + DATA_ONLY, 0xBB, + DATA_ONLY, 0x00, + DATA_ONLY, 0xAC, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB3, + DATA_ONLY, 0xB1, + DATA_ONLY, 0xAA, + DATA_ONLY, 0xBC, + DATA_ONLY, 0x00, + DATA_ONLY, 0xB3, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_ctrl[] = { + 0xFB, 0x02, + + DATA_ONLY, 0x5A, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gamma_start[] = { + 0xF9, COMMAND_ONLY, + + ENDDEF, 0x00 +}; + +static const unsigned short seq_apon[] = { + 0xF3, 0x00, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x0A, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_ctrl[] = { + 0xF2, 0x02, + + DATA_ONLY, 0x08, + DATA_ONLY, 0x08, + DATA_ONLY, 0x10, + DATA_ONLY, 0x10, + ENDDEF, 0x00 +}; + +static const unsigned short seq_manual_pwr[] = { + 0xB0, 0x04, + ENDDEF, 0x00 +}; + +static const unsigned short seq_pwr_ctrl[] = { + 0xF4, 0x0A, + + DATA_ONLY, 0x87, + DATA_ONLY, 0x25, + DATA_ONLY, 0x6A, + DATA_ONLY, 0x44, + DATA_ONLY, 0x02, + DATA_ONLY, 0x88, + ENDDEF, 0x00 +}; + +static const unsigned short seq_sleep_out[] = { + 0x11, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_sleep_in[] = { + 0x10, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_on[] = { + 0x29, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_display_off[] = { + 0x28, COMMAND_ONLY, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vci1_1st_en[] = { + 0xF3, 0x10, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl1_en[] = { + 0xF3, 0x11, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl2_en[] = { + 0xF3, 0x13, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vci1_2nd_en[] = { + 0xF3, 0x33, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vl3_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vreg1_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x01, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vgh_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x11, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vgl_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0x31, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x02, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vmos_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xB1, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vint_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xF1, + /* DATA_ONLY, 0x71, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_vbh_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xF9, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_vbl_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFD, + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + ENDDEF, 0x00 +}; + +static const unsigned short seq_gam_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x00, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_sd_amp_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x80, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_gls_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x81, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_els_en[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x83, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static const unsigned short seq_el_on[] = { + 0xF3, 0x37, + + DATA_ONLY, 0xFF, + /* DATA_ONLY, 0x73, VMOS/VBL/VBH not used */ + DATA_ONLY, 0x87, + DATA_ONLY, 0x00, + DATA_ONLY, 0x03, + /* DATA_ONLY, 0x02, VMOS/VBL/VBH not used */ + ENDDEF, 0x00 +}; + +static int ld9040_spi_write_byte(struct ld9040 *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 ld9040_spi_write(struct ld9040 *lcd, unsigned char address, + unsigned char command) +{ + int ret = 0; + + if (address != DATA_ONLY) + ret = ld9040_spi_write_byte(lcd, 0x0, address); + if (command != COMMAND_ONLY) + ret = ld9040_spi_write_byte(lcd, 0x1, command); + + return ret; +} + +static int ld9040_panel_send_sequence(struct ld9040 *lcd, + const unsigned short *wbuf) +{ + int ret = 0, i = 0; + + while ((wbuf[i] & DEFMASK) != ENDDEF) { + if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { + ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]); + if (ret) + break; + } else + udelay(wbuf[i+1]*1000); + i += 2; + } + + return ret; +} + +static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma) +{ + unsigned int i = 0; + int ret = 0; + + /* start gamma table updating. */ + ret = ld9040_panel_send_sequence(lcd, seq_gamma_start); + 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 = ld9040_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 = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl); + if (ret) + dev_err(lcd->dev, "failed to update gamma table.\n"); + +gamma_err: + return ret; +} + +static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma) +{ + int ret = 0; + + ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]); + + return ret; +} + + +static int ld9040_ldi_init(struct ld9040 *lcd) +{ + int ret, i; + static const unsigned short *init_seq[] = { + seq_user_setting, + seq_panel_condition, + seq_display_ctrl, + seq_manual_pwr, + seq_elvss_on, + seq_gtcon, + seq_gamma_set1, + seq_gamma_ctrl, + seq_sleep_out, + }; + + for (i = 0; i < ARRAY_SIZE(init_seq); i++) { + ret = ld9040_panel_send_sequence(lcd, init_seq[i]); + /* workaround: minimum delay time for transferring CMD */ + udelay(300); + if (ret) + break; + } + + return ret; +} + +static int ld9040_ldi_enable(struct ld9040 *lcd) +{ + int ret = 0; + + ret = ld9040_panel_send_sequence(lcd, seq_display_on); + + return ret; +} + +static int ld9040_ldi_disable(struct ld9040 *lcd) +{ + int ret; + + ret = ld9040_panel_send_sequence(lcd, seq_display_off); + ret = ld9040_panel_send_sequence(lcd, seq_sleep_in); + + return ret; +} + +static int ld9040_power_on(struct ld9040 *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; + } + + 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 = ld9040_ldi_init(lcd); + if (ret) { + dev_err(lcd->dev, "failed to initialize ldi.\n"); + return ret; + } + + ret = ld9040_ldi_enable(lcd); + if (ret) { + dev_err(lcd->dev, "failed to enable ldi.\n"); + return ret; + } + + return 0; +} + +static int ld9040_power_off(struct ld9040 *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 = ld9040_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 ld9040_power(struct ld9040 *lcd, int power) +{ + int ret = 0; + + if (power_is_on(power) && !power_is_on(lcd->power)) + ret = ld9040_power_on(lcd); + else if (!power_is_on(power) && power_is_on(lcd->power)) + ret = ld9040_power_off(lcd); + + if (!ret) + lcd->power = power; + + return ret; +} + +static int ld9040_set_power(struct lcd_device *ld, int power) +{ + struct ld9040 *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 ld9040_power(lcd, power); +} + +static int ld9040_get_power(struct lcd_device *ld) +{ + struct ld9040 *lcd = lcd_get_data(ld); + + return lcd->power; +} + +static int ld9040_get_brightness(struct backlight_device *bd) +{ + return bd->props.brightness; +} + +static int ld9040_set_brightness(struct backlight_device *bd) +{ + int ret = 0, brightness = bd->props.brightness; + struct ld9040 *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 = ld9040_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 ld9040_lcd_ops = { + .set_power = ld9040_set_power, + .get_power = ld9040_get_power, +}; + +static const struct backlight_ops ld9040_backlight_ops = { + .get_brightness = ld9040_get_brightness, + .update_status = ld9040_set_brightness, +}; + + +static int ld9040_probe(struct spi_device *spi) +{ + int ret = 0; + struct ld9040 *lcd = NULL; + struct lcd_device *ld = NULL; + struct backlight_device *bd = NULL; + + lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL); + if (!lcd) + return -ENOMEM; + + /* ld9040 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 = 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("ld9040", &spi->dev, lcd, &ld9040_lcd_ops); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + lcd->ld = ld; + + bd = backlight_device_register("ld9040-bl", &spi->dev, + lcd, &ld9040_backlight_ops, NULL); + if (IS_ERR(ld)) { + ret = PTR_ERR(ld); + goto out_free_lcd; + } + + bd->props.max_brightness = MAX_BRIGHTNESS; + bd->props.brightness = MAX_BRIGHTNESS; + lcd->bd = bd; + + /* + * 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; + + ld9040_power(lcd, FB_BLANK_UNBLANK); + } else + lcd->power = FB_BLANK_UNBLANK; + + dev_set_drvdata(&spi->dev, lcd); + + dev_info(&spi->dev, "ld9040 panel driver has been probed.\n"); + return 0; + +out_free_lcd: + kfree(lcd); + return ret; +} + +static int __devexit ld9040_remove(struct spi_device *spi) +{ + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + ld9040_power(lcd, FB_BLANK_POWERDOWN); + lcd_device_unregister(lcd->ld); + kfree(lcd); + + return 0; +} + +#if defined(CONFIG_PM) +static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg) +{ + int ret = 0; + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power); + + /* + * when lcd panel is suspend, lcd panel becomes off + * regardless of status. + */ + ret = ld9040_power(lcd, FB_BLANK_POWERDOWN); + + return ret; +} + +static int ld9040_resume(struct spi_device *spi) +{ + int ret = 0; + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + lcd->power = FB_BLANK_POWERDOWN; + + ret = ld9040_power(lcd, FB_BLANK_UNBLANK); + + return ret; +} +#else +#define ld9040_suspend NULL +#define ld9040_resume NULL +#endif + +/* Power down all displays on reboot, poweroff or halt. */ +static void ld9040_shutdown(struct spi_device *spi) +{ + struct ld9040 *lcd = dev_get_drvdata(&spi->dev); + + ld9040_power(lcd, FB_BLANK_POWERDOWN); +} + +static struct spi_driver ld9040_driver = { + .driver = { + .name = "ld9040", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + .probe = ld9040_probe, + .remove = __devexit_p(ld9040_remove), + .shutdown = ld9040_shutdown, + .suspend = ld9040_suspend, + .resume = ld9040_resume, +}; + +static int __init ld9040_init(void) +{ + return spi_register_driver(&ld9040_driver); +} + +static void __exit ld9040_exit(void) +{ + spi_unregister_driver(&ld9040_driver); +} + +module_init(ld9040_init); +module_exit(ld9040_exit); + +MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); +MODULE_DESCRIPTION("ld9040 LCD Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h new file mode 100644 index 000000000000..038d9c86ec03 --- /dev/null +++ b/drivers/video/backlight/ld9040_gamma.h @@ -0,0 +1,200 @@ +/* + * Gamma level definitions. + * + * Copyright (c) 2011 Samsung Electronics + * InKi Dae <inki.dae@samsung.com> + * Donghwa Lee <dh09.lee@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 _LD9040_BRIGHTNESS_H +#define _LD9040_BRIGHTNESS_H + +#define MAX_GAMMA_LEVEL 25 +#define GAMMA_TABLE_COUNT 21 + +/* gamma value: 2.2 */ +static const unsigned int ld9040_22_300[] = { + 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, + 0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac, + 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 +}; + +static const unsigned int ld9040_22_290[] = { + 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, + 0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4, + 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa +}; + +static const unsigned int ld9040_22_280[] = { + 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, + 0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0, + 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 +}; + +static const unsigned int ld9040_22_270[] = { + 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, + 0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d, + 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 + +}; +static const unsigned int ld9040_22_260[] = { + 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, + 0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a, + 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 +}; + +static const unsigned int ld9040_22_250[] = { + 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, + 0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97, + 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d +}; + +static const unsigned int ld9040_22_240[] = { + 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, + 0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94, + 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a +}; + +static const unsigned int ld9040_22_230[] = { + 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, + 0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90, + 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 +}; + +static const unsigned int ld9040_22_220[] = { + 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, + 0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e, + 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 +}; + +static const unsigned int ld9040_22_210[] = { + 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, + 0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a, + 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 +}; + +static const unsigned int ld9040_22_200[] = { + 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, + 0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86, + 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d +}; + +static const unsigned int ld9040_22_190[] = { + 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, + 0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82, + 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 +}; + +static const unsigned int ld9040_22_180[] = { + 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, + 0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f, + 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 +}; + +static const unsigned int ld9040_22_170[] = { + 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, + 0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a, + 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 +}; + +static const unsigned int ld9040_22_160[] = { + 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, + 0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76, + 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e +}; + +static const unsigned int ld9040_22_150[] = { + 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, + 0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72, + 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a +}; + +static const unsigned int ld9040_22_140[] = { + 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, + 0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e, + 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 +}; + +static const unsigned int ld9040_22_130[] = { + 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, + 0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a, + 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 +}; + +static const unsigned int ld9040_22_120[] = { + 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, + 0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65, + 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c +}; + +static const unsigned int ld9040_22_110[] = { + 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, + 0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60, + 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 +}; + +static const unsigned int ld9040_22_100[] = { + 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, + 0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c, + 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 +}; + +static const unsigned int ld9040_22_90[] = { + 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, + 0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56, + 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d +}; + +static const unsigned int ld9040_22_80[] = { + 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, + 0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51, + 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 +}; + +static const unsigned int ld9040_22_70[] = { + 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, + 0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b, + 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 +}; + +static const unsigned int ld9040_22_50[] = { + 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, + 0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d, + 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 +}; + +struct ld9040_gamma { + unsigned int *gamma_22_table[MAX_GAMMA_LEVEL]; +} gamma_table = { + .gamma_22_table[0] = (unsigned int *)&ld9040_22_50, + .gamma_22_table[1] = (unsigned int *)&ld9040_22_70, + .gamma_22_table[2] = (unsigned int *)&ld9040_22_80, + .gamma_22_table[3] = (unsigned int *)&ld9040_22_90, + .gamma_22_table[4] = (unsigned int *)&ld9040_22_100, + .gamma_22_table[5] = (unsigned int *)&ld9040_22_110, + .gamma_22_table[6] = (unsigned int *)&ld9040_22_120, + .gamma_22_table[7] = (unsigned int *)&ld9040_22_130, + .gamma_22_table[8] = (unsigned int *)&ld9040_22_140, + .gamma_22_table[9] = (unsigned int *)&ld9040_22_150, + .gamma_22_table[10] = (unsigned int *)&ld9040_22_160, + .gamma_22_table[11] = (unsigned int *)&ld9040_22_170, + .gamma_22_table[12] = (unsigned int *)&ld9040_22_180, + .gamma_22_table[13] = (unsigned int *)&ld9040_22_190, + .gamma_22_table[14] = (unsigned int *)&ld9040_22_200, + .gamma_22_table[15] = (unsigned int *)&ld9040_22_210, + .gamma_22_table[16] = (unsigned int *)&ld9040_22_220, + .gamma_22_table[17] = (unsigned int *)&ld9040_22_230, + .gamma_22_table[18] = (unsigned int *)&ld9040_22_240, + .gamma_22_table[19] = (unsigned int *)&ld9040_22_250, + .gamma_22_table[20] = (unsigned int *)&ld9040_22_260, + .gamma_22_table[21] = (unsigned int *)&ld9040_22_270, + .gamma_22_table[22] = (unsigned int *)&ld9040_22_280, + .gamma_22_table[23] = (unsigned int *)&ld9040_22_290, + .gamma_22_table[24] = (unsigned int *)&ld9040_22_300, +}; + +#endif diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c index d2f59015d517..bbca3127071e 100644 --- a/drivers/video/backlight/locomolcd.c +++ b/drivers/video/backlight/locomolcd.c @@ -184,6 +184,7 @@ static int locomolcd_probe(struct locomo_dev *ldev) local_irq_restore(flags); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 4; locomolcd_bl_device = backlight_device_register("locomo-bl", &ldev->dev, NULL, diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 209acc105cbc..07e8e273ced0 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -136,6 +136,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; bl = backlight_device_register(name, &pdev->dev, data, &max8925_backlight_ops, &props); diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c deleted file mode 100644 index 1485f7345f49..000000000000 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Backlight Driver for Nvidia 8600 in Macbook Pro - * - * Copyright (c) Red Hat <mjg@redhat.com> - * Based on code from Pommed: - * Copyright (C) 2006 Nicolas Boichat <nicolas @boichat.ch> - * Copyright (C) 2006 Felipe Alfaro Solana <felipe_alfaro @linuxmail.org> - * Copyright (C) 2007 Julien BLACHE <jb@jblache.org> - * - * 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 triggers SMIs which cause the firmware to change the - * backlight brightness. This is icky in many ways, but it's impractical to - * get at the firmware code in order to figure out what it's actually doing. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/backlight.h> -#include <linux/err.h> -#include <linux/dmi.h> -#include <linux/io.h> - -static struct backlight_device *mbp_backlight_device; - -/* Structure to be passed to the DMI_MATCH function. */ -struct dmi_match_data { - /* I/O resource to allocate. */ - unsigned long iostart; - unsigned long iolen; - /* Backlight operations structure. */ - const struct backlight_ops backlight_ops; -}; - -/* Module parameters. */ -static int debug; -module_param_named(debug, debug, int, 0644); -MODULE_PARM_DESC(debug, "Set to one to enable debugging messages."); - -/* - * Implementation for MacBooks with Intel chipset. - */ -static int intel_chipset_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", - intensity); - - outb(0x04 | (intensity << 4), 0xb3); - outb(0xbf, 0xb2); - return 0; -} - -static int intel_chipset_get_intensity(struct backlight_device *bd) -{ - int intensity; - - outb(0x03, 0xb3); - outb(0xbf, 0xb2); - intensity = inb(0xb3) >> 4; - - if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", - intensity); - - return intensity; -} - -static const struct dmi_match_data intel_chipset_data = { - .iostart = 0xb2, - .iolen = 2, - .backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = intel_chipset_get_intensity, - .update_status = intel_chipset_send_intensity, - } -}; - -/* - * Implementation for MacBooks with Nvidia chipset. - */ -static int nvidia_chipset_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: setting brightness to %d\n", - intensity); - - outb(0x04 | (intensity << 4), 0x52f); - outb(0xbf, 0x52e); - return 0; -} - -static int nvidia_chipset_get_intensity(struct backlight_device *bd) -{ - int intensity; - - outb(0x03, 0x52f); - outb(0xbf, 0x52e); - intensity = inb(0x52f) >> 4; - - if (debug) - printk(KERN_DEBUG "mbp_nvidia_bl: read brightness of %d\n", - intensity); - - return intensity; -} - -static const struct dmi_match_data nvidia_chipset_data = { - .iostart = 0x52e, - .iolen = 2, - .backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = nvidia_chipset_get_intensity, - .update_status = nvidia_chipset_send_intensity - } -}; - -/* - * DMI matching. - */ -static /* const */ struct dmi_match_data *driver_data; - -static int mbp_dmi_match(const struct dmi_system_id *id) -{ - driver_data = id->driver_data; - - printk(KERN_INFO "mbp_nvidia_bl: %s detected\n", id->ident); - return 1; -} - -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 Computer, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 2,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook3,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 4,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 4,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook4,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .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."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 3,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,2"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 4,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro4,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 1,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir1,1"), - }, - .driver_data = (void *)&intel_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 5,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBook 5,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .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."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir2,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,4", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookPro 5,5", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,5"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { } -}; - -static int __init mbp_init(void) -{ - struct backlight_properties props; - if (!dmi_check_system(mbp_device_table)) - return -ENODEV; - - if (!request_region(driver_data->iostart, driver_data->iolen, - "Macbook Pro backlight")) - return -ENXIO; - - memset(&props, 0, sizeof(struct backlight_properties)); - props.max_brightness = 15; - mbp_backlight_device = backlight_device_register("mbp_backlight", NULL, - NULL, - &driver_data->backlight_ops, - &props); - if (IS_ERR(mbp_backlight_device)) { - release_region(driver_data->iostart, driver_data->iolen); - return PTR_ERR(mbp_backlight_device); - } - - mbp_backlight_device->props.brightness = - driver_data->backlight_ops.get_brightness(mbp_backlight_device); - backlight_update_status(mbp_backlight_device); - - return 0; -} - -static void __exit mbp_exit(void) -{ - backlight_device_unregister(mbp_backlight_device); - - release_region(driver_data->iostart, driver_data->iolen); -} - -module_init(mbp_init); -module_exit(mbp_exit); - -MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); -MODULE_DESCRIPTION("Nvidia-based Macbook Pro Backlight Driver"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(dmi, mbp_device_table); diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c index d3bc56296c8d..08d26a72394c 100644 --- a/drivers/video/backlight/omap1_bl.c +++ b/drivers/video/backlight/omap1_bl.c @@ -146,6 +146,7 @@ static int omapbl_probe(struct platform_device *pdev) return -ENOMEM; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = OMAPBL_MAX_INTENSITY; dev = backlight_device_register("omap-bl", &pdev->dev, bl, &omapbl_ops, &props); diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index 3c424f7efdcc..ef5628d60563 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -112,6 +112,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) if (!pcf_bl) return -ENOMEM; + bl_props.type = BACKLIGHT_RAW; bl_props.max_brightness = 0x3f; bl_props.power = FB_BLANK_UNBLANK; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 809278c90738..6af183d6465e 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -84,6 +84,7 @@ static int progearbl_probe(struct platform_device *pdev) pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN; progear_backlight_device = backlight_device_register("progear-bl", &pdev->dev, NULL, diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c index 21866ec69656..b8f38ec6eb18 100644 --- a/drivers/video/backlight/pwm_bl.c +++ b/drivers/video/backlight/pwm_bl.c @@ -28,6 +28,7 @@ struct pwm_bl_data { unsigned int lth_brightness; int (*notify)(struct device *, int brightness); + int (*check_fb)(struct device *, struct fb_info *); }; static int pwm_backlight_update_status(struct backlight_device *bl) @@ -62,9 +63,18 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl) return bl->props.brightness; } +static int pwm_backlight_check_fb(struct backlight_device *bl, + struct fb_info *info) +{ + struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); + + return !pb->check_fb || pb->check_fb(pb->dev, info); +} + static const struct backlight_ops pwm_backlight_ops = { .update_status = pwm_backlight_update_status, .get_brightness = pwm_backlight_get_brightness, + .check_fb = pwm_backlight_check_fb, }; static int pwm_backlight_probe(struct platform_device *pdev) @@ -95,6 +105,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; + pb->check_fb = data->check_fb; pb->lth_brightness = data->lth_brightness * (data->pwm_period_ns / data->max_brightness); pb->dev = &pdev->dev; @@ -108,6 +119,7 @@ static int pwm_backlight_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "got pwm for backlight\n"); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = data->max_brightness; bl = backlight_device_register(dev_name(&pdev->dev), &pdev->dev, pb, &pwm_backlight_ops, &props); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 5927db0da999..322040f686c2 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -778,6 +778,7 @@ static int __devinit s6e63m0_probe(struct spi_device *spi) bd->props.max_brightness = MAX_BRIGHTNESS; bd->props.brightness = MAX_BRIGHTNESS; + bd->props.type = BACKLIGHT_RAW; lcd->bd = bd; /* diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 2a04b382ec48..425a7365470b 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -102,6 +102,7 @@ static int __devinit tosa_bl_probe(struct i2c_client *client, data->i2c = client; memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 512 - 1; data->bl = backlight_device_register("tosa-bl", &client->dev, data, &bl_ops, &props); diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c index 08fd87f3aecc..d4c6eb248ff9 100644 --- a/drivers/video/backlight/wm831x_bl.c +++ b/drivers/video/backlight/wm831x_bl.c @@ -193,6 +193,7 @@ static int wm831x_backlight_probe(struct platform_device *pdev) data->current_brightness = 0; data->isink_reg = isink_reg; + props.type = BACKLIGHT_RAW; props.max_brightness = max_isel; bl = backlight_device_register("wm831x", &pdev->dev, data, &wm831x_backlight_ops, &props); diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index e7d0f525041e..2464b910b590 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -649,6 +649,7 @@ static int __devinit bfin_bf54x_probe(struct platform_device *pdev) } #ifndef NO_BL_SUPPORT memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 255; bl_dev = backlight_device_register("bf54x-bl", NULL, NULL, &bfin_lq043fb_bl_ops, &props); diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c index 3cf77676947c..d8de29f0dd8d 100644 --- a/drivers/video/bfin-t350mcqb-fb.c +++ b/drivers/video/bfin-t350mcqb-fb.c @@ -545,6 +545,7 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) } #ifndef NO_BL_SUPPORT memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = 255; bl_dev = backlight_device_register("bf52x-bl", NULL, NULL, &bfin_lq043fb_bl_ops, &props); diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index 69bd4a581d4a..ef72cb483834 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -499,6 +499,7 @@ static void imxfb_init_backlight(struct imxfb_info *fbi) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = 0xff; + props.type = BACKLIGHT_RAW; writel(fbi->pwmr, fbi->regs + LCDC_PWMR); bl = backlight_device_register("imxfb-bl", &fbi->pdev->dev, fbi, diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile index 6c782d3ae1be..f7d631ebee8e 100644 --- a/drivers/video/intelfb/Makefile +++ b/drivers/video/intelfb/Makefile @@ -4,7 +4,4 @@ intelfb-y := intelfbdrv.o intelfbhw.o intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o intelfb-objs := $(intelfb-y) -ifdef CONFIG_FB_INTEL_DEBUG -#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP -EXTRA_CFLAGS += -DDEBUG -DREGDUMP -endif +ccflags-$(CONFIG_FB_INTEL_DEBUG) := -DDEBUG -DREGDUMP diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index a082debe824b..a74439affce9 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1461,13 +1461,6 @@ static struct board { MGA_G100, &vbG100, "MGA-G100 (AGP)"}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, 0xFF, - 0, 0, - DEVF_G200, - 230000, - MGA_G200, - &vbG200, - "MGA-G200eV (PCI)"}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF, 0, 0, DEVF_G200, @@ -2119,8 +2112,6 @@ static struct pci_device_id matroxfb_devices[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP, diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h index 4e3deb4e592b..d80477415caa 100644 --- a/drivers/video/msm/mdp_hw.h +++ b/drivers/video/msm/mdp_hw.h @@ -449,6 +449,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, #define PPP_CFG_MDP_XRGB_8888(dir) PPP_CFG_MDP_ARGB_8888(dir) #define PPP_CFG_MDP_RGBA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir) #define PPP_CFG_MDP_BGRA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir) +#define PPP_CFG_MDP_RGBX_8888(dir) PPP_CFG_MDP_ARGB_8888(dir) #define PPP_CFG_MDP_Y_CBCR_H2V2(dir) (PPP_##dir##_C2R_8BIT | \ PPP_##dir##_C0G_8BIT | \ @@ -488,12 +489,14 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8) #define PPP_PACK_PATTERN_MDP_RGB_888 PPP_PACK_PATTERN_MDP_RGB_565 #define PPP_PACK_PATTERN_MDP_XRGB_8888 \ - MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8) + MDP_GET_PACK_PATTERN(CLR_B, CLR_G, CLR_R, CLR_ALPHA, 8) #define PPP_PACK_PATTERN_MDP_ARGB_8888 PPP_PACK_PATTERN_MDP_XRGB_8888 #define PPP_PACK_PATTERN_MDP_RGBA_8888 \ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8) #define PPP_PACK_PATTERN_MDP_BGRA_8888 \ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8) +#define PPP_PACK_PATTERN_MDP_RGBX_8888 \ + MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8) #define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1 \ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8) #define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V2 PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1 @@ -509,6 +512,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, #define PPP_CHROMA_SAMP_MDP_ARGB_8888(dir) PPP_OP_##dir##_CHROMA_RGB #define PPP_CHROMA_SAMP_MDP_RGBA_8888(dir) PPP_OP_##dir##_CHROMA_RGB #define PPP_CHROMA_SAMP_MDP_BGRA_8888(dir) PPP_OP_##dir##_CHROMA_RGB +#define PPP_CHROMA_SAMP_MDP_RGBX_8888(dir) PPP_OP_##dir##_CHROMA_RGB #define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1 #define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V2(dir) PPP_OP_##dir##_CHROMA_420 #define PPP_CHROMA_SAMP_MDP_Y_CRCB_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1 @@ -523,6 +527,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, [MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888,\ [MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888,\ [MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888,\ + [MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888,\ [MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1,\ [MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2,\ [MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1,\ @@ -536,6 +541,7 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, [MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888(dir),\ [MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888(dir),\ [MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888(dir),\ + [MDP_RGBX_8888] = PPP_##name##_MDP_RGBX_8888(dir),\ [MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1(dir),\ [MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2(dir),\ [MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1(dir),\ @@ -547,7 +553,8 @@ int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req, (img == MDP_YCRYCB_H2V1)) #define IS_RGB(img) ((img == MDP_RGB_565) | (img == MDP_RGB_888) | \ (img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \ - (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888)) + (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888) | \ + (img == MDP_RGBX_8888)) #define HAS_ALPHA(img) ((img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \ (img == MDP_BGRA_8888)) diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c index 4ff001f4cbbd..2b6564e8bfea 100644 --- a/drivers/video/msm/mdp_ppp.c +++ b/drivers/video/msm/mdp_ppp.c @@ -69,6 +69,7 @@ static uint32_t bytes_per_pixel[] = { [MDP_ARGB_8888] = 4, [MDP_RGBA_8888] = 4, [MDP_BGRA_8888] = 4, + [MDP_RGBX_8888] = 4, [MDP_Y_CBCR_H2V1] = 1, [MDP_Y_CBCR_H2V2] = 1, [MDP_Y_CRCB_H2V1] = 1, diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c index debe5933fd2e..ec351309e607 100644 --- a/drivers/video/msm/msm_fb.c +++ b/drivers/video/msm/msm_fb.c @@ -81,7 +81,6 @@ struct msmfb_info { spinlock_t update_lock; struct mutex panel_init_lock; wait_queue_head_t frame_wq; - struct workqueue_struct *resume_workqueue; struct work_struct resume_work; struct msmfb_callback dma_callback; struct msmfb_callback vsync_callback; @@ -111,7 +110,7 @@ static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback) if (msmfb->sleeping == UPDATING && msmfb->frame_done == msmfb->update_frame) { DLOG(SUSPEND_RESUME, "full update completed\n"); - queue_work(msmfb->resume_workqueue, &msmfb->resume_work); + schedule_work(&msmfb->resume_work); } spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); wake_up(&msmfb->frame_wq); @@ -220,8 +219,8 @@ restart: sleeping = msmfb->sleeping; /* on a full update, if the last frame has not completed, wait for it */ - if (pan_display && (msmfb->frame_requested != msmfb->frame_done || - sleeping == UPDATING)) { + if ((pan_display && msmfb->frame_requested != msmfb->frame_done) || + sleeping == UPDATING) { int ret; spin_unlock_irqrestore(&msmfb->update_lock, irq_flags); ret = wait_event_interruptible_timeout(msmfb->frame_wq, @@ -470,6 +469,18 @@ static void setup_fb_info(struct msmfb_info *msmfb) fb_info->var.yoffset = 0; if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) { + /* + * Set the param in the fixed screen, so userspace can't + * change it. This will be used to check for the + * capability. + */ + fb_info->fix.reserved[0] = 0x5444; + fb_info->fix.reserved[1] = 0x5055; + + /* + * This preloads the value so that if userspace doesn't + * change it, it will be a full update + */ fb_info->var.reserved[0] = 0x54445055; fb_info->var.reserved[1] = 0; fb_info->var.reserved[2] = (uint16_t)msmfb->xres | @@ -559,12 +570,6 @@ static int msmfb_probe(struct platform_device *pdev) spin_lock_init(&msmfb->update_lock); mutex_init(&msmfb->panel_init_lock); init_waitqueue_head(&msmfb->frame_wq); - msmfb->resume_workqueue = create_workqueue("panel_on"); - if (msmfb->resume_workqueue == NULL) { - printk(KERN_ERR "failed to create panel_on workqueue\n"); - ret = -ENOMEM; - goto error_create_workqueue; - } INIT_WORK(&msmfb->resume_work, power_on_panel); msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres, GFP_KERNEL); @@ -589,8 +594,6 @@ static int msmfb_probe(struct platform_device *pdev) return 0; error_register_framebuffer: - destroy_workqueue(msmfb->resume_workqueue); -error_create_workqueue: iounmap(fb->screen_base); error_setup_fbmem: framebuffer_release(msmfb->fb); diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c new file mode 100644 index 000000000000..7d0284882984 --- /dev/null +++ b/drivers/video/mxsfb.c @@ -0,0 +1,919 @@ +/* + * Copyright (C) 2010 Juergen Beisert, Pengutronix + * + * This code is based on: + * Author: Vitaly Wool <vital@embeddedalley.com> + * + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define DRIVER_NAME "mxsfb" + +/** + * @file + * @brief LCDIF driver for i.MX23 and i.MX28 + * + * The LCDIF support four modes of operation + * - MPU interface (to drive smart displays) -> not supported yet + * - VSYNC interface (like MPU interface plus Vsync) -> not supported yet + * - Dotclock interface (to drive LC displays with RGB data and sync signals) + * - DVI (to drive ITU-R BT656) -> not supported yet + * + * This driver depends on a correct setup of the pins used for this purpose + * (platform specific). + * + * For the developer: Don't forget to set the data bus width to the display + * in the imx_fb_videomode structure. You will else end up with ugly colours. + * If you fight against jitter you can vary the clock delay. This is a feature + * of the i.MX28 and you can vary it between 2 ns ... 8 ns in 2 ns steps. Give + * the required value in the imx_fb_videomode structure. + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <mach/mxsfb.h> + +#define REG_SET 4 +#define REG_CLR 8 + +#define LCDC_CTRL 0x00 +#define LCDC_CTRL1 0x10 +#define LCDC_V4_CTRL2 0x20 +#define LCDC_V3_TRANSFER_COUNT 0x20 +#define LCDC_V4_TRANSFER_COUNT 0x30 +#define LCDC_V4_CUR_BUF 0x40 +#define LCDC_V4_NEXT_BUF 0x50 +#define LCDC_V3_CUR_BUF 0x30 +#define LCDC_V3_NEXT_BUF 0x40 +#define LCDC_TIMING 0x60 +#define LCDC_VDCTRL0 0x70 +#define LCDC_VDCTRL1 0x80 +#define LCDC_VDCTRL2 0x90 +#define LCDC_VDCTRL3 0xa0 +#define LCDC_VDCTRL4 0xb0 +#define LCDC_DVICTRL0 0xc0 +#define LCDC_DVICTRL1 0xd0 +#define LCDC_DVICTRL2 0xe0 +#define LCDC_DVICTRL3 0xf0 +#define LCDC_DVICTRL4 0x100 +#define LCDC_V4_DATA 0x180 +#define LCDC_V3_DATA 0x1b0 +#define LCDC_V4_DEBUG0 0x1d0 +#define LCDC_V3_DEBUG0 0x1f0 + +#define CTRL_SFTRST (1 << 31) +#define CTRL_CLKGATE (1 << 30) +#define CTRL_BYPASS_COUNT (1 << 19) +#define CTRL_VSYNC_MODE (1 << 18) +#define CTRL_DOTCLK_MODE (1 << 17) +#define CTRL_DATA_SELECT (1 << 16) +#define CTRL_SET_BUS_WIDTH(x) (((x) & 0x3) << 10) +#define CTRL_GET_BUS_WIDTH(x) (((x) >> 10) & 0x3) +#define CTRL_SET_WORD_LENGTH(x) (((x) & 0x3) << 8) +#define CTRL_GET_WORD_LENGTH(x) (((x) >> 8) & 0x3) +#define CTRL_MASTER (1 << 5) +#define CTRL_DF16 (1 << 3) +#define CTRL_DF18 (1 << 2) +#define CTRL_DF24 (1 << 1) +#define CTRL_RUN (1 << 0) + +#define CTRL1_FIFO_CLEAR (1 << 21) +#define CTRL1_SET_BYTE_PACKAGING(x) (((x) & 0xf) << 16) +#define CTRL1_GET_BYTE_PACKAGING(x) (((x) >> 16) & 0xf) + +#define TRANSFER_COUNT_SET_VCOUNT(x) (((x) & 0xffff) << 16) +#define TRANSFER_COUNT_GET_VCOUNT(x) (((x) >> 16) & 0xffff) +#define TRANSFER_COUNT_SET_HCOUNT(x) ((x) & 0xffff) +#define TRANSFER_COUNT_GET_HCOUNT(x) ((x) & 0xffff) + + +#define VDCTRL0_ENABLE_PRESENT (1 << 28) +#define VDCTRL0_VSYNC_ACT_HIGH (1 << 27) +#define VDCTRL0_HSYNC_ACT_HIGH (1 << 26) +#define VDCTRL0_DOTCLK_ACT_FAILING (1 << 25) +#define VDCTRL0_ENABLE_ACT_HIGH (1 << 24) +#define VDCTRL0_VSYNC_PERIOD_UNIT (1 << 21) +#define VDCTRL0_VSYNC_PULSE_WIDTH_UNIT (1 << 20) +#define VDCTRL0_HALF_LINE (1 << 19) +#define VDCTRL0_HALF_LINE_MODE (1 << 18) +#define VDCTRL0_SET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) +#define VDCTRL0_GET_VSYNC_PULSE_WIDTH(x) ((x) & 0x3ffff) + +#define VDCTRL2_SET_HSYNC_PERIOD(x) ((x) & 0x3ffff) +#define VDCTRL2_GET_HSYNC_PERIOD(x) ((x) & 0x3ffff) + +#define VDCTRL3_MUX_SYNC_SIGNALS (1 << 29) +#define VDCTRL3_VSYNC_ONLY (1 << 28) +#define SET_HOR_WAIT_CNT(x) (((x) & 0xfff) << 16) +#define GET_HOR_WAIT_CNT(x) (((x) >> 16) & 0xfff) +#define SET_VERT_WAIT_CNT(x) ((x) & 0xffff) +#define GET_VERT_WAIT_CNT(x) ((x) & 0xffff) + +#define VDCTRL4_SET_DOTCLK_DLY(x) (((x) & 0x7) << 29) /* v4 only */ +#define VDCTRL4_GET_DOTCLK_DLY(x) (((x) >> 29) & 0x7) /* v4 only */ +#define VDCTRL4_SYNC_SIGNALS_ON (1 << 18) +#define SET_DOTCLK_H_VALID_DATA_CNT(x) ((x) & 0x3ffff) + +#define DEBUG0_HSYNC (1 < 26) +#define DEBUG0_VSYNC (1 < 25) + +#define MIN_XRES 120 +#define MIN_YRES 120 + +#define RED 0 +#define GREEN 1 +#define BLUE 2 +#define TRANSP 3 + +enum mxsfb_devtype { + MXSFB_V3, + MXSFB_V4, +}; + +/* CPU dependent register offsets */ +struct mxsfb_devdata { + unsigned transfer_count; + unsigned cur_buf; + unsigned next_buf; + unsigned debug0; + unsigned hs_wdth_mask; + unsigned hs_wdth_shift; + unsigned ipversion; +}; + +struct mxsfb_info { + struct fb_info fb_info; + struct platform_device *pdev; + struct clk *clk; + void __iomem *base; /* registers */ + unsigned allocated_size; + int enabled; + unsigned ld_intf_width; + unsigned dotclk_delay; + const struct mxsfb_devdata *devdata; + int mapped; +}; + +#define mxsfb_is_v3(host) (host->devdata->ipversion == 3) +#define mxsfb_is_v4(host) (host->devdata->ipversion == 4) + +static const struct mxsfb_devdata mxsfb_devdata[] = { + [MXSFB_V3] = { + .transfer_count = LCDC_V3_TRANSFER_COUNT, + .cur_buf = LCDC_V3_CUR_BUF, + .next_buf = LCDC_V3_NEXT_BUF, + .debug0 = LCDC_V3_DEBUG0, + .hs_wdth_mask = 0xff, + .hs_wdth_shift = 24, + .ipversion = 3, + }, + [MXSFB_V4] = { + .transfer_count = LCDC_V4_TRANSFER_COUNT, + .cur_buf = LCDC_V4_CUR_BUF, + .next_buf = LCDC_V4_NEXT_BUF, + .debug0 = LCDC_V4_DEBUG0, + .hs_wdth_mask = 0x3fff, + .hs_wdth_shift = 18, + .ipversion = 4, + }, +}; + +#define to_imxfb_host(x) (container_of(x, struct mxsfb_info, fb_info)) + +/* mask and shift depends on architecture */ +static inline u32 set_hsync_pulse_width(struct mxsfb_info *host, unsigned val) +{ + return (val & host->devdata->hs_wdth_mask) << + host->devdata->hs_wdth_shift; +} + +static inline u32 get_hsync_pulse_width(struct mxsfb_info *host, unsigned val) +{ + return (val >> host->devdata->hs_wdth_shift) & + host->devdata->hs_wdth_mask; +} + +static const struct fb_bitfield def_rgb565[] = { + [RED] = { + .offset = 11, + .length = 5, + }, + [GREEN] = { + .offset = 5, + .length = 6, + }, + [BLUE] = { + .offset = 0, + .length = 5, + }, + [TRANSP] = { /* no support for transparency */ + .length = 0, + } +}; + +static const struct fb_bitfield def_rgb666[] = { + [RED] = { + .offset = 16, + .length = 6, + }, + [GREEN] = { + .offset = 8, + .length = 6, + }, + [BLUE] = { + .offset = 0, + .length = 6, + }, + [TRANSP] = { /* no support for transparency */ + .length = 0, + } +}; + +static const struct fb_bitfield def_rgb888[] = { + [RED] = { + .offset = 16, + .length = 8, + }, + [GREEN] = { + .offset = 8, + .length = 8, + }, + [BLUE] = { + .offset = 0, + .length = 8, + }, + [TRANSP] = { /* no support for transparency */ + .length = 0, + } +}; + +static inline unsigned chan_to_field(unsigned chan, struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int mxsfb_check_var(struct fb_var_screeninfo *var, + struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + const struct fb_bitfield *rgb = NULL; + + if (var->xres < MIN_XRES) + var->xres = MIN_XRES; + if (var->yres < MIN_YRES) + var->yres = MIN_YRES; + + var->xres_virtual = var->xres; + + var->yres_virtual = var->yres; + + switch (var->bits_per_pixel) { + case 16: + /* always expect RGB 565 */ + rgb = def_rgb565; + break; + case 32: + switch (host->ld_intf_width) { + case STMLCDIF_8BIT: + pr_debug("Unsupported LCD bus width mapping\n"); + break; + case STMLCDIF_16BIT: + case STMLCDIF_18BIT: + /* 24 bit to 18 bit mapping */ + rgb = def_rgb666; + break; + case STMLCDIF_24BIT: + /* real 24 bit */ + rgb = def_rgb888; + break; + } + break; + default: + pr_debug("Unsupported colour depth: %u\n", var->bits_per_pixel); + return -EINVAL; + } + + /* + * Copy the RGB parameters for this display + * from the machine specific parameters. + */ + var->red = rgb[RED]; + var->green = rgb[GREEN]; + var->blue = rgb[BLUE]; + var->transp = rgb[TRANSP]; + + return 0; +} + +static void mxsfb_enable_controller(struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + u32 reg; + + dev_dbg(&host->pdev->dev, "%s\n", __func__); + + clk_enable(host->clk); + clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); + + /* if it was disabled, re-enable the mode again */ + writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); + + /* enable the SYNC signals first, then the DMA engine */ + reg = readl(host->base + LCDC_VDCTRL4); + reg |= VDCTRL4_SYNC_SIGNALS_ON; + writel(reg, host->base + LCDC_VDCTRL4); + + writel(CTRL_RUN, host->base + LCDC_CTRL + REG_SET); + + host->enabled = 1; +} + +static void mxsfb_disable_controller(struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + unsigned loop; + u32 reg; + + dev_dbg(&host->pdev->dev, "%s\n", __func__); + + /* + * Even if we disable the controller here, it will still continue + * until its FIFOs are running out of data + */ + writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_CLR); + + loop = 1000; + while (loop) { + reg = readl(host->base + LCDC_CTRL); + if (!(reg & CTRL_RUN)) + break; + loop--; + } + + writel(VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4 + REG_CLR); + + clk_disable(host->clk); + + host->enabled = 0; +} + +static int mxsfb_set_par(struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + u32 ctrl, vdctrl0, vdctrl4; + int line_size, fb_size; + int reenable = 0; + + line_size = fb_info->var.xres * (fb_info->var.bits_per_pixel >> 3); + fb_size = fb_info->var.yres_virtual * line_size; + + if (fb_size > fb_info->fix.smem_len) + return -ENOMEM; + + fb_info->fix.line_length = line_size; + + /* + * It seems, you can't re-program the controller if it is still running. + * This may lead into shifted pictures (FIFO issue?). + * So, first stop the controller and drain its FIFOs + */ + if (host->enabled) { + reenable = 1; + mxsfb_disable_controller(fb_info); + } + + /* clear the FIFOs */ + writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); + + ctrl = CTRL_BYPASS_COUNT | CTRL_MASTER | + CTRL_SET_BUS_WIDTH(host->ld_intf_width);; + + switch (fb_info->var.bits_per_pixel) { + case 16: + dev_dbg(&host->pdev->dev, "Setting up RGB565 mode\n"); + ctrl |= CTRL_SET_WORD_LENGTH(0); + writel(CTRL1_SET_BYTE_PACKAGING(0xf), host->base + LCDC_CTRL1); + break; + case 32: + dev_dbg(&host->pdev->dev, "Setting up RGB888/666 mode\n"); + ctrl |= CTRL_SET_WORD_LENGTH(3); + switch (host->ld_intf_width) { + case STMLCDIF_8BIT: + dev_dbg(&host->pdev->dev, + "Unsupported LCD bus width mapping\n"); + return -EINVAL; + case STMLCDIF_16BIT: + case STMLCDIF_18BIT: + /* 24 bit to 18 bit mapping */ + ctrl |= CTRL_DF24; /* ignore the upper 2 bits in + * each colour component + */ + break; + case STMLCDIF_24BIT: + /* real 24 bit */ + break; + } + /* do not use packed pixels = one pixel per word instead */ + writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); + break; + default: + dev_dbg(&host->pdev->dev, "Unhandled color depth of %u\n", + fb_info->var.bits_per_pixel); + return -EINVAL; + } + + writel(ctrl, host->base + LCDC_CTRL); + + writel(TRANSFER_COUNT_SET_VCOUNT(fb_info->var.yres) | + TRANSFER_COUNT_SET_HCOUNT(fb_info->var.xres), + host->base + host->devdata->transfer_count); + + vdctrl0 = VDCTRL0_ENABLE_PRESENT | /* always in DOTCLOCK mode */ + VDCTRL0_VSYNC_PERIOD_UNIT | + VDCTRL0_VSYNC_PULSE_WIDTH_UNIT | + VDCTRL0_SET_VSYNC_PULSE_WIDTH(fb_info->var.vsync_len); + if (fb_info->var.sync & FB_SYNC_HOR_HIGH_ACT) + vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH; + if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT) + vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH; + if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT) + vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH; + if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT) + vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING; + + writel(vdctrl0, host->base + LCDC_VDCTRL0); + + /* frame length in lines */ + writel(fb_info->var.upper_margin + fb_info->var.vsync_len + + fb_info->var.lower_margin + fb_info->var.yres, + host->base + LCDC_VDCTRL1); + + /* line length in units of clocks or pixels */ + writel(set_hsync_pulse_width(host, fb_info->var.hsync_len) | + VDCTRL2_SET_HSYNC_PERIOD(fb_info->var.left_margin + + fb_info->var.hsync_len + fb_info->var.right_margin + + fb_info->var.xres), + host->base + LCDC_VDCTRL2); + + writel(SET_HOR_WAIT_CNT(fb_info->var.left_margin + + fb_info->var.hsync_len) | + SET_VERT_WAIT_CNT(fb_info->var.upper_margin + + fb_info->var.vsync_len), + host->base + LCDC_VDCTRL3); + + vdctrl4 = SET_DOTCLK_H_VALID_DATA_CNT(fb_info->var.xres); + if (mxsfb_is_v4(host)) + vdctrl4 |= VDCTRL4_SET_DOTCLK_DLY(host->dotclk_delay); + writel(vdctrl4, host->base + LCDC_VDCTRL4); + + writel(fb_info->fix.smem_start + + fb_info->fix.line_length * fb_info->var.yoffset, + host->base + host->devdata->next_buf); + + if (reenable) + mxsfb_enable_controller(fb_info); + + return 0; +} + +static int mxsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *fb_info) +{ + unsigned int val; + int ret = -EINVAL; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (fb_info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + + switch (fb_info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 12 or 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = fb_info->pseudo_palette; + + val = chan_to_field(red, &fb_info->var.red); + val |= chan_to_field(green, &fb_info->var.green); + val |= chan_to_field(blue, &fb_info->var.blue); + + pal[regno] = val; + ret = 0; + } + break; + + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +static int mxsfb_blank(int blank, struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + + switch (blank) { + case FB_BLANK_POWERDOWN: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (host->enabled) + mxsfb_disable_controller(fb_info); + break; + + case FB_BLANK_UNBLANK: + if (!host->enabled) + mxsfb_enable_controller(fb_info); + break; + } + return 0; +} + +static int mxsfb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fb_info) +{ + struct mxsfb_info *host = to_imxfb_host(fb_info); + unsigned offset; + + if (var->xoffset != 0) + return -EINVAL; + + offset = fb_info->fix.line_length * var->yoffset; + + /* update on next VSYNC */ + writel(fb_info->fix.smem_start + offset, + host->base + host->devdata->next_buf); + + return 0; +} + +static struct fb_ops mxsfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = mxsfb_check_var, + .fb_set_par = mxsfb_set_par, + .fb_setcolreg = mxsfb_setcolreg, + .fb_blank = mxsfb_blank, + .fb_pan_display = mxsfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, +}; + +static int __devinit mxsfb_restore_mode(struct mxsfb_info *host) +{ + struct fb_info *fb_info = &host->fb_info; + unsigned line_count; + unsigned period; + unsigned long pa, fbsize; + int bits_per_pixel, ofs; + u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; + struct fb_videomode vmode; + + /* Only restore the mode when the controller is running */ + ctrl = readl(host->base + LCDC_CTRL); + if (!(ctrl & CTRL_RUN)) + return -EINVAL; + + vdctrl0 = readl(host->base + LCDC_VDCTRL0); + vdctrl2 = readl(host->base + LCDC_VDCTRL2); + vdctrl3 = readl(host->base + LCDC_VDCTRL3); + vdctrl4 = readl(host->base + LCDC_VDCTRL4); + + transfer_count = readl(host->base + host->devdata->transfer_count); + + vmode.xres = TRANSFER_COUNT_GET_HCOUNT(transfer_count); + vmode.yres = TRANSFER_COUNT_GET_VCOUNT(transfer_count); + + switch (CTRL_GET_WORD_LENGTH(ctrl)) { + case 0: + bits_per_pixel = 16; + break; + case 3: + bits_per_pixel = 32; + case 1: + default: + return -EINVAL; + } + + fb_info->var.bits_per_pixel = bits_per_pixel; + + vmode.pixclock = KHZ2PICOS(clk_get_rate(host->clk) / 1000U); + vmode.hsync_len = get_hsync_pulse_width(host, vdctrl2); + vmode.left_margin = GET_HOR_WAIT_CNT(vdctrl3) - vmode.hsync_len; + vmode.right_margin = VDCTRL2_GET_HSYNC_PERIOD(vdctrl2) - vmode.hsync_len - + vmode.left_margin - vmode.xres; + vmode.vsync_len = VDCTRL0_GET_VSYNC_PULSE_WIDTH(vdctrl0); + period = readl(host->base + LCDC_VDCTRL1); + vmode.upper_margin = GET_VERT_WAIT_CNT(vdctrl3) - vmode.vsync_len; + vmode.lower_margin = period - vmode.vsync_len - vmode.upper_margin - vmode.yres; + + vmode.vmode = FB_VMODE_NONINTERLACED; + + vmode.sync = 0; + if (vdctrl0 & VDCTRL0_HSYNC_ACT_HIGH) + vmode.sync |= FB_SYNC_HOR_HIGH_ACT; + if (vdctrl0 & VDCTRL0_VSYNC_ACT_HIGH) + vmode.sync |= FB_SYNC_VERT_HIGH_ACT; + + pr_debug("Reconstructed video mode:\n"); + pr_debug("%dx%d, hsync: %u left: %u, right: %u, vsync: %u, upper: %u, lower: %u\n", + vmode.xres, vmode.yres, + vmode.hsync_len, vmode.left_margin, vmode.right_margin, + vmode.vsync_len, vmode.upper_margin, vmode.lower_margin); + pr_debug("pixclk: %ldkHz\n", PICOS2KHZ(vmode.pixclock)); + + fb_add_videomode(&vmode, &fb_info->modelist); + + host->ld_intf_width = CTRL_GET_BUS_WIDTH(ctrl); + host->dotclk_delay = VDCTRL4_GET_DOTCLK_DLY(vdctrl4); + + fb_info->fix.line_length = vmode.xres * (bits_per_pixel >> 3); + + pa = readl(host->base + host->devdata->cur_buf); + fbsize = fb_info->fix.line_length * vmode.yres; + if (pa < fb_info->fix.smem_start) + return -EINVAL; + if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) + return -EINVAL; + ofs = pa - fb_info->fix.smem_start; + if (ofs) { + memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); + writel(fb_info->fix.smem_start, host->base + host->devdata->next_buf); + } + + line_count = fb_info->fix.smem_len / fb_info->fix.line_length; + fb_info->fix.ypanstep = 1; + + clk_enable(host->clk); + host->enabled = 1; + + return 0; +} + +static int __devinit mxsfb_init_fbinfo(struct mxsfb_info *host) +{ + struct fb_info *fb_info = &host->fb_info; + struct fb_var_screeninfo *var = &fb_info->var; + struct mxsfb_platform_data *pdata = host->pdev->dev.platform_data; + dma_addr_t fb_phys; + void *fb_virt; + unsigned fb_size = pdata->fb_size; + + fb_info->fbops = &mxsfb_ops; + fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST; + strlcpy(fb_info->fix.id, "mxs", sizeof(fb_info->fix.id)); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.ypanstep = 1; + fb_info->fix.visual = FB_VISUAL_TRUECOLOR, + fb_info->fix.accel = FB_ACCEL_NONE; + + var->bits_per_pixel = pdata->default_bpp ? pdata->default_bpp : 16; + var->nonstd = 0; + var->activate = FB_ACTIVATE_NOW; + var->accel_flags = 0; + var->vmode = FB_VMODE_NONINTERLACED; + + host->dotclk_delay = pdata->dotclk_delay; + host->ld_intf_width = pdata->ld_intf_width; + + /* Memory allocation for framebuffer */ + if (pdata->fb_phys) { + if (!fb_size) + return -EINVAL; + + fb_phys = pdata->fb_phys; + + if (!request_mem_region(fb_phys, fb_size, host->pdev->name)) + return -ENOMEM; + + fb_virt = ioremap(fb_phys, fb_size); + if (!fb_virt) { + release_mem_region(fb_phys, fb_size); + return -ENOMEM; + } + host->mapped = 1; + } else { + if (!fb_size) + fb_size = SZ_2M; /* default */ + fb_virt = alloc_pages_exact(fb_size, GFP_DMA); + if (!fb_virt) + return -ENOMEM; + + fb_phys = virt_to_phys(fb_virt); + } + + fb_info->fix.smem_start = fb_phys; + fb_info->screen_base = fb_virt; + fb_info->screen_size = fb_info->fix.smem_len = fb_size; + + if (mxsfb_restore_mode(host)) + memset(fb_virt, 0, fb_size); + + return 0; +} + +static void __devexit mxsfb_free_videomem(struct mxsfb_info *host) +{ + struct fb_info *fb_info = &host->fb_info; + + if (host->mapped) { + iounmap(fb_info->screen_base); + release_mem_region(fb_info->fix.smem_start, + fb_info->screen_size); + } else { + free_pages_exact(fb_info->screen_base, fb_info->fix.smem_len); + } +} + +static int __devinit mxsfb_probe(struct platform_device *pdev) +{ + struct mxsfb_platform_data *pdata = pdev->dev.platform_data; + struct resource *res; + struct mxsfb_info *host; + struct fb_info *fb_info; + struct fb_modelist *modelist; + int i, ret; + + if (!pdata) { + dev_err(&pdev->dev, "No platformdata. Giving up\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Cannot get memory IO resource\n"); + return -ENODEV; + } + + if (!request_mem_region(res->start, resource_size(res), pdev->name)) + return -EBUSY; + + fb_info = framebuffer_alloc(sizeof(struct mxsfb_info), &pdev->dev); + if (!fb_info) { + dev_err(&pdev->dev, "Failed to allocate fbdev\n"); + ret = -ENOMEM; + goto error_alloc_info; + } + + host = to_imxfb_host(fb_info); + + host->base = ioremap(res->start, resource_size(res)); + if (!host->base) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto error_ioremap; + } + + host->pdev = pdev; + platform_set_drvdata(pdev, host); + + host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data]; + + host->clk = clk_get(&host->pdev->dev, NULL); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + goto error_getclock; + } + + fb_info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); + if (!fb_info->pseudo_palette) { + ret = -ENOMEM; + goto error_pseudo_pallette; + } + + INIT_LIST_HEAD(&fb_info->modelist); + + ret = mxsfb_init_fbinfo(host); + if (ret != 0) + goto error_init_fb; + + for (i = 0; i < pdata->mode_count; i++) + fb_add_videomode(&pdata->mode_list[i], &fb_info->modelist); + + modelist = list_first_entry(&fb_info->modelist, + struct fb_modelist, list); + fb_videomode_to_var(&fb_info->var, &modelist->mode); + + /* init the color fields */ + mxsfb_check_var(&fb_info->var, fb_info); + + platform_set_drvdata(pdev, fb_info); + + ret = register_framebuffer(fb_info); + if (ret != 0) { + dev_err(&pdev->dev,"Failed to register framebuffer\n"); + goto error_register; + } + + if (!host->enabled) { + writel(0, host->base + LCDC_CTRL); + mxsfb_set_par(fb_info); + mxsfb_enable_controller(fb_info); + } + + dev_info(&pdev->dev, "initialized\n"); + + return 0; + +error_register: + if (host->enabled) + clk_disable(host->clk); + fb_destroy_modelist(&fb_info->modelist); +error_init_fb: + kfree(fb_info->pseudo_palette); +error_pseudo_pallette: + clk_put(host->clk); +error_getclock: + iounmap(host->base); +error_ioremap: + framebuffer_release(fb_info); +error_alloc_info: + release_mem_region(res->start, resource_size(res)); + + return ret; +} + +static int __devexit mxsfb_remove(struct platform_device *pdev) +{ + struct fb_info *fb_info = platform_get_drvdata(pdev); + struct mxsfb_info *host = to_imxfb_host(fb_info); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (host->enabled) + mxsfb_disable_controller(fb_info); + + unregister_framebuffer(fb_info); + kfree(fb_info->pseudo_palette); + mxsfb_free_videomem(host); + iounmap(host->base); + clk_put(host->clk); + + framebuffer_release(fb_info); + release_mem_region(res->start, resource_size(res)); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_device_id mxsfb_devtype[] = { + { + .name = "imx23-fb", + .driver_data = MXSFB_V3, + }, { + .name = "imx28-fb", + .driver_data = MXSFB_V4, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, mxsfb_devtype); + +static struct platform_driver mxsfb_driver = { + .probe = mxsfb_probe, + .remove = __devexit_p(mxsfb_remove), + .id_table = mxsfb_devtype, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init mxsfb_init(void) +{ + return platform_driver_register(&mxsfb_driver); +} + +static void __exit mxsfb_exit(void) +{ + platform_driver_unregister(&mxsfb_driver); +} + +module_init(mxsfb_init); +module_exit(mxsfb_exit); + +MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index 6aac6d1b937b..8471008aa6ff 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -111,6 +111,7 @@ void nvidia_bl_init(struct nvidia_par *par) snprintf(name, sizeof(name), "nvidiabl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &nvidia_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index e77310653207..7e04c921aa2a 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c @@ -534,6 +534,7 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) props.fb_blank = FB_BLANK_UNBLANK; props.power = FB_BLANK_UNBLANK; + props.type = BACKLIGHT_RAW; bldev = backlight_device_register("acx565akm", &md->spi->dev, md, &acx565akm_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 9a138f650e05..d2b35d2df2a6 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c @@ -99,6 +99,7 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) memset(&props, 0, sizeof(struct backlight_properties)); props.max_brightness = dssdev->max_backlight_level; + props.type = BACKLIGHT_RAW; bl = backlight_device_register("sharp-ls", &dssdev->dev, dssdev, &sharp_ls_bl_ops, &props); diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 61026f96ad20..c74e8b778ba1 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -729,6 +729,8 @@ static int taal_probe(struct omap_dss_device *dssdev) props.max_brightness = 255; else props.max_brightness = 127; + + props.type = BACKLIGHT_RAW; bldev = backlight_device_register("taal", &dssdev->dev, dssdev, &taal_bl_ops, &props); if (IS_ERR(bldev)) { diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index da388186d617..d8ab7be4fd6b 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -355,6 +355,7 @@ static void riva_bl_init(struct riva_par *par) snprintf(name, sizeof(name), "rivabl%d", info->node); memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; props.max_brightness = FB_BACKLIGHT_LEVELS - 1; bd = backlight_device_register(name, info->dev, par, &riva_bl_ops, &props); diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index d66f963e930e..137996dc547e 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h @@ -94,9 +94,6 @@ extern int viafb_LCD_ON; extern int viafb_DVI_ON; extern int viafb_hotplug; -extern int strict_strtoul(const char *cp, unsigned int base, - unsigned long *res); - u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information *plvds_setting_info, struct lvds_chip_information *plvds_chip_info, u8 index); |