Merge branch 'akpm' (incoming from Andrew)
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Feb 2013 01:38:49 +0000 (17:38 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Feb 2013 01:38:49 +0000 (17:38 -0800)
Merge misc patches from Andrew Morton:

 - Florian has vanished so I appear to have become fbdev maintainer
   again :(

 - Joel and Mark are distracted to welcome to the new OCFS2 maintainer

 - The backlight queue

 - Small core kernel changes

 - lib/ updates

 - The rtc queue

 - Various random bits

* akpm: (164 commits)
  rtc: rtc-davinci: use devm_*() functions
  rtc: rtc-max8997: use devm_request_threaded_irq()
  rtc: rtc-max8907: use devm_request_threaded_irq()
  rtc: rtc-da9052: use devm_request_threaded_irq()
  rtc: rtc-wm831x: use devm_request_threaded_irq()
  rtc: rtc-tps80031: use devm_request_threaded_irq()
  rtc: rtc-lp8788: use devm_request_threaded_irq()
  rtc: rtc-coh901331: use devm_clk_get()
  rtc: rtc-vt8500: use devm_*() functions
  rtc: rtc-tps6586x: use devm_request_threaded_irq()
  rtc: rtc-imxdi: use devm_clk_get()
  rtc: rtc-cmos: use dev_warn()/dev_dbg() instead of printk()/pr_debug()
  rtc: rtc-pcf8583: use dev_warn() instead of printk()
  rtc: rtc-sun4v: use pr_warn() instead of printk()
  rtc: rtc-vr41xx: use dev_info() instead of printk()
  rtc: rtc-rs5c313: use pr_err() instead of printk()
  rtc: rtc-at91rm9200: use dev_dbg()/dev_err() instead of printk()/pr_debug()
  rtc: rtc-rs5c372: use dev_dbg()/dev_warn() instead of printk()/pr_debug()
  rtc: rtc-ds2404: use dev_err() instead of printk()
  rtc: rtc-efi: use dev_err()/dev_warn()/pr_err() instead of printk()
  ...

165 files changed:
Documentation/ABI/testing/sysfs-class-bdi
Documentation/backlight/lp855x-driver.txt
Documentation/devicetree/booting-without-of.txt
Documentation/printk-formats.txt
MAINTAINERS
arch/alpha/kernel/osf_sys.c
arch/arm/boot/dts/armada-370-xp.dtsi
arch/arm/configs/pxa910_defconfig
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mmp/ttc_dkb.c
arch/cris/include/uapi/asm/posix_types.h
arch/mn10300/unit-asb2305/pci-irq.c
arch/tile/Kconfig
block/blk-core.c
block/blk-integrity.c
drivers/net/ethernet/sun/Kconfig
drivers/pcmcia/cs.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-coh901331.c
drivers/rtc/rtc-da9052.c
drivers/rtc/rtc-davinci.c
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds2404.c
drivers/rtc/rtc-efi.c
drivers/rtc/rtc-fm3130.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-isl12022.c
drivers/rtc/rtc-lp8788.c [new file with mode: 0644]
drivers/rtc/rtc-max77686.c [new file with mode: 0644]
drivers/rtc/rtc-max8907.c
drivers/rtc/rtc-max8997.c [new file with mode: 0644]
drivers/rtc/rtc-mpc5121.c
drivers/rtc/rtc-pcf8523.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-rs5c313.c
drivers/rtc/rtc-rs5c372.c
drivers/rtc/rtc-rx4581.c [new file with mode: 0644]
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-sa1100.c
drivers/rtc/rtc-snvs.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-sun4v.c
drivers/rtc/rtc-tps6586x.c
drivers/rtc/rtc-tps65910.c
drivers/rtc/rtc-tps80031.c [new file with mode: 0644]
drivers/rtc/rtc-twl.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-vt8500.c
drivers/rtc/rtc-wm831x.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/backlight/88pm860x_bl.c
drivers/video/backlight/Kconfig
drivers/video/backlight/Makefile
drivers/video/backlight/aat2870_bl.c
drivers/video/backlight/adp8860_bl.c
drivers/video/backlight/adp8870_bl.c
drivers/video/backlight/ams369fg06.c
drivers/video/backlight/as3711_bl.c [new file with mode: 0644]
drivers/video/backlight/corgi_lcd.c
drivers/video/backlight/hx8357.c [new file with mode: 0644]
drivers/video/backlight/l4f00242t03.c
drivers/video/backlight/ld9040.c
drivers/video/backlight/lm3630_bl.c
drivers/video/backlight/lm3639_bl.c
drivers/video/backlight/lms283gf05.c
drivers/video/backlight/lms501kf03.c [new file with mode: 0644]
drivers/video/backlight/lp855x_bl.c
drivers/video/backlight/ltv350qv.c
drivers/video/backlight/omap1_bl.c
drivers/video/backlight/pwm_bl.c
drivers/video/backlight/s6e63m0.c
drivers/video/backlight/tdo24m.c
drivers/video/backlight/tosa_bl.c
drivers/video/backlight/tosa_lcd.c
drivers/video/backlight/vgg2432a4.c
drivers/video/console/fbcon.c
drivers/video/exynos/exynos_dp_core.c
drivers/video/exynos/exynos_mipi_dsi.c
drivers/video/exynos/s6e8ax0.c
drivers/video/goldfishfb.c [new file with mode: 0644]
drivers/video/mmp/Kconfig [new file with mode: 0644]
drivers/video/mmp/Makefile [new file with mode: 0644]
drivers/video/mmp/core.c [new file with mode: 0644]
drivers/video/mmp/fb/Kconfig [new file with mode: 0644]
drivers/video/mmp/fb/Makefile [new file with mode: 0644]
drivers/video/mmp/fb/mmpfb.c [new file with mode: 0644]
drivers/video/mmp/fb/mmpfb.h [new file with mode: 0644]
drivers/video/mmp/hw/Kconfig [new file with mode: 0644]
drivers/video/mmp/hw/Makefile [new file with mode: 0644]
drivers/video/mmp/hw/mmp_ctrl.c [new file with mode: 0644]
drivers/video/mmp/hw/mmp_ctrl.h [new file with mode: 0644]
drivers/video/mmp/hw/mmp_spi.c [new file with mode: 0644]
drivers/video/mmp/panel/Kconfig [new file with mode: 0644]
drivers/video/mmp/panel/Makefile [new file with mode: 0644]
drivers/video/mmp/panel/tpo_tj032md01bw.c [new file with mode: 0644]
drivers/video/mx3fb.c
fs/9p/vfs_file.c
fs/binfmt_elf.c
fs/block_dev.c
fs/buffer.c
fs/configfs/dir.c
fs/ext3/super.c
fs/ext4/inode.c
fs/gfs2/file.c
fs/nilfs2/file.c
fs/notify/inotify/inotify_user.c
fs/ocfs2/alloc.c
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlmglue.c
fs/ocfs2/extent_map.c
fs/ocfs2/journal.c
fs/ocfs2/localalloc.c
fs/ocfs2/stack_o2cb.c
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/ubifs/file.c
include/linux/backing-dev.h
include/linux/bug.h
include/linux/compiler-gcc.h
include/linux/compiler-gcc3.h
include/linux/compiler-gcc4.h
include/linux/compiler.h
include/linux/lockdep.h
include/linux/pagemap.h
include/linux/platform_data/lp855x.h
include/linux/printk.h
include/linux/smp.h
include/uapi/linux/elf.h
include/uapi/linux/fs.h
include/video/exynos_mipi_dsim.h
include/video/mmp_disp.h [new file with mode: 0644]
include/video/samsung_fimd.h
kernel/compat.c
kernel/nsproxy.c
kernel/smp.c
kernel/sys.c
kernel/time.c
lib/Kconfig.debug
lib/parser.c
lib/vsprintf.c
lib/xz/Kconfig
mm/Kconfig
mm/backing-dev.c
mm/bounce.c
mm/filemap.c
mm/page-writeback.c
net/ipv6/Kconfig
scripts/checkpatch.pl
scripts/get_maintainer.pl
scripts/tags.sh
security/device_cgroup.c

index 5f50097..d773d56 100644 (file)
@@ -48,3 +48,8 @@ max_ratio (read-write)
        most of the write-back cache.  For example in case of an NFS
        mount that is prone to get stuck, or a FUSE mount which cannot
        be trusted to play fair.
+
+stable_pages_required (read-only)
+
+       If set, the backing device requires that all pages comprising a write
+       request must not be changed until writeout is complete.
index 1529394..18b06ca 100644 (file)
@@ -4,7 +4,7 @@ Kernel driver lp855x
 Backlight driver for LP855x ICs
 
 Supported chips:
-       Texas Instruments LP8550, LP8551, LP8552, LP8553 and LP8556
+       Texas Instruments LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557
 
 Author: Milo(Woogyom) Kim <milo.kim@ti.com>
 
@@ -24,7 +24,7 @@ Value : pwm based or register based
 
 2) chip_id
 The lp855x chip id.
-Value : lp8550/lp8551/lp8552/lp8553/lp8556
+Value : lp8550/lp8551/lp8552/lp8553/lp8556/lp8557
 
 Platform data for lp855x
 ------------------------
index d4d6675..b2fb2f5 100644 (file)
@@ -1228,7 +1228,7 @@ hierarchy and routing of interrupts in the hardware.
 The interrupt tree model is fully described in the
 document "Open Firmware Recommended Practice: Interrupt
 Mapping Version 0.9".  The document is available at:
-<http://playground.sun.com/1275/practice>.
+<http://www.openfirmware.org/ofwg/practice/>
 
 1) interrupts property
 ----------------------
index 8ffb274..e8a6aa4 100644 (file)
@@ -53,6 +53,14 @@ Struct Resources:
        For printing struct resources. The 'R' and 'r' specifiers result in a
        printed resource with ('R') or without ('r') a decoded flags member.
 
+Physical addresses:
+
+       %pa     0x01234567 or 0x0123456789abcdef
+
+       For printing a phys_addr_t type (and its derivatives, such as
+       resource_size_t) which can vary based on build options, regardless of
+       the width of the CPU data path. Passed by reference.
+
 Raw buffer as a hex string:
        %*ph    00 01 02  ...  3f
        %*phC   00:01:02: ... :3f
@@ -150,9 +158,9 @@ s64 SHOULD be printed with %lld/%llx, (long long):
        printk("%lld", (long long)s64_var);
 
 If <type> is dependent on a config option for its size (e.g., sector_t,
-blkcnt_t, phys_addr_t, resource_size_t) or is architecture-dependent
-for its size (e.g., tcflag_t), use a format specifier of its largest
-possible type and explicitly cast to it.  Example:
+blkcnt_t) or is architecture-dependent for its size (e.g., tcflag_t), use a
+format specifier of its largest possible type and explicitly cast to it.
+Example:
 
        printk("test: sector number/total blocks: %llu/%llu\n",
                (unsigned long long)sector, (unsigned long long)blockcount);
index f4da1b8..81e4ad8 100644 (file)
@@ -1956,7 +1956,8 @@ F:        drivers/misc/*
 
 CHECKPATCH
 M:     Andy Whitcroft <apw@canonical.com>
-S:     Supported
+M:     Joe Perches <joe@perches.com>
+S:     Maintained
 F:     scripts/checkpatch.pl
 
 CHINESE DOCUMENTATION
@@ -5035,6 +5036,10 @@ L:       linux-mm@kvack.org
 W:     http://www.linux-mm.org
 S:     Maintained
 F:     include/linux/mm.h
+F:     include/linux/gfp.h
+F:     include/linux/mmzone.h
+F:     include/linux/memory_hotplug.h
+F:     include/linux/vmalloc.h
 F:     mm/
 
 MEMORY RESOURCE CONTROLLER
index dbc1760..b9e37ad 100644 (file)
@@ -1300,17 +1300,15 @@ static unsigned long
 arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
                         unsigned long limit)
 {
-       struct vm_area_struct *vma = find_vma(current->mm, addr);
-
-       while (1) {
-               /* At this point:  (!vma || addr < vma->vm_end). */
-               if (limit - len < addr)
-                       return -ENOMEM;
-               if (!vma || addr + len <= vma->vm_start)
-                       return addr;
-               addr = vma->vm_end;
-               vma = vma->vm_next;
-       }
+       struct vm_unmapped_area_info info;
+
+       info.flags = 0;
+       info.length = len;
+       info.low_limit = addr;
+       info.high_limit = limit;
+       info.align_mask = 0;
+       info.align_offset = 0;
+       return vm_unmapped_area(&info);
 }
 
 unsigned long
index 4c0abe8..5b29225 100644 (file)
                        clocks = <&coreclk 0>;
                        status = "disabled";
                };
+
+               rtc@10300 {
+                       compatible = "marvell,orion-rtc";
+                       reg = <0xd0010300 0x20>;
+                       interrupts = <50>;
+               };
        };
 };
 
index 191118c..3bb7771 100644 (file)
@@ -42,6 +42,14 @@ CONFIG_SMC91X=y
 # CONFIG_SERIO is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SPI=y
+CONFIG_FB=y
+CONFIG_MMP_DISP=y
+CONFIG_MMP_DISP_CONTROLLER=y
+CONFIG_MMP_SPI=y
+CONFIG_MMP_PANEL_TPOHVGA=y
+CONFIG_MMP_FB=y
+CONFIG_LOGO=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
index eff31ab..b914afa 100644 (file)
@@ -8,6 +8,7 @@ extern void __init pxa910_init_irq(void);
 #include <linux/i2c/pxa-i2c.h>
 #include <mach/devices.h>
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
+#include <video/mmp_disp.h>
 
 extern struct pxa_device_desc pxa910_device_uart1;
 extern struct pxa_device_desc pxa910_device_uart2;
@@ -21,7 +22,9 @@ extern struct pxa_device_desc pxa910_device_nand;
 extern struct platform_device pxa168_device_u2o;
 extern struct platform_device pxa168_device_u2ootg;
 extern struct platform_device pxa168_device_u2oehci;
-
+extern struct pxa_device_desc pxa910_device_disp;
+extern struct pxa_device_desc pxa910_device_fb;
+extern struct pxa_device_desc pxa910_device_panel;
 extern struct platform_device pxa910_device_gpio;
 extern struct platform_device pxa910_device_rtc;
 
index c6a89f1..36cb321 100644 (file)
@@ -134,6 +134,9 @@ PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
 PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
 PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
+PXA910_DEVICE(disp, "mmp-disp", 0, LCD, 0xd420b000, 0x1ec);
+PXA910_DEVICE(fb, "mmp-fb", -1, NONE, 0, 0);
+PXA910_DEVICE(panel, "tpo-hvga", -1, NONE, 0, 0);
 
 struct resource pxa910_resource_gpio[] = {
        {
index 6e47490..22a9058 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/gpio.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/platform_data/mv_usb.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -184,6 +186,92 @@ static struct pxa3xx_nand_platform_data dkb_nand_info = {
 };
 #endif
 
+#ifdef CONFIG_MMP_DISP
+/* path config */
+#define CFG_IOPADMODE(iopad)   (iopad)  /* 0x0 ~ 0xd */
+#define SCLK_SOURCE_SELECT(x)  (x << 30) /* 0x0 ~ 0x3 */
+/* link config */
+#define CFG_DUMBMODE(mode)     (mode << 28) /* 0x0 ~ 0x6*/
+#define CFG_GRA_SWAPRB(x)      (x << 0) /* 1: rbswap enabled */
+static struct mmp_mach_path_config dkb_disp_config[] = {
+       [0] = {
+               .name = "mmp-parallel",
+               .overlay_num = 2,
+               .output_type = PATH_OUT_PARALLEL,
+               .path_config = CFG_IOPADMODE(0x1)
+                       | SCLK_SOURCE_SELECT(0x1),
+               .link_config = CFG_DUMBMODE(0x2)
+                       | CFG_GRA_SWAPRB(0x1),
+       },
+};
+
+static struct mmp_mach_plat_info dkb_disp_info = {
+       .name = "mmp-disp",
+       .clk_name = "disp0",
+       .path_num = 1,
+       .paths = dkb_disp_config,
+};
+
+static struct mmp_buffer_driver_mach_info dkb_fb_info = {
+       .name = "mmp-fb",
+       .path_name = "mmp-parallel",
+       .overlay_id = 0,
+       .dmafetch_id = 1,
+       .default_pixfmt = PIXFMT_RGB565,
+};
+
+static void dkb_tpo_panel_power(int on)
+{
+       int err;
+       u32 spi_reset = mfp_to_gpio(MFP_PIN_GPIO106);
+
+       if (on) {
+               err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET");
+               if (err) {
+                       pr_err("failed to request GPIO for TPO LCD RESET\n");
+                       return;
+               }
+               gpio_direction_output(spi_reset, 0);
+               udelay(100);
+               gpio_set_value(spi_reset, 1);
+               gpio_free(spi_reset);
+       } else {
+               err = gpio_request(spi_reset, "TPO_LCD_SPI_RESET");
+               if (err) {
+                       pr_err("failed to request LCD RESET gpio\n");
+                       return;
+               }
+               gpio_set_value(spi_reset, 0);
+               gpio_free(spi_reset);
+       }
+}
+
+static struct mmp_mach_panel_info dkb_tpo_panel_info = {
+       .name = "tpo-hvga",
+       .plat_path_name = "mmp-parallel",
+       .plat_set_onoff = dkb_tpo_panel_power,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+       {
+               .modalias       = "tpo-hvga",
+               .platform_data  = &dkb_tpo_panel_info,
+               .bus_num        = 5,
+       }
+};
+
+static void __init add_disp(void)
+{
+       pxa_register_device(&pxa910_device_disp,
+               &dkb_disp_info, sizeof(dkb_disp_info));
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+       pxa_register_device(&pxa910_device_fb,
+               &dkb_fb_info, sizeof(dkb_fb_info));
+       pxa_register_device(&pxa910_device_panel,
+               &dkb_tpo_panel_info, sizeof(dkb_tpo_panel_info));
+}
+#endif
+
 static void __init ttc_dkb_init(void)
 {
        mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
@@ -212,6 +300,10 @@ static void __init ttc_dkb_init(void)
        pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
        platform_device_register(&pxa168_device_u2ootg);
 #endif
+
+#ifdef CONFIG_MMP_DISP
+       add_disp();
+#endif
 }
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
index ce4e517..0f22e6a 100644 (file)
@@ -22,11 +22,6 @@ typedef unsigned short       __kernel_uid_t;
 typedef unsigned short __kernel_gid_t;
 #define __kernel_uid_t __kernel_uid_t
 
-typedef __SIZE_TYPE__  __kernel_size_t;
-typedef long           __kernel_ssize_t;
-typedef int            __kernel_ptrdiff_t;
-#define __kernel_size_t __kernel_size_t
-
 typedef unsigned short __kernel_old_dev_t;
 #define __kernel_old_dev_t __kernel_old_dev_t
 
index 91212ea..77439da 100644 (file)
@@ -29,7 +29,7 @@ void __init pcibios_fixup_irqs(void)
        struct pci_dev *dev = NULL;
        u8 line, pin;
 
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+       for_each_pci_dev(dev) {
                pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
                if (pin) {
                        dev->irq = XIRQ1;
index 36136e8..4ce6e4c 100644 (file)
@@ -413,12 +413,6 @@ config TILE_USB
          Provides USB host adapter support for the built-in EHCI and OHCI
          interfaces on TILE-Gx chips.
 
-# USB OHCI needs the bounce pool since tilegx will often have more
-# than 4GB of memory, but we don't currently use the IOTLB to present
-# a 32-bit address to OHCI.  So we need to use a bounce pool instead.
-config NEED_BOUNCE_POOL
-       def_bool USB_OHCI_HCD
-
 source "drivers/pci/hotplug/Kconfig"
 
 endmenu
index c973249..277134c 100644 (file)
@@ -1474,6 +1474,11 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio)
         */
        blk_queue_bounce(q, &bio);
 
+       if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
+               bio_endio(bio, -EIO);
+               return;
+       }
+
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
                spin_lock_irq(q->queue_lock);
                where = ELEVATOR_INSERT_FLUSH;
@@ -1714,9 +1719,6 @@ generic_make_request_checks(struct bio *bio)
         */
        blk_partition_remap(bio);
 
-       if (bio_integrity_enabled(bio) && bio_integrity_prep(bio))
-               goto end_io;
-
        if (bio_check_eod(bio, nr_sectors))
                goto end_io;
 
index da2a818..dabd221 100644 (file)
@@ -420,6 +420,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
        } else
                bi->name = bi_unsupported_name;
 
+       disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+
        return 0;
 }
 EXPORT_SYMBOL(blk_integrity_register);
@@ -438,6 +440,8 @@ void blk_integrity_unregister(struct gendisk *disk)
        if (!disk || !disk->integrity)
                return;
 
+       disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
+
        bi = disk->integrity;
 
        kobject_uevent(&bi->kobj, KOBJ_REMOVE);
index ae3a355..3074aa3 100644 (file)
@@ -61,7 +61,7 @@ config SUNGEM
        select SUNGEM_PHY
        ---help---
          Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
-         <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+         <http://docs.oracle.com/cd/E19455-01/806-3985-10/806-3985-10.pdf>.
 
 config CASSINI
        tristate "Sun Cassini support"
@@ -69,7 +69,7 @@ config CASSINI
        select CRC32
        ---help---
          Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
-         <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+         <http://docs.oracle.com/cd/E19113-01/giga.ether.pci/817-4341-10/817-4341-10.pdf>.
 
 config SUNVNET
        tristate "Sun Virtual Network support"
index 673c14e..5292db6 100644 (file)
@@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt)
 
 static int socket_late_resume(struct pcmcia_socket *skt)
 {
-       int ret;
+       int ret = 0;
 
        mutex_lock(&skt->ops_mutex);
        skt->state &= ~SOCKET_SUSPEND;
@@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt)
                return socket_insert(skt);
        }
 
+       if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
+               ret = skt->callback->early_resume(skt);
+       return ret;
+}
+
+/*
+ * Finalize the resume. In case of a cardbus socket, we have
+ * to rebind the devices as we can't be certain that it has been
+ * replaced, or not.
+ */
+static int socket_complete_resume(struct pcmcia_socket *skt)
+{
+       int ret = 0;
 #ifdef CONFIG_CARDBUS
        if (skt->state & SOCKET_CARDBUS) {
                /* We can't be sure the CardBus card is the same
                 * as the one previously inserted. Therefore, remove
                 * and re-add... */
                cb_free(skt);
-               cb_alloc(skt);
-               return 0;
+               ret = cb_alloc(skt);
+               if (ret)
+                       cb_free(skt);
        }
 #endif
-       if (!(skt->state & SOCKET_CARDBUS) && (skt->callback))
-               skt->callback->early_resume(skt);
-       return 0;
+       return ret;
 }
 
 /*
@@ -533,11 +545,15 @@ static int socket_late_resume(struct pcmcia_socket *skt)
  */
 static int socket_resume(struct pcmcia_socket *skt)
 {
+       int err;
        if (!(skt->state & SOCKET_SUSPEND))
                return -EBUSY;
 
        socket_early_resume(skt);
-       return socket_late_resume(skt);
+       err = socket_late_resume(skt);
+       if (!err)
+               err = socket_complete_resume(skt);
+       return err;
 }
 
 static void socket_remove(struct pcmcia_socket *skt)
@@ -848,6 +864,12 @@ static int __used pcmcia_socket_dev_resume(struct device *dev)
        return __pcmcia_pm_op(dev, socket_late_resume);
 }
 
+static void __used pcmcia_socket_dev_complete(struct device *dev)
+{
+       WARN(__pcmcia_pm_op(dev, socket_complete_resume),
+               "failed to complete resume");
+}
+
 static const struct dev_pm_ops pcmcia_socket_pm_ops = {
        /* dev_resume may be called with IRQs enabled */
        SET_SYSTEM_SLEEP_PM_OPS(NULL,
@@ -862,6 +884,7 @@ static const struct dev_pm_ops pcmcia_socket_pm_ops = {
        .resume_noirq = pcmcia_socket_dev_resume_noirq,
        .thaw_noirq = pcmcia_socket_dev_resume_noirq,
        .restore_noirq = pcmcia_socket_dev_resume_noirq,
+       .complete = pcmcia_socket_dev_complete,
 };
 
 #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)
index 476d064..e6ab071 100644 (file)
@@ -204,6 +204,12 @@ config RTC_DRV_DS3232
          This driver can also be built as a module.  If so, the module
          will be called rtc-ds3232.
 
+config RTC_DRV_LP8788
+       tristate "TI LP8788 RTC driver"
+       depends on MFD_LP8788
+       help
+         Say Y to enable support for the LP8788 RTC/ALARM driver.
+
 config RTC_DRV_MAX6900
        tristate "Maxim MAX6900"
        help
@@ -243,6 +249,26 @@ config RTC_DRV_MAX8998
          This driver can also be built as a module. If so, the module
          will be called rtc-max8998.
 
+config RTC_DRV_MAX8997
+       tristate "Maxim MAX8997"
+       depends on MFD_MAX8997
+       help
+         If you say yes here you will get support for the
+         RTC of Maxim MAX8997 PMIC.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-max8997.
+
+config RTC_DRV_MAX77686
+       tristate "Maxim MAX77686"
+       depends on MFD_MAX77686
+       help
+         If you say yes here you will get support for the
+         RTC of Maxim MAX77686 PMIC.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-max77686.
+
 config RTC_DRV_RS5C372
        tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
        help
@@ -380,6 +406,14 @@ config RTC_DRV_TPS65910
          This driver can also be built as a module. If so, the module
          will be called rtc-tps65910.
 
+config RTC_DRV_TPS80031
+       tristate "TI TPS80031/TPS80032 RTC driver"
+       depends on MFD_TPS80031
+       help
+         TI Power Managment IC TPS80031 supports RTC functionality
+         along with alarm. This driver supports the RTC driver for
+         the TPS80031 RTC module.
+
 config RTC_DRV_RC5T583
        tristate "RICOH 5T583 RTC driver"
        depends on MFD_RC5T583
@@ -537,6 +571,14 @@ config RTC_DRV_PCF2123
          This driver can also be built as a module. If so, the module
          will be called rtc-pcf2123.
 
+config RTC_DRV_RX4581
+       tristate "Epson RX-4581"
+       help
+         If you say yes here you will get support for the Epson RX-4581.
+
+         This driver can also be built as a module. If so the module
+         will be called rtc-rx4581.
+
 endif # SPI_MASTER
 
 comment "Platform RTC drivers"
index 60c0414..e8f2e2f 100644 (file)
@@ -58,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI)   += rtc-imxdi.o
 obj-$(CONFIG_RTC_DRV_ISL1208)  += rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_JZ4740)   += rtc-jz4740.o
+obj-$(CONFIG_RTC_DRV_LP8788)   += rtc-lp8788.o
 obj-$(CONFIG_RTC_DRV_LPC32XX)  += rtc-lpc32xx.o
 obj-$(CONFIG_RTC_DRV_LOONGSON1)        += rtc-ls1x.o
 obj-$(CONFIG_RTC_DRV_M41T80)   += rtc-m41t80.o
@@ -71,7 +72,9 @@ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX8907)  += rtc-max8907.o
 obj-$(CONFIG_RTC_DRV_MAX8925)  += rtc-max8925.o
 obj-$(CONFIG_RTC_DRV_MAX8998)  += rtc-max8998.o
+obj-$(CONFIG_RTC_DRV_MAX8997)  += rtc-max8997.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)  += rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MPC5121)  += rtc-mpc5121.o
@@ -97,6 +100,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313)        += rtc-rs5c313.o
 obj-$(CONFIG_RTC_DRV_RS5C348)  += rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)  += rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
+obj-$(CONFIG_RTC_DRV_RX4581)   += rtc-rx4581.o
 obj-$(CONFIG_RTC_DRV_RX8025)   += rtc-rx8025.o
 obj-$(CONFIG_RTC_DRV_RX8581)   += rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_S35390A)  += rtc-s35390a.o
@@ -115,6 +119,7 @@ obj-$(CONFIG_RTC_DRV_TILE)  += rtc-tile.o
 obj-$(CONFIG_RTC_DRV_TWL4030)  += rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
 obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
+obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o
 obj-$(CONFIG_RTC_DRV_TX4939)   += rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)    += rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)   += rtc-vr41xx.o
index 26388f1..9b742d3 100644 (file)
@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/kdev_t.h>
@@ -261,7 +263,7 @@ static int __init rtc_init(void)
 {
        rtc_class = class_create(THIS_MODULE, "rtc");
        if (IS_ERR(rtc_class)) {
-               printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+               pr_err("couldn't create class\n");
                return PTR_ERR(rtc_class);
        }
        rtc_class->suspend = rtc_suspend;
index b6469e2..434ebc3 100644 (file)
@@ -86,7 +86,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
        tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
        tm->tm_year = tm->tm_year - 1900;
 
-       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+       dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
                tm->tm_hour, tm->tm_min, tm->tm_sec);
 
@@ -100,7 +100,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
 {
        unsigned long cr;
 
-       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+       dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
                tm->tm_hour, tm->tm_min, tm->tm_sec);
 
@@ -145,7 +145,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
        alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
                        ? 1 : 0;
 
-       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+       dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
                tm->tm_hour, tm->tm_min, tm->tm_sec);
 
@@ -183,7 +183,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
                at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
        }
 
-       pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+       dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
                at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
                tm.tm_min, tm.tm_sec);
 
@@ -192,7 +192,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
 static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       pr_debug("%s(): cmd=%08x\n", __func__, enabled);
+       dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled);
 
        if (enabled) {
                at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
@@ -240,7 +240,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
 
                rtc_update_irq(rtc, 1, events);
 
-               pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
+               dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
                        events >> 8, events & 0x000000FF);
 
                return IRQ_HANDLED;
@@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                                IRQF_SHARED,
                                "at91_rtc", pdev);
        if (ret) {
-               printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
-                               irq);
+               dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
                return ret;
        }
 
@@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, rtc);
 
-       printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+       dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
        return 0;
 }
 
index 16630aa..af97c94 100644 (file)
@@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                        rtc_cmos_int_handler = hpet_rtc_interrupt;
                        err = hpet_register_irq_handler(cmos_interrupt);
                        if (err != 0) {
-                               printk(KERN_WARNING "hpet_register_irq_handler "
+                               dev_warn(dev, "hpet_register_irq_handler "
                                                " failed in rtc_init().");
                                goto cleanup1;
                        }
@@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                goto cleanup2;
        }
 
-       pr_info("%s: %s%s, %zd bytes nvram%s\n",
-               dev_name(&cmos_rtc.rtc->dev),
+       dev_info(dev, "%s%s, %zd bytes nvram%s\n",
                !is_valid_irq(rtc_irq) ? "no alarms" :
                        cmos_rtc.mon_alrm ? "alarms up to one year" :
                        cmos_rtc.day_alrm ? "alarms up to one month" :
@@ -820,8 +819,7 @@ static int cmos_suspend(struct device *dev)
                        enable_irq_wake(cmos->irq);
        }
 
-       pr_debug("%s: suspend%s, ctrl %02x\n",
-                       dev_name(&cmos_rtc.rtc->dev),
+       dev_dbg(dev, "suspend%s, ctrl %02x\n",
                        (tmp & RTC_AIE) ? ", alarm may wake" : "",
                        tmp);
 
@@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev)
                spin_unlock_irq(&rtc_lock);
        }
 
-       pr_debug("%s: resume, ctrl %02x\n",
-                       dev_name(&cmos_rtc.rtc->dev),
-                       tmp);
+       dev_dbg(dev, "resume, ctrl %02x\n", tmp);
 
        return 0;
 }
@@ -1098,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev)
 }
 #else
 static inline void cmos_of_init(struct platform_device *pdev) {}
-#define of_cmos_match NULL
 #endif
 /*----------------------------------------------------------------*/
 
@@ -1140,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = {
 #ifdef CONFIG_PM
                .pm             = &cmos_pm_ops,
 #endif
-               .of_match_table = of_cmos_match,
+               .of_match_table = of_match_ptr(of_cmos_match),
        }
 };
 
index c8115b8..2d28ec1 100644 (file)
@@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev)
        if (rtap) {
                rtc_device_unregister(rtap->rtc);
                clk_unprepare(rtap->clk);
-               clk_put(rtap->clk);
                platform_set_drvdata(pdev, NULL);
        }
 
@@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
                             "RTC COH 901 331 Alarm", rtap))
                return -EIO;
 
-       rtap->clk = clk_get(&pdev->dev, NULL);
+       rtap->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(rtap->clk)) {
                ret = PTR_ERR(rtap->clk);
                dev_err(&pdev->dev, "could not get clock\n");
@@ -207,7 +206,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
        ret = clk_prepare_enable(rtap->clk);
        if (ret) {
                dev_err(&pdev->dev, "could not enable clock\n");
-               goto out_no_clk_prepenable;
+               return ret;
        }
        clk_disable(rtap->clk);
 
@@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev)
  out_no_rtc:
        platform_set_drvdata(pdev, NULL);
        clk_unprepare(rtap->clk);
- out_no_clk_prepenable:
-       clk_put(rtap->clk);
        return ret;
 }
 
index 60b826e..0dde688 100644 (file)
@@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
        rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
        platform_set_drvdata(pdev, rtc);
        rtc->irq = platform_get_irq_byname(pdev, "ALM");
-       ret = request_threaded_irq(rtc->irq, NULL, da9052_rtc_irq,
-                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
-                                  "ALM", rtc);
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                               da9052_rtc_irq,
+                               IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                               "ALM", rtc);
        if (ret != 0) {
                rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
                return ret;
@@ -250,16 +251,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
 
        rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
                                       &da9052_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc->rtc)) {
-               ret = PTR_ERR(rtc->rtc);
-               goto err_free_irq;
-       }
+       if (IS_ERR(rtc->rtc))
+               return PTR_ERR(rtc->rtc);
 
        return 0;
-
-err_free_irq:
-       free_irq(rtc->irq, rtc);
-       return ret;
 }
 
 static int da9052_rtc_remove(struct platform_device *pdev)
@@ -267,7 +262,6 @@ static int da9052_rtc_remove(struct platform_device *pdev)
        struct da9052_rtc *rtc = pdev->dev.platform_data;
 
        rtc_device_unregister(rtc->rtc);
-       free_irq(rtc->irq, rtc);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 5f7982f..56b7308 100644 (file)
@@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        davinci_rtc->pbase = res->start;
        davinci_rtc->base_size = resource_size(res);
 
-       mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size,
-                                pdev->name);
+       mem = devm_request_mem_region(dev, davinci_rtc->pbase,
+                               davinci_rtc->base_size, pdev->name);
        if (!mem) {
                dev_err(dev, "RTC registers at %08x are not free\n",
                        davinci_rtc->pbase);
                return -EBUSY;
        }
 
-       davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size);
+       davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase,
+                                       davinci_rtc->base_size);
        if (!davinci_rtc->base) {
                dev_err(dev, "unable to ioremap MEM resource\n");
-               ret = -ENOMEM;
-               goto fail2;
+               return -ENOMEM;
        }
 
        platform_set_drvdata(pdev, davinci_rtc);
@@ -529,7 +529,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
                ret = PTR_ERR(davinci_rtc->rtc);
                dev_err(dev, "unable to register RTC device, err %d\n",
                                ret);
-               goto fail3;
+               goto fail1;
        }
 
        rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
@@ -539,11 +539,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
        rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
        rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
 
-       ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
+       ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt,
                          0, "davinci_rtc", davinci_rtc);
        if (ret < 0) {
                dev_err(dev, "unable to register davinci RTC interrupt\n");
-               goto fail4;
+               goto fail2;
        }
 
        /* Enable interrupts */
@@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 
        return 0;
 
-fail4:
+fail2:
        rtc_device_unregister(davinci_rtc->rtc);
-fail3:
+fail1:
        platform_set_drvdata(pdev, NULL);
-       iounmap(davinci_rtc->base);
-fail2:
-       release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
        return ret;
 }
 
@@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev)
 
        rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
 
-       free_irq(davinci_rtc->irq, davinci_rtc);
-
        rtc_device_unregister(davinci_rtc->rtc);
 
-       iounmap(davinci_rtc->base);
-       release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
-
        platform_set_drvdata(pdev, NULL);
 
        return 0;
index 9a86b4b..d049393 100644 (file)
@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
 */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/sched.h>
@@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
                return;
 
        if (rtc->id >= RTC_DEV_MAX) {
-               pr_debug("%s: too many RTC devices\n", rtc->name);
+               dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
                return;
        }
 
@@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc)
 void rtc_dev_add_device(struct rtc_device *rtc)
 {
        if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
-               printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
+               dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
                        rtc->name, MAJOR(rtc_devt), rtc->id);
        else
-               pr_debug("%s: dev (%d:%d)\n", rtc->name,
+               dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
                        MAJOR(rtc_devt), rtc->id);
 }
 
@@ -499,8 +501,7 @@ void __init rtc_dev_init(void)
 
        err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
        if (err < 0)
-               printk(KERN_ERR "%s: failed to allocate char dev region\n",
-                       __FILE__);
+               pr_err("failed to allocate char dev region\n");
 }
 
 void __exit rtc_dev_exit(void)
index d578773..b05a6dc 100644 (file)
@@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi)
                goto fail0;
        }
 
-       dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
-                       "read", ds1305->ctrl[0],
-                       ds1305->ctrl[1], ds1305->ctrl[2]);
+       dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
 
        /* Sanity check register values ... partially compensating for the
         * fact that SPI has no device handshake.  A pullup on MISO would
@@ -723,9 +721,7 @@ static int ds1305_probe(struct spi_device *spi)
                        goto fail0;
                }
 
-               dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
-                               "write", ds1305->ctrl[0],
-                               ds1305->ctrl[1], ds1305->ctrl[2]);
+               dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
        }
 
        /* see if non-Linux software set up AM/PM mode */
index e0d0ba4..970a236 100644 (file)
@@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
                return -EIO;
        }
 
-       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
-                       "read",
-                       ds1307->regs[0], ds1307->regs[1],
-                       ds1307->regs[2], ds1307->regs[3],
-                       ds1307->regs[4], ds1307->regs[5],
-                       ds1307->regs[6]);
+       dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
 
        t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
        t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
@@ -398,9 +393,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                break;
        }
 
-       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
-               "write", buf[0], buf[1], buf[2], buf[3],
-               buf[4], buf[5], buf[6]);
+       dev_dbg(dev, "%s: %7ph\n", "write", buf);
 
        result = ds1307->write_block_data(ds1307->client,
                ds1307->offset, 7, buf);
index 5ea9df7..b04fc42 100644 (file)
@@ -70,7 +70,7 @@ static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
        for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
                err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
                if (err) {
-                       printk(KERN_ERR "error mapping gpio %s: %d\n",
+                       dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
                                ds2404_gpio[i].name, err);
                        goto err_request;
                }
@@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset,
 
        for (i = 0; i < length; i++) {
                if (out[i] != ds2404_read_byte(dev)) {
-                       printk(KERN_ERR "read invalid data\n");
+                       dev_err(dev, "read invalid data\n");
                        return;
                }
        }
@@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = {
                .owner  = THIS_MODULE,
        },
 };
-
-static __init int ds2404_init(void)
-{
-       return platform_driver_register(&rtc_device_driver);
-}
-
-static __exit void ds2404_exit(void)
-{
-       platform_driver_unregister(&rtc_device_driver);
-}
-
-module_init(ds2404_init);
-module_exit(ds2404_exit);
+module_platform_driver(rtc_device_driver);
 
 MODULE_DESCRIPTION("DS2404 RTC");
 MODULE_AUTHOR("Sven Schnelle");
index c9f890b..1a0c37c 100644 (file)
@@ -13,6 +13,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/time.h>
@@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft)
        int ndays = 0;
 
        if (eft->year < 1998) {
-               printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+               pr_err("EFI year < 1998, invalid date\n");
                return -1;
        }
 
@@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
        eft->day        = wtime->tm_mday;
        eft->hour       = wtime->tm_hour;
        eft->minute     = wtime->tm_min;
-       eft->second     = wtime->tm_sec;
+       eft->second     = wtime->tm_sec;
        eft->nanosecond = 0;
        eft->daylight   = wtime->tm_isdst ? EFI_ISDST : 0;
        eft->timezone   = EFI_UNSPECIFIED_TIMEZONE;
@@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
         */
        status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
 
-       printk(KERN_WARNING "write status is %d\n", (int)status);
+       dev_warn(dev, "write status is %d\n", (int)status);
 
        return status == EFI_SUCCESS ? 0 : -EINVAL;
 }
@@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
 
        if (status != EFI_SUCCESS) {
                /* should never happen */
-               printk(KERN_ERR "efitime: can't read time\n");
+               dev_err(dev, "can't read time\n");
                return -EINVAL;
        }
 
index 04e93c6..bff3cdc 100644 (file)
@@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
 
        fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
 
-       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
-                       "%02x %02x %02x %02x %02x %02x %02x\n",
-                       "read",
-                       fm3130->regs[0], fm3130->regs[1],
-                       fm3130->regs[2], fm3130->regs[3],
-                       fm3130->regs[4], fm3130->regs[5],
-                       fm3130->regs[6], fm3130->regs[7],
-                       fm3130->regs[8], fm3130->regs[9],
-                       fm3130->regs[0xa], fm3130->regs[0xb],
-                       fm3130->regs[0xc], fm3130->regs[0xd],
-                       fm3130->regs[0xe]);
+       dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs);
 
        t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
        t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
@@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t)
        tmp = t->tm_year - 100;
        buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
 
-       dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
-               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-               "write", buf[0], buf[1], buf[2], buf[3],
-               buf[4], buf[5], buf[6], buf[7],
-               buf[8], buf[9], buf[0xa], buf[0xb],
-               buf[0xc], buf[0xd], buf[0xe]);
+       dev_dbg(dev, "%s: %15ph\n", "write", buf);
 
        fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
 
@@ -517,18 +502,8 @@ bad_alarm:
 bad_clock:
 
        if (!fm3130->data_valid || !fm3130->alarm_valid)
-               dev_dbg(&client->dev,
-                               "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
-                               "%02x %02x %02x %02x %02x %02x %02x\n",
-                       "bogus registers",
-                       fm3130->regs[0], fm3130->regs[1],
-                       fm3130->regs[2], fm3130->regs[3],
-                       fm3130->regs[4], fm3130->regs[5],
-                       fm3130->regs[6], fm3130->regs[7],
-                       fm3130->regs[8], fm3130->regs[9],
-                       fm3130->regs[0xa], fm3130->regs[0xb],
-                       fm3130->regs[0xc], fm3130->regs[0xd],
-                       fm3130->regs[0xe]);
+               dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers",
+                       fm3130->regs);
 
        /* We won't bail out here because we just got invalid data.
           Time setting from u-boot doesn't work anyway */
index 75d307a..82aad69 100644 (file)
@@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev)
 
        mutex_init(&imxdi->write_mutex);
 
-       imxdi->clk = clk_get(&pdev->dev, NULL);
+       imxdi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(imxdi->clk))
                return PTR_ERR(imxdi->clk);
        clk_prepare_enable(imxdi->clk);
@@ -475,7 +475,6 @@ static int dryice_rtc_probe(struct platform_device *pdev)
 
 err:
        clk_disable_unprepare(imxdi->clk);
-       clk_put(imxdi->clk);
 
        return rc;
 }
@@ -492,7 +491,6 @@ static int dryice_rtc_remove(struct platform_device *pdev)
        rtc_device_unregister(imxdi->rtc);
 
        clk_disable_unprepare(imxdi->clk);
-       clk_put(imxdi->clk);
 
        return 0;
 }
index 1850104..6b4298e 100644 (file)
@@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
                                         buf[ISL12022_REG_SC + i]);
                if (ret)
                        return -EIO;
-       };
+       }
 
        return 0;
 }
diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c
new file mode 100644 (file)
index 0000000..9a46312
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * TI LP8788 MFD - rtc driver
+ *
+ * Copyright 2012 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/lp8788.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+/* register address */
+#define LP8788_INTEN_3                 0x05
+#define LP8788_RTC_UNLOCK              0x64
+#define LP8788_RTC_SEC                 0x70
+#define LP8788_ALM1_SEC                        0x77
+#define LP8788_ALM1_EN                 0x7D
+#define LP8788_ALM2_SEC                        0x7E
+#define LP8788_ALM2_EN                 0x84
+
+/* mask/shift bits */
+#define LP8788_INT_RTC_ALM1_M          BIT(1)  /* Addr 05h */
+#define LP8788_INT_RTC_ALM1_S          1
+#define LP8788_INT_RTC_ALM2_M          BIT(2)  /* Addr 05h */
+#define LP8788_INT_RTC_ALM2_S          2
+#define LP8788_ALM_EN_M                        BIT(7)  /* Addr 7Dh or 84h */
+#define LP8788_ALM_EN_S                        7
+
+#define DEFAULT_ALARM_SEL              LP8788_ALARM_1
+#define LP8788_MONTH_OFFSET            1
+#define LP8788_BASE_YEAR               2000
+#define MAX_WDAY_BITS                  7
+#define LP8788_WDAY_SET                        1
+#define RTC_UNLOCK                     0x1
+#define RTC_LATCH                      0x2
+#define ALARM_IRQ_FLAG                 (RTC_IRQF | RTC_AF)
+
+enum lp8788_time {
+       LPTIME_SEC,
+       LPTIME_MIN,
+       LPTIME_HOUR,
+       LPTIME_MDAY,
+       LPTIME_MON,
+       LPTIME_YEAR,
+       LPTIME_WDAY,
+       LPTIME_MAX,
+};
+
+struct lp8788_rtc {
+       struct lp8788 *lp;
+       struct rtc_device *rdev;
+       enum lp8788_alarm_sel alarm;
+       int irq;
+};
+
+static const u8 addr_alarm_sec[LP8788_ALARM_MAX] = {
+       LP8788_ALM1_SEC,
+       LP8788_ALM2_SEC,
+};
+
+static const u8 addr_alarm_en[LP8788_ALARM_MAX] = {
+       LP8788_ALM1_EN,
+       LP8788_ALM2_EN,
+};
+
+static const u8 mask_alarm_en[LP8788_ALARM_MAX] = {
+       LP8788_INT_RTC_ALM1_M,
+       LP8788_INT_RTC_ALM2_M,
+};
+
+static const u8 shift_alarm_en[LP8788_ALARM_MAX] = {
+       LP8788_INT_RTC_ALM1_S,
+       LP8788_INT_RTC_ALM2_S,
+};
+
+static int _to_tm_wday(u8 lp8788_wday)
+{
+       int i;
+
+       if (lp8788_wday == 0)
+               return 0;
+
+       /* lookup defined weekday from read register value */
+       for (i = 0; i < MAX_WDAY_BITS; i++) {
+               if ((lp8788_wday >> i) == LP8788_WDAY_SET)
+                       break;
+       }
+
+       return i + 1;
+}
+
+static inline int _to_lp8788_wday(int tm_wday)
+{
+       return LP8788_WDAY_SET << (tm_wday - 1);
+}
+
+static void lp8788_rtc_unlock(struct lp8788 *lp)
+{
+       lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_UNLOCK);
+       lp8788_write_byte(lp, LP8788_RTC_UNLOCK, RTC_LATCH);
+}
+
+static int lp8788_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct lp8788_rtc *rtc = dev_get_drvdata(dev);
+       struct lp8788 *lp = rtc->lp;
+       u8 data[LPTIME_MAX];
+       int ret;
+
+       lp8788_rtc_unlock(lp);
+
+       ret = lp8788_read_multi_bytes(lp, LP8788_RTC_SEC, data, LPTIME_MAX);
+       if (ret)
+               return ret;
+
+       tm->tm_sec  = data[LPTIME_SEC];
+       tm->tm_min  = data[LPTIME_MIN];
+       tm->tm_hour = data[LPTIME_HOUR];
+       tm->tm_mday = data[LPTIME_MDAY];
+       tm->tm_mon  = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
+       tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
+       tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
+
+       return 0;
+}
+
+static int lp8788_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct lp8788_rtc *rtc = dev_get_drvdata(dev);
+       struct lp8788 *lp = rtc->lp;
+       u8 data[LPTIME_MAX - 1];
+       int ret, i, year;
+
+       year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
+       if (year < 0) {
+               dev_err(lp->dev, "invalid year: %d\n", year);
+               return -EINVAL;
+       }
+
+       /* because rtc weekday is a readonly register, do not update */
+       data[LPTIME_SEC]  = tm->tm_sec;
+       data[LPTIME_MIN]  = tm->tm_min;
+       data[LPTIME_HOUR] = tm->tm_hour;
+       data[LPTIME_MDAY] = tm->tm_mday;
+       data[LPTIME_MON]  = tm->tm_mon + LP8788_MONTH_OFFSET;
+       data[LPTIME_YEAR] = year;
+
+       for (i = 0; i < ARRAY_SIZE(data); i++) {
+               ret = lp8788_write_byte(lp, LP8788_RTC_SEC + i, data[i]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int lp8788_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct lp8788_rtc *rtc = dev_get_drvdata(dev);
+       struct lp8788 *lp = rtc->lp;
+       struct rtc_time *tm = &alarm->time;
+       u8 addr, data[LPTIME_MAX];
+       int ret;
+
+       addr = addr_alarm_sec[rtc->alarm];
+       ret = lp8788_read_multi_bytes(lp, addr, data, LPTIME_MAX);
+       if (ret)
+               return ret;
+
+       tm->tm_sec  = data[LPTIME_SEC];
+       tm->tm_min  = data[LPTIME_MIN];
+       tm->tm_hour = data[LPTIME_HOUR];
+       tm->tm_mday = data[LPTIME_MDAY];
+       tm->tm_mon  = data[LPTIME_MON] - LP8788_MONTH_OFFSET;
+       tm->tm_year = data[LPTIME_YEAR] + LP8788_BASE_YEAR - 1900;
+       tm->tm_wday = _to_tm_wday(data[LPTIME_WDAY]);
+       alarm->enabled = data[LPTIME_WDAY] & LP8788_ALM_EN_M;
+
+       return 0;
+}
+
+static int lp8788_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+       struct lp8788_rtc *rtc = dev_get_drvdata(dev);
+       struct lp8788 *lp = rtc->lp;
+       struct rtc_time *tm = &alarm->time;
+       u8 addr, data[LPTIME_MAX];
+       int ret, i, year;
+
+       year = tm->tm_year + 1900 - LP8788_BASE_YEAR;
+       if (year < 0) {
+               dev_err(lp->dev, "invalid year: %d\n", year);
+               return -EINVAL;
+       }
+
+       data[LPTIME_SEC]  = tm->tm_sec;
+       data[LPTIME_MIN]  = tm->tm_min;
+       data[LPTIME_HOUR] = tm->tm_hour;
+       data[LPTIME_MDAY] = tm->tm_mday;
+       data[LPTIME_MON]  = tm->tm_mon + LP8788_MONTH_OFFSET;
+       data[LPTIME_YEAR] = year;
+       data[LPTIME_WDAY] = _to_lp8788_wday(tm->tm_wday);
+
+       for (i = 0; i < ARRAY_SIZE(data); i++) {
+               addr = addr_alarm_sec[rtc->alarm] + i;
+               ret = lp8788_write_byte(lp, addr, data[i]);
+               if (ret)
+                       return ret;
+       }
+
+       alarm->enabled = 1;
+       addr = addr_alarm_en[rtc->alarm];
+
+       return lp8788_update_bits(lp, addr, LP8788_ALM_EN_M,
+                               alarm->enabled << LP8788_ALM_EN_S);
+}
+
+static int lp8788_alarm_irq_enable(struct device *dev, unsigned int enable)
+{
+       struct lp8788_rtc *rtc = dev_get_drvdata(dev);
+       struct lp8788 *lp = rtc->lp;
+       u8 mask, shift;
+
+       if (!rtc->irq)
+               return -EIO;
+
+       mask = mask_alarm_en[rtc->alarm];
+       shift = shift_alarm_en[rtc->alarm];
+
+       return lp8788_update_bits(lp, LP8788_INTEN_3, mask, enable << shift);
+}
+
+static const struct rtc_class_ops lp8788_rtc_ops = {
+       .read_time = lp8788_rtc_read_time,
+       .set_time = lp8788_rtc_set_time,
+       .read_alarm = lp8788_read_alarm,
+       .set_alarm = lp8788_set_alarm,
+       .alarm_irq_enable = lp8788_alarm_irq_enable,
+};
+
+static irqreturn_t lp8788_alarm_irq_handler(int irq, void *ptr)
+{
+       struct lp8788_rtc *rtc = ptr;
+
+       rtc_update_irq(rtc->rdev, 1, ALARM_IRQ_FLAG);
+       return IRQ_HANDLED;
+}
+
+static int lp8788_alarm_irq_register(struct platform_device *pdev,
+                               struct lp8788_rtc *rtc)
+{
+       struct resource *r;
+       struct lp8788 *lp = rtc->lp;
+       struct irq_domain *irqdm = lp->irqdm;
+       int irq;
+
+       rtc->irq = 0;
+
+       /* even the alarm IRQ number is not specified, rtc time should work */
+       r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, LP8788_ALM_IRQ);
+       if (!r)
+               return 0;
+
+       if (rtc->alarm == LP8788_ALARM_1)
+               irq = r->start;
+       else
+               irq = r->end;
+
+       rtc->irq = irq_create_mapping(irqdm, irq);
+
+       return devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                               lp8788_alarm_irq_handler,
+                               0, LP8788_ALM_IRQ, rtc);
+}
+
+static int lp8788_rtc_probe(struct platform_device *pdev)
+{
+       struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent);
+       struct lp8788_rtc *rtc;
+       struct device *dev = &pdev->dev;
+
+       rtc = devm_kzalloc(dev, sizeof(struct lp8788_rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->lp = lp;
+       rtc->alarm = lp->pdata ? lp->pdata->alarm_sel : DEFAULT_ALARM_SEL;
+       platform_set_drvdata(pdev, rtc);
+
+       device_init_wakeup(dev, 1);
+
+       rtc->rdev = rtc_device_register("lp8788_rtc", dev,
+                                       &lp8788_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rdev)) {
+               dev_err(dev, "can not register rtc device\n");
+               return PTR_ERR(rtc->rdev);
+       }
+
+       if (lp8788_alarm_irq_register(pdev, rtc))
+               dev_warn(lp->dev, "no rtc irq handler\n");
+
+       return 0;
+}
+
+static int lp8788_rtc_remove(struct platform_device *pdev)
+{
+       struct lp8788_rtc *rtc = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(rtc->rdev);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver lp8788_rtc_driver = {
+       .probe = lp8788_rtc_probe,
+       .remove = lp8788_rtc_remove,
+       .driver = {
+               .name = LP8788_DEV_RTC,
+               .owner = THIS_MODULE,
+       },
+};
+module_platform_driver(lp8788_rtc_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8788 RTC Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lp8788-rtc");
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
new file mode 100644 (file)
index 0000000..6b1337f
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * RTC driver for Maxim MAX77686
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ *
+ *  based on rtc-max8997.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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max77686-private.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT                   0
+#define BCD_EN_MASK                            (1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT                  1
+#define MODEL24_MASK                   (1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT                  0
+#define RTC_UDR_MASK                   (1 << RTC_UDR_SHIFT)
+#define RTC_RBUDR_SHIFT                        4
+#define RTC_RBUDR_MASK                 (1 << RTC_RBUDR_SHIFT)
+/* WTSR and SMPL Register */
+#define WTSRT_SHIFT                            0
+#define SMPLT_SHIFT                            2
+#define WTSR_EN_SHIFT                  6
+#define SMPL_EN_SHIFT                  7
+#define WTSRT_MASK                             (3 << WTSRT_SHIFT)
+#define SMPLT_MASK                             (3 << SMPLT_SHIFT)
+#define WTSR_EN_MASK                   (1 << WTSR_EN_SHIFT)
+#define SMPL_EN_MASK                   (1 << SMPL_EN_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT                  6
+#define HOUR_PM_MASK                   (1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT             7
+#define ALARM_ENABLE_MASK              (1 << ALARM_ENABLE_SHIFT)
+
+#define MAX77686_RTC_UPDATE_DELAY      16
+#undef MAX77686_RTC_WTSR_SMPL
+
+enum {
+       RTC_SEC = 0,
+       RTC_MIN,
+       RTC_HOUR,
+       RTC_WEEKDAY,
+       RTC_MONTH,
+       RTC_YEAR,
+       RTC_DATE,
+       RTC_NR_TIME
+};
+
+struct max77686_rtc_info {
+       struct device           *dev;
+       struct max77686_dev     *max77686;
+       struct i2c_client       *rtc;
+       struct rtc_device       *rtc_dev;
+       struct mutex            lock;
+
+       struct regmap           *regmap;
+
+       int virq;
+       int rtc_24hr_mode;
+};
+
+enum MAX77686_RTC_OP {
+       MAX77686_RTC_WRITE,
+       MAX77686_RTC_READ,
+};
+
+static inline int max77686_rtc_calculate_wday(u8 shifted)
+{
+       int counter = -1;
+       while (shifted) {
+               shifted >>= 1;
+               counter++;
+       }
+       return counter;
+}
+
+static void max77686_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
+                                  int rtc_24hr_mode)
+{
+       tm->tm_sec = data[RTC_SEC] & 0x7f;
+       tm->tm_min = data[RTC_MIN] & 0x7f;
+       if (rtc_24hr_mode)
+               tm->tm_hour = data[RTC_HOUR] & 0x1f;
+       else {
+               tm->tm_hour = data[RTC_HOUR] & 0x0f;
+               if (data[RTC_HOUR] & HOUR_PM_MASK)
+                       tm->tm_hour += 12;
+       }
+
+       tm->tm_wday = max77686_rtc_calculate_wday(data[RTC_WEEKDAY] & 0x7f);
+       tm->tm_mday = data[RTC_DATE] & 0x1f;
+       tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
+       tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+}
+
+static int max77686_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+       data[RTC_SEC] = tm->tm_sec;
+       data[RTC_MIN] = tm->tm_min;
+       data[RTC_HOUR] = tm->tm_hour;
+       data[RTC_WEEKDAY] = 1 << tm->tm_wday;
+       data[RTC_DATE] = tm->tm_mday;
+       data[RTC_MONTH] = tm->tm_mon + 1;
+       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
+
+       if (tm->tm_year < 100) {
+               pr_warn("%s: MAX77686 RTC cannot handle the year %d."
+                       "Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int max77686_rtc_update(struct max77686_rtc_info *info,
+       enum MAX77686_RTC_OP op)
+{
+       int ret;
+       unsigned int data;
+
+       if (op == MAX77686_RTC_WRITE)
+               data = 1 << RTC_UDR_SHIFT;
+       else
+               data = 1 << RTC_RBUDR_SHIFT;
+
+       ret = regmap_update_bits(info->max77686->rtc_regmap,
+                                MAX77686_RTC_UPDATE0, data, data);
+       if (ret < 0)
+               dev_err(info->dev, "%s: fail to write update reg(ret=%d, data=0x%x)\n",
+                               __func__, ret, data);
+       else {
+               /* Minimum 16ms delay required before RTC update. */
+               msleep(MAX77686_RTC_UPDATE_DELAY);
+       }
+
+       return ret;
+}
+
+static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max77686_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77686->rtc_regmap,
+                               MAX77686_RTC_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__, ret);
+               goto out;
+       }
+
+       max77686_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+
+       ret = rtc_valid_tm(tm);
+
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max77686_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max77686_rtc_tm_to_data(tm, data);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&info->lock);
+
+       ret = regmap_bulk_write(info->max77686->rtc_regmap,
+                                MAX77686_RTC_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
+                               ret);
+               goto out;
+       }
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
+
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max77686_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       unsigned int val;
+       int i, ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       max77686_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+
+       alrm->enabled = 0;
+       for (i = 0; i < RTC_NR_TIME; i++) {
+               if (data[i] & ALARM_ENABLE_MASK) {
+                       alrm->enabled = 1;
+                       break;
+               }
+       }
+
+       alrm->pending = 0;
+       ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       if (val & (1 << 4)) /* RTCA1 */
+               alrm->pending = 1;
+
+out:
+       mutex_unlock(&info->lock);
+       return 0;
+}
+
+static int max77686_rtc_stop_alarm(struct max77686_rtc_info *info)
+{
+       u8 data[RTC_NR_TIME];
+       int ret, i;
+       struct rtc_time tm;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
+
+       for (i = 0; i < RTC_NR_TIME; i++)
+               data[i] &= ~ALARM_ENABLE_MASK;
+
+       ret = regmap_bulk_write(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
+out:
+       return ret;
+}
+
+static int max77686_rtc_start_alarm(struct max77686_rtc_info *info)
+{
+       u8 data[RTC_NR_TIME];
+       int ret;
+       struct rtc_time tm;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_READ);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_read(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       max77686_rtc_data_to_tm(data, &tm, info->rtc_24hr_mode);
+
+       data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
+       if (data[RTC_MONTH] & 0xf)
+               data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
+       if (data[RTC_YEAR] & 0x7f)
+               data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
+       if (data[RTC_DATE] & 0x1f)
+               data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
+
+       ret = regmap_bulk_write(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
+out:
+       return ret;
+}
+
+static int max77686_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max77686_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max77686_rtc_tm_to_data(&alrm->time, data);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max77686_rtc_stop_alarm(info);
+       if (ret < 0)
+               goto out;
+
+       ret = regmap_bulk_write(info->max77686->rtc_regmap,
+                                MAX77686_ALARM1_SEC, data, RTC_NR_TIME);
+
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
+       if (ret < 0)
+               goto out;
+
+       if (alrm->enabled)
+               ret = max77686_rtc_start_alarm(info);
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max77686_rtc_alarm_irq_enable(struct device *dev,
+                                       unsigned int enabled)
+{
+       struct max77686_rtc_info *info = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&info->lock);
+       if (enabled)
+               ret = max77686_rtc_start_alarm(info);
+       else
+               ret = max77686_rtc_stop_alarm(info);
+       mutex_unlock(&info->lock);
+
+       return ret;
+}
+
+static irqreturn_t max77686_rtc_alarm_irq(int irq, void *data)
+{
+       struct max77686_rtc_info *info = data;
+
+       dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
+
+       rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max77686_rtc_ops = {
+       .read_time = max77686_rtc_read_time,
+       .set_time = max77686_rtc_set_time,
+       .read_alarm = max77686_rtc_read_alarm,
+       .set_alarm = max77686_rtc_set_alarm,
+       .alarm_irq_enable = max77686_rtc_alarm_irq_enable,
+};
+
+#ifdef MAX77686_RTC_WTSR_SMPL
+static void max77686_rtc_enable_wtsr(struct max77686_rtc_info *info, bool enable)
+{
+       int ret;
+       unsigned int val, mask;
+
+       if (enable)
+               val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
+       else
+               val = 0;
+
+       mask = WTSR_EN_MASK | WTSRT_MASK;
+
+       dev_info(info->dev, "%s: %s WTSR\n", __func__,
+                       enable ? "enable" : "disable");
+
+       ret = regmap_update_bits(info->max77686->rtc_regmap,
+                                MAX77686_WTSR_SMPL_CNTL, mask, val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
+                               __func__, ret);
+               return;
+       }
+
+       max77686_rtc_update(info, MAX77686_RTC_WRITE);
+}
+
+static void max77686_rtc_enable_smpl(struct max77686_rtc_info *info, bool enable)
+{
+       int ret;
+       unsigned int val, mask;
+
+       if (enable)
+               val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
+       else
+               val = 0;
+
+       mask = SMPL_EN_MASK | SMPLT_MASK;
+
+       dev_info(info->dev, "%s: %s SMPL\n", __func__,
+                       enable ? "enable" : "disable");
+
+       ret = regmap_update_bits(info->max77686->rtc_regmap,
+                                MAX77686_WTSR_SMPL_CNTL, mask, val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
+                               __func__, ret);
+               return;
+       }
+
+       max77686_rtc_update(info, MAX77686_RTC_WRITE);
+
+       val = 0;
+       regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
+       pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
+}
+#endif /* MAX77686_RTC_WTSR_SMPL */
+
+static int max77686_rtc_init_reg(struct max77686_rtc_info *info)
+{
+       u8 data[2];
+       int ret;
+
+       /* Set RTC control register : Binary mode, 24hour mdoe */
+       data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+       data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+
+       info->rtc_24hr_mode = 1;
+
+       ret = regmap_bulk_write(info->max77686->rtc_regmap, MAX77686_RTC_CONTROLM, data, 2);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       ret = max77686_rtc_update(info, MAX77686_RTC_WRITE);
+       return ret;
+}
+
+static struct regmap_config max77686_rtc_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int max77686_rtc_probe(struct platform_device *pdev)
+{
+       struct max77686_dev *max77686 = dev_get_drvdata(pdev->dev.parent);
+       struct max77686_rtc_info *info;
+       int ret, virq;
+
+       dev_info(&pdev->dev, "%s\n", __func__);
+
+       info = kzalloc(sizeof(struct max77686_rtc_info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->max77686 = max77686;
+       info->rtc = max77686->rtc;
+       info->max77686->rtc_regmap = regmap_init_i2c(info->max77686->rtc,
+                                        &max77686_rtc_regmap_config);
+       if (IS_ERR(info->max77686->rtc_regmap)) {
+               ret = PTR_ERR(info->max77686->rtc_regmap);
+               dev_err(info->max77686->dev, "Failed to allocate register map: %d\n",
+                               ret);
+               kfree(info);
+               return ret;
+       }
+       platform_set_drvdata(pdev, info);
+
+       ret = max77686_rtc_init_reg(info);
+
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
+               goto err_rtc;
+       }
+
+#ifdef MAX77686_RTC_WTSR_SMPL
+       max77686_rtc_enable_wtsr(info, true);
+       max77686_rtc_enable_smpl(info, true);
+#endif
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       info->rtc_dev = rtc_device_register("max77686-rtc", &pdev->dev,
+                       &max77686_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(info->rtc_dev)) {
+               dev_info(&pdev->dev, "%s: fail\n", __func__);
+
+               ret = PTR_ERR(info->rtc_dev);
+               dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+               if (ret == 0)
+                       ret = -EINVAL;
+               goto err_rtc;
+       }
+       virq = irq_create_mapping(max77686->irq_domain, MAX77686_RTCIRQ_RTCA1);
+       if (!virq)
+               goto err_rtc;
+       info->virq = virq;
+
+       ret = request_threaded_irq(virq, NULL, max77686_rtc_alarm_irq, 0,
+                       "rtc-alarm0", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+                       info->virq, ret);
+               goto err_rtc;
+       }
+
+       goto out;
+err_rtc:
+       kfree(info);
+       return ret;
+out:
+       return ret;
+}
+
+static int max77686_rtc_remove(struct platform_device *pdev)
+{
+       struct max77686_rtc_info *info = platform_get_drvdata(pdev);
+
+       if (info) {
+               free_irq(info->virq, info);
+               rtc_device_unregister(info->rtc_dev);
+               kfree(info);
+       }
+
+       return 0;
+}
+
+static void max77686_rtc_shutdown(struct platform_device *pdev)
+{
+#ifdef MAX77686_RTC_WTSR_SMPL
+       struct max77686_rtc_info *info = platform_get_drvdata(pdev);
+       int i;
+       u8 val = 0;
+
+       for (i = 0; i < 3; i++) {
+               max77686_rtc_enable_wtsr(info, false);
+               regmap_read(info->max77686->rtc_regmap, MAX77686_WTSR_SMPL_CNTL, &val);
+               pr_info("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val);
+               if (val & WTSR_EN_MASK)
+                       pr_emerg("%s: fail to disable WTSR\n", __func__);
+               else {
+                       pr_info("%s: success to disable WTSR\n", __func__);
+                       break;
+               }
+       }
+
+       /* Disable SMPL when power off */
+       max77686_rtc_enable_smpl(info, false);
+#endif /* MAX77686_RTC_WTSR_SMPL */
+}
+
+static const struct platform_device_id rtc_id[] = {
+       { "max77686-rtc", 0 },
+       {},
+};
+
+static struct platform_driver max77686_rtc_driver = {
+       .driver         = {
+               .name   = "max77686-rtc",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max77686_rtc_probe,
+       .remove         = max77686_rtc_remove,
+       .shutdown       = max77686_rtc_shutdown,
+       .id_table       = rtc_id,
+};
+
+static int __init max77686_rtc_init(void)
+{
+       return platform_driver_register(&max77686_rtc_driver);
+}
+module_init(max77686_rtc_init);
+
+static void __exit max77686_rtc_exit(void)
+{
+       platform_driver_unregister(&max77686_rtc_driver);
+}
+module_exit(max77686_rtc_exit);
+
+MODULE_DESCRIPTION("Maxim MAX77686 RTC driver");
+MODULE_AUTHOR("<woong.byun@samsung.com>");
+MODULE_LICENSE("GPL");
index 1d049da..31ca8fa 100644 (file)
@@ -205,8 +205,9 @@ static int max8907_rtc_probe(struct platform_device *pdev)
                goto err_unregister;
        }
 
-       ret = request_threaded_irq(rtc->irq, NULL, max8907_irq_handler,
-                                  IRQF_ONESHOT, "max8907-alarm0", rtc);
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                               max8907_irq_handler,
+                               IRQF_ONESHOT, "max8907-alarm0", rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
                        rtc->irq, ret);
@@ -224,7 +225,6 @@ static int max8907_rtc_remove(struct platform_device *pdev)
 {
        struct max8907_rtc *rtc = platform_get_drvdata(pdev);
 
-       free_irq(rtc->irq, rtc);
        rtc_device_unregister(rtc->rtc_dev);
 
        return 0;
diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c
new file mode 100644 (file)
index 0000000..00e505b
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * RTC driver for Maxim MAX8997
+ *
+ * Copyright (C) 2013 Samsung Electronics Co.Ltd
+ *
+ *  based on rtc-max8998.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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/max8997-private.h>
+#include <linux/irqdomain.h>
+
+/* Module parameter for WTSR function control */
+static int wtsr_en = 1;
+module_param(wtsr_en, int, 0444);
+MODULE_PARM_DESC(wtsr_en, "Wachdog Timeout & Sofware Reset (default=on)");
+/* Module parameter for SMPL function control */
+static int smpl_en = 1;
+module_param(smpl_en, int, 0444);
+MODULE_PARM_DESC(smpl_en, "Sudden Momentary Power Loss (default=on)");
+
+/* RTC Control Register */
+#define BCD_EN_SHIFT                   0
+#define BCD_EN_MASK                    (1 << BCD_EN_SHIFT)
+#define MODEL24_SHIFT                  1
+#define MODEL24_MASK                   (1 << MODEL24_SHIFT)
+/* RTC Update Register1 */
+#define RTC_UDR_SHIFT                  0
+#define RTC_UDR_MASK                   (1 << RTC_UDR_SHIFT)
+/* WTSR and SMPL Register */
+#define WTSRT_SHIFT                    0
+#define SMPLT_SHIFT                    2
+#define WTSR_EN_SHIFT                  6
+#define SMPL_EN_SHIFT                  7
+#define WTSRT_MASK                     (3 << WTSRT_SHIFT)
+#define SMPLT_MASK                     (3 << SMPLT_SHIFT)
+#define WTSR_EN_MASK                   (1 << WTSR_EN_SHIFT)
+#define SMPL_EN_MASK                   (1 << SMPL_EN_SHIFT)
+/* RTC Hour register */
+#define HOUR_PM_SHIFT                  6
+#define HOUR_PM_MASK                   (1 << HOUR_PM_SHIFT)
+/* RTC Alarm Enable */
+#define ALARM_ENABLE_SHIFT             7
+#define ALARM_ENABLE_MASK              (1 << ALARM_ENABLE_SHIFT)
+
+enum {
+       RTC_SEC = 0,
+       RTC_MIN,
+       RTC_HOUR,
+       RTC_WEEKDAY,
+       RTC_MONTH,
+       RTC_YEAR,
+       RTC_DATE,
+       RTC_NR_TIME
+};
+
+struct max8997_rtc_info {
+       struct device           *dev;
+       struct max8997_dev      *max8997;
+       struct i2c_client       *rtc;
+       struct rtc_device       *rtc_dev;
+       struct mutex            lock;
+       int virq;
+       int rtc_24hr_mode;
+};
+
+static void max8997_rtc_data_to_tm(u8 *data, struct rtc_time *tm,
+                                  int rtc_24hr_mode)
+{
+       tm->tm_sec = data[RTC_SEC] & 0x7f;
+       tm->tm_min = data[RTC_MIN] & 0x7f;
+       if (rtc_24hr_mode)
+               tm->tm_hour = data[RTC_HOUR] & 0x1f;
+       else {
+               tm->tm_hour = data[RTC_HOUR] & 0x0f;
+               if (data[RTC_HOUR] & HOUR_PM_MASK)
+                       tm->tm_hour += 12;
+       }
+
+       tm->tm_wday = fls(data[RTC_WEEKDAY] & 0x7f) - 1;
+       tm->tm_mday = data[RTC_DATE] & 0x1f;
+       tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
+       tm->tm_year = (data[RTC_YEAR] & 0x7f) + 100;
+       tm->tm_yday = 0;
+       tm->tm_isdst = 0;
+}
+
+static int max8997_rtc_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+       data[RTC_SEC] = tm->tm_sec;
+       data[RTC_MIN] = tm->tm_min;
+       data[RTC_HOUR] = tm->tm_hour;
+       data[RTC_WEEKDAY] = 1 << tm->tm_wday;
+       data[RTC_DATE] = tm->tm_mday;
+       data[RTC_MONTH] = tm->tm_mon + 1;
+       data[RTC_YEAR] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0 ;
+
+       if (tm->tm_year < 100) {
+               pr_warn("%s: MAX8997 RTC cannot handle the year %d."
+                       "Assume it's 2000.\n", __func__, 1900 + tm->tm_year);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info)
+{
+       int ret;
+
+       ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1,
+                                               RTC_UDR_MASK);
+       if (ret < 0)
+               dev_err(info->dev, "%s: fail to write update reg(%d)\n",
+                               __func__, ret);
+       else {
+               /* Minimum 16ms delay required before RTC update.
+                * Otherwise, we may read and update based on out-of-date
+                * value */
+               msleep(20);
+       }
+
+       return ret;
+}
+
+static int max8997_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max8997_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       mutex_lock(&info->lock);
+       ret = max8997_bulk_read(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
+       mutex_unlock(&info->lock);
+
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read time reg(%d)\n", __func__,
+                               ret);
+               return ret;
+       }
+
+       max8997_rtc_data_to_tm(data, tm, info->rtc_24hr_mode);
+
+       return rtc_valid_tm(tm);
+}
+
+static int max8997_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct max8997_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max8997_rtc_tm_to_data(tm, data);
+       if (ret < 0)
+               return ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max8997_bulk_write(info->rtc, MAX8997_RTC_SEC, RTC_NR_TIME, data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write time reg(%d)\n", __func__,
+                               ret);
+               goto out;
+       }
+
+       ret = max8997_rtc_set_update_reg(info);
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max8997_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       u8 val;
+       int i, ret;
+
+       mutex_lock(&info->lock);
+
+       ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                       data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read alarm reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       max8997_rtc_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
+
+       alrm->enabled = 0;
+       for (i = 0; i < RTC_NR_TIME; i++) {
+               if (data[i] & ALARM_ENABLE_MASK) {
+                       alrm->enabled = 1;
+                       break;
+               }
+       }
+
+       alrm->pending = 0;
+       ret = max8997_read_reg(info->max8997->i2c, MAX8997_REG_STATUS1, &val);
+       if (ret < 0) {
+               dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
+                               __func__, __LINE__, ret);
+               goto out;
+       }
+
+       if (val & (1 << 4)) /* RTCA1 */
+               alrm->pending = 1;
+
+out:
+       mutex_unlock(&info->lock);
+       return 0;
+}
+
+static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info)
+{
+       u8 data[RTC_NR_TIME];
+       int ret, i;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+       ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                               data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       for (i = 0; i < RTC_NR_TIME; i++)
+               data[i] &= ~ALARM_ENABLE_MASK;
+
+       ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                                data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max8997_rtc_set_update_reg(info);
+out:
+       return ret;
+}
+
+static int max8997_rtc_start_alarm(struct max8997_rtc_info *info)
+{
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       if (!mutex_is_locked(&info->lock))
+               dev_warn(info->dev, "%s: should have mutex locked\n", __func__);
+
+       ret = max8997_bulk_read(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                               data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to read alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       data[RTC_SEC] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_MIN] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_HOUR] |= (1 << ALARM_ENABLE_SHIFT);
+       data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
+       if (data[RTC_MONTH] & 0xf)
+               data[RTC_MONTH] |= (1 << ALARM_ENABLE_SHIFT);
+       if (data[RTC_YEAR] & 0x7f)
+               data[RTC_YEAR] |= (1 << ALARM_ENABLE_SHIFT);
+       if (data[RTC_DATE] & 0x1f)
+               data[RTC_DATE] |= (1 << ALARM_ENABLE_SHIFT);
+
+       ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                                data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max8997_rtc_set_update_reg(info);
+out:
+       return ret;
+}
+static int max8997_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct max8997_rtc_info *info = dev_get_drvdata(dev);
+       u8 data[RTC_NR_TIME];
+       int ret;
+
+       ret = max8997_rtc_tm_to_data(&alrm->time, data);
+       if (ret < 0)
+               return ret;
+
+       dev_info(info->dev, "%s: %d-%02d-%02d %02d:%02d:%02d\n", __func__,
+                       data[RTC_YEAR] + 2000, data[RTC_MONTH], data[RTC_DATE],
+                       data[RTC_HOUR], data[RTC_MIN], data[RTC_SEC]);
+
+       mutex_lock(&info->lock);
+
+       ret = max8997_rtc_stop_alarm(info);
+       if (ret < 0)
+               goto out;
+
+       ret = max8997_bulk_write(info->rtc, MAX8997_RTC_ALARM1_SEC, RTC_NR_TIME,
+                               data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write alarm reg(%d)\n",
+                               __func__, ret);
+               goto out;
+       }
+
+       ret = max8997_rtc_set_update_reg(info);
+       if (ret < 0)
+               goto out;
+
+       if (alrm->enabled)
+               ret = max8997_rtc_start_alarm(info);
+out:
+       mutex_unlock(&info->lock);
+       return ret;
+}
+
+static int max8997_rtc_alarm_irq_enable(struct device *dev,
+                                       unsigned int enabled)
+{
+       struct max8997_rtc_info *info = dev_get_drvdata(dev);
+       int ret;
+
+       mutex_lock(&info->lock);
+       if (enabled)
+               ret = max8997_rtc_start_alarm(info);
+       else
+               ret = max8997_rtc_stop_alarm(info);
+       mutex_unlock(&info->lock);
+
+       return ret;
+}
+
+static irqreturn_t max8997_rtc_alarm_irq(int irq, void *data)
+{
+       struct max8997_rtc_info *info = data;
+
+       dev_info(info->dev, "%s:irq(%d)\n", __func__, irq);
+
+       rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops max8997_rtc_ops = {
+       .read_time = max8997_rtc_read_time,
+       .set_time = max8997_rtc_set_time,
+       .read_alarm = max8997_rtc_read_alarm,
+       .set_alarm = max8997_rtc_set_alarm,
+       .alarm_irq_enable = max8997_rtc_alarm_irq_enable,
+};
+
+static void max8997_rtc_enable_wtsr(struct max8997_rtc_info *info, bool enable)
+{
+       int ret;
+       u8 val, mask;
+
+       if (!wtsr_en)
+               return;
+
+       if (enable)
+               val = (1 << WTSR_EN_SHIFT) | (3 << WTSRT_SHIFT);
+       else
+               val = 0;
+
+       mask = WTSR_EN_MASK | WTSRT_MASK;
+
+       dev_info(info->dev, "%s: %s WTSR\n", __func__,
+                       enable ? "enable" : "disable");
+
+       ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n",
+                               __func__, ret);
+               return;
+       }
+
+       max8997_rtc_set_update_reg(info);
+}
+
+static void max8997_rtc_enable_smpl(struct max8997_rtc_info *info, bool enable)
+{
+       int ret;
+       u8 val, mask;
+
+       if (!smpl_en)
+               return;
+
+       if (enable)
+               val = (1 << SMPL_EN_SHIFT) | (0 << SMPLT_SHIFT);
+       else
+               val = 0;
+
+       mask = SMPL_EN_MASK | SMPLT_MASK;
+
+       dev_info(info->dev, "%s: %s SMPL\n", __func__,
+                       enable ? "enable" : "disable");
+
+       ret = max8997_update_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, val, mask);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n",
+                               __func__, ret);
+               return;
+       }
+
+       max8997_rtc_set_update_reg(info);
+
+       val = 0;
+       max8997_read_reg(info->rtc, MAX8997_RTC_WTSR_SMPL, &val);
+       pr_info("%s: WTSR_SMPL(0x%02x)\n", __func__, val);
+}
+
+static int max8997_rtc_init_reg(struct max8997_rtc_info *info)
+{
+       u8 data[2];
+       int ret;
+
+       /* Set RTC control register : Binary mode, 24hour mdoe */
+       data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+       data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
+
+       info->rtc_24hr_mode = 1;
+
+       ret = max8997_bulk_write(info->rtc, MAX8997_RTC_CTRLMASK, 2, data);
+       if (ret < 0) {
+               dev_err(info->dev, "%s: fail to write controlm reg(%d)\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       ret = max8997_rtc_set_update_reg(info);
+       return ret;
+}
+
+static int max8997_rtc_probe(struct platform_device *pdev)
+{
+       struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
+       struct max8997_rtc_info *info;
+       int ret, virq;
+
+       info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_rtc_info),
+                       GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       mutex_init(&info->lock);
+       info->dev = &pdev->dev;
+       info->max8997 = max8997;
+       info->rtc = max8997->rtc;
+
+       platform_set_drvdata(pdev, info);
+
+       ret = max8997_rtc_init_reg(info);
+
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to initialize RTC reg:%d\n", ret);
+               return ret;
+       }
+
+       max8997_rtc_enable_wtsr(info, true);
+       max8997_rtc_enable_smpl(info, true);
+
+       device_init_wakeup(&pdev->dev, 1);
+
+       info->rtc_dev = rtc_device_register("max8997-rtc", &pdev->dev,
+                       &max8997_rtc_ops, THIS_MODULE);
+
+       if (IS_ERR(info->rtc_dev)) {
+               ret = PTR_ERR(info->rtc_dev);
+               dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+               return ret;
+       }
+
+       virq = irq_create_mapping(max8997->irq_domain, MAX8997_PMICIRQ_RTCA1);
+       if (!virq) {
+               dev_err(&pdev->dev, "Failed to create mapping alarm IRQ\n");
+               goto err_out;
+       }
+       info->virq = virq;
+
+       ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+                               max8997_rtc_alarm_irq, 0,
+                               "rtc-alarm0", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n",
+                       info->virq, ret);
+               goto err_out;
+       }
+
+       return ret;
+
+err_out:
+       rtc_device_unregister(info->rtc_dev);
+       return ret;
+}
+
+static int max8997_rtc_remove(struct platform_device *pdev)
+{
+       struct max8997_rtc_info *info = platform_get_drvdata(pdev);
+
+       if (info)
+               rtc_device_unregister(info->rtc_dev);
+
+       return 0;
+}
+
+static void max8997_rtc_shutdown(struct platform_device *pdev)
+{
+       struct max8997_rtc_info *info = platform_get_drvdata(pdev);
+
+       max8997_rtc_enable_wtsr(info, false);
+       max8997_rtc_enable_smpl(info, false);
+}
+
+static const struct platform_device_id rtc_id[] = {
+       { "max8997-rtc", 0 },
+       {},
+};
+
+static struct platform_driver max8997_rtc_driver = {
+       .driver         = {
+               .name   = "max8997-rtc",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max8997_rtc_probe,
+       .remove         = max8997_rtc_remove,
+       .shutdown       = max8997_rtc_shutdown,
+       .id_table       = rtc_id,
+};
+
+module_platform_driver(max8997_rtc_driver);
+
+MODULE_DESCRIPTION("Maxim MAX8997 RTC driver");
+MODULE_AUTHOR("<ms925.kim@samsung.com>");
+MODULE_LICENSE("GPL");
index bec10be..bdcc608 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/io.h>
@@ -403,17 +404,19 @@ static int mpc5121_rtc_remove(struct platform_device *op)
        return 0;
 }
 
+#ifdef CONFIG_OF
 static struct of_device_id mpc5121_rtc_match[] = {
        { .compatible = "fsl,mpc5121-rtc", },
        { .compatible = "fsl,mpc5200-rtc", },
        {},
 };
+#endif
 
 static struct platform_driver mpc5121_rtc_driver = {
        .driver = {
                .name = "mpc5121-rtc",
                .owner = THIS_MODULE,
-               .of_match_table = mpc5121_rtc_match,
+               .of_match_table = of_match_ptr(mpc5121_rtc_match),
        },
        .probe = mpc5121_rtc_probe,
        .remove = mpc5121_rtc_remove,
index be05a64..889e316 100644 (file)
@@ -23,6 +23,7 @@
 #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */
 #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */
 #define REG_CONTROL3_PM_MASK 0xe0
+#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */
 
 #define REG_SECONDS  0x03
 #define REG_SECONDS_OS (1 << 7)
@@ -250,9 +251,39 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return pcf8523_start_rtc(client);
 }
 
+#ifdef CONFIG_RTC_INTF_DEV
+static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
+                            unsigned long arg)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       u8 value;
+       int ret = 0, err;
+
+       switch (cmd) {
+       case RTC_VL_READ:
+               err = pcf8523_read(client, REG_CONTROL3, &value);
+               if (err < 0)
+                       return err;
+
+               if (value & REG_CONTROL3_BLF)
+                       ret = 1;
+
+               if (copy_to_user((void __user *)arg, &ret, sizeof(int)))
+                       return -EFAULT;
+
+               return 0;
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+#else
+#define pcf8523_rtc_ioctl NULL
+#endif
+
 static const struct rtc_class_ops pcf8523_rtc_ops = {
        .read_time = pcf8523_rtc_read_time,
        .set_time = pcf8523_rtc_set_time,
+       .ioctl = pcf8523_rtc_ioctl,
 };
 
 static int pcf8523_probe(struct i2c_client *client,
index 7098ee8..f7daf18 100644 (file)
@@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
                                __func__, err, data[0], data[1]);
                        return -EIO;
                }
-       };
+       }
 
        return 0;
 }
index 3415b8f..5f97c61 100644 (file)
@@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
        if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
                unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
 
-               printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
-                      ctrl, new_ctrl);
+               dev_warn(dev, "resetting control %02x -> %02x\n",
+                       ctrl, new_ctrl);
 
                if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
                        return err;
index 81c5077..8900ea7 100644 (file)
@@ -384,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
                goto out_no_irq;
        }
 
+       device_init_wakeup(&adev->dev, 1);
+
        return 0;
 
 out_no_irq:
index f771b2e..03c85ee 100644 (file)
 #define RYxR_MONTH_S   5
 #define RYxR_MONTH_MASK        (0xf << RYxR_MONTH_S)
 #define RYxR_DAY_MASK  0x1f
+#define RDxR_WOM_S     20
+#define RDxR_WOM_MASK  (0x7 << RDxR_WOM_S)
+#define RDxR_DOW_S     17
+#define RDxR_DOW_MASK  (0x7 << RDxR_DOW_S)
 #define RDxR_HOUR_S    12
 #define RDxR_HOUR_MASK (0x1f << RDxR_HOUR_S)
 #define RDxR_MIN_S     6
@@ -91,6 +95,7 @@ struct pxa_rtc {
        spinlock_t              lock;           /* Protects this structure */
 };
 
+
 static u32 ryxr_calc(struct rtc_time *tm)
 {
        return ((tm->tm_year + 1900) << RYxR_YEAR_S)
@@ -100,7 +105,10 @@ static u32 ryxr_calc(struct rtc_time *tm)
 
 static u32 rdxr_calc(struct rtc_time *tm)
 {
-       return (tm->tm_hour << RDxR_HOUR_S) | (tm->tm_min << RDxR_MIN_S)
+       return ((((tm->tm_mday + 6) / 7) << RDxR_WOM_S) & RDxR_WOM_MASK)
+               | (((tm->tm_wday + 1) << RDxR_DOW_S) & RDxR_DOW_MASK)
+               | (tm->tm_hour << RDxR_HOUR_S)
+               | (tm->tm_min << RDxR_MIN_S)
                | tm->tm_sec;
 }
 
@@ -109,6 +117,7 @@ static void tm_calc(u32 rycr, u32 rdcr, struct rtc_time *tm)
        tm->tm_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900;
        tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
        tm->tm_mday = (rycr & RYxR_DAY_MASK);
+       tm->tm_wday = ((rycr & RDxR_DOW_MASK) >> RDxR_DOW_S) - 1;
        tm->tm_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S;
        tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
        tm->tm_sec = rdcr & RDxR_SEC_MASK;
@@ -300,8 +309,6 @@ static int pxa_rtc_proc(struct device *dev, struct seq_file *seq)
 }
 
 static const struct rtc_class_ops pxa_rtc_ops = {
-       .open = pxa_rtc_open,
-       .release = pxa_rtc_release,
        .read_time = pxa_rtc_read_time,
        .set_time = pxa_rtc_set_time,
        .read_alarm = pxa_rtc_read_alarm,
@@ -341,7 +348,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
                dev_err(dev, "No alarm IRQ resource defined\n");
                goto err_ress;
        }
-
+       pxa_rtc_open(dev);
        ret = -ENOMEM;
        pxa_rtc->base = ioremap(pxa_rtc->ress->start,
                                resource_size(pxa_rtc->ress));
@@ -387,6 +394,9 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
 {
        struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
 
+       struct device *dev = &pdev->dev;
+       pxa_rtc_release(dev);
+
        rtc_device_unregister(pxa_rtc->rtc);
 
        spin_lock_irq(&pxa_rtc->lock);
@@ -444,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = {
 
 static int __init pxa_rtc_init(void)
 {
-       if (cpu_is_pxa27x() || cpu_is_pxa3xx())
-               return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
-
-       return -ENODEV;
+       return platform_driver_probe(&pxa_rtc_driver, pxa_rtc_probe);
 }
 
 static void __exit pxa_rtc_exit(void)
index d1aee79..d98ea5b 100644 (file)
@@ -39,6 +39,8 @@
  *     1.13    Nobuhiro Iwamatsu: Updata driver.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/rtc.h>
@@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void)
                tm.tm_year      = 2000 - 1900;
 
                rs5c313_rtc_set_time(NULL, &tm);
-               printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
-                               "1 Jan 2000\n");
+               pr_err("invalid value, resetting to 1 Jan 2000\n");
        }
        RS5C313_CEDISABLE;
        ndelay(700);            /* CE:L */
index 76f565a..581739f 100644 (file)
@@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
                buf &= ~RS5C_CTRL1_AALE;
 
        if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
-               printk(KERN_WARNING "%s: can't update alarm\n",
-                       rs5c->rtc->name);
+               dev_warn(dev, "can't update alarm\n");
                status = -EIO;
        } else
                rs5c->regs[RS5C_REG_CTRL1] = buf;
@@ -381,7 +380,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                addr = RS5C_ADDR(RS5C_REG_CTRL1);
                buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
                if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
-                       pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
+                       dev_dbg(dev, "can't disable alarm\n");
                        return -EIO;
                }
                rs5c->regs[RS5C_REG_CTRL1] = buf[0];
@@ -395,7 +394,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        for (i = 0; i < sizeof(buf); i++) {
                addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
                if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
-                       pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
+                       dev_dbg(dev, "can't set alarm time\n");
                        return -EIO;
                }
        }
@@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                addr = RS5C_ADDR(RS5C_REG_CTRL1);
                buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
                if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
-                       printk(KERN_WARNING "%s: can't enable alarm\n",
-                               rs5c->rtc->name);
+                       dev_warn(dev, "can't enable alarm\n");
                rs5c->regs[RS5C_REG_CTRL1] = buf[0];
        }
 
diff --git a/drivers/rtc/rtc-rx4581.c b/drivers/rtc/rtc-rx4581.c
new file mode 100644 (file)
index 0000000..599ec73
--- /dev/null
@@ -0,0 +1,314 @@
+/* drivers/rtc/rtc-rx4581.c
+ *
+ * written by Torben Hohn <torbenh@linutronix.de>
+ *
+ * Based on:
+ * drivers/rtc/rtc-max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * 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.
+ *
+ * Driver for MAX6902 spi RTC
+ *
+ * and based on:
+ * drivers/rtc/rtc-rx8581.c
+ *
+ * An I2C driver for the Epson RX8581 RTC
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * 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.
+ *
+ * Based on: rtc-pcf8563.c (An I2C driver for the Philips PCF8563 RTC)
+ * Copyright 2005-06 Tower Technologies
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#define RX4581_REG_SC          0x00 /* Second in BCD */
+#define RX4581_REG_MN          0x01 /* Minute in BCD */
+#define RX4581_REG_HR          0x02 /* Hour in BCD */
+#define RX4581_REG_DW          0x03 /* Day of Week */
+#define RX4581_REG_DM          0x04 /* Day of Month in BCD */
+#define RX4581_REG_MO          0x05 /* Month in BCD */
+#define RX4581_REG_YR          0x06 /* Year in BCD */
+#define RX4581_REG_RAM         0x07 /* RAM */
+#define RX4581_REG_AMN         0x08 /* Alarm Min in BCD*/
+#define RX4581_REG_AHR         0x09 /* Alarm Hour in BCD */
+#define RX4581_REG_ADM         0x0A
+#define RX4581_REG_ADW         0x0A
+#define RX4581_REG_TMR0                0x0B
+#define RX4581_REG_TMR1                0x0C
+#define RX4581_REG_EXT         0x0D /* Extension Register */
+#define RX4581_REG_FLAG                0x0E /* Flag Register */
+#define RX4581_REG_CTRL                0x0F /* Control Register */
+
+
+/* Flag Register bit definitions */
+#define RX4581_FLAG_UF         0x20 /* Update */
+#define RX4581_FLAG_TF         0x10 /* Timer */
+#define RX4581_FLAG_AF         0x08 /* Alarm */
+#define RX4581_FLAG_VLF                0x02 /* Voltage Low */
+
+/* Control Register bit definitions */
+#define RX4581_CTRL_UIE                0x20 /* Update Interrupt Enable */
+#define RX4581_CTRL_TIE                0x10 /* Timer Interrupt Enable */
+#define RX4581_CTRL_AIE                0x08 /* Alarm Interrupt Enable */
+#define RX4581_CTRL_STOP       0x02 /* STOP bit */
+#define RX4581_CTRL_RESET      0x01 /* RESET bit */
+
+static int rx4581_set_reg(struct device *dev, unsigned char address,
+                               unsigned char data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char buf[2];
+
+       /* high nibble must be '0' to write */
+       buf[0] = address & 0x0f;
+       buf[1] = data;
+
+       return spi_write_then_read(spi, buf, 2, NULL, 0);
+}
+
+static int rx4581_get_reg(struct device *dev, unsigned char address,
+                               unsigned char *data)
+{
+       struct spi_device *spi = to_spi_device(dev);
+
+       /* Set MSB to indicate read */
+       *data = address | 0x80;
+
+       return spi_write_then_read(spi, data, 1, data, 1);
+}
+
+/*
+ * In the routines that deal directly with the rx8581 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int rx4581_get_datetime(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       unsigned char date[7];
+       unsigned char data;
+       int err;
+
+       /* First we ensure that the "update flag" is not set, we read the
+        * time and date then re-read the "update flag". If the update flag
+        * has been set, we know that the time has changed during the read so
+        * we repeat the whole process again.
+        */
+       err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
+       if (err != 0) {
+               dev_err(dev, "Unable to read device flags\n");
+               return -EIO;
+       }
+
+       do {
+               /* If update flag set, clear it */
+               if (data & RX4581_FLAG_UF) {
+                       err = rx4581_set_reg(dev,
+                               RX4581_REG_FLAG, (data & ~RX4581_FLAG_UF));
+                       if (err != 0) {
+                               dev_err(dev, "Unable to write device "
+                                       "flags\n");
+                               return -EIO;
+                       }
+               }
+
+               /* Now read time and date */
+               date[0] = 0x80;
+               err = spi_write_then_read(spi, date, 1, date, 7);
+               if (err < 0) {
+                       dev_err(dev, "Unable to read date\n");
+                       return -EIO;
+               }
+
+               /* Check flag register */
+               err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
+               if (err != 0) {
+                       dev_err(dev, "Unable to read device flags\n");
+                       return -EIO;
+               }
+       } while (data & RX4581_FLAG_UF);
+
+       if (data & RX4581_FLAG_VLF)
+               dev_info(dev,
+                       "low voltage detected, date/time is not reliable.\n");
+
+       dev_dbg(dev,
+               "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
+               "wday=%02x, mday=%02x, mon=%02x, year=%02x\n",
+               __func__,
+               date[0], date[1], date[2], date[3], date[4], date[5], date[6]);
+
+       tm->tm_sec = bcd2bin(date[RX4581_REG_SC] & 0x7F);
+       tm->tm_min = bcd2bin(date[RX4581_REG_MN] & 0x7F);
+       tm->tm_hour = bcd2bin(date[RX4581_REG_HR] & 0x3F); /* rtc hr 0-23 */
+       tm->tm_wday = ilog2(date[RX4581_REG_DW] & 0x7F);
+       tm->tm_mday = bcd2bin(date[RX4581_REG_DM] & 0x3F);
+       tm->tm_mon = bcd2bin(date[RX4581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+       tm->tm_year = bcd2bin(date[RX4581_REG_YR]);
+       if (tm->tm_year < 70)
+               tm->tm_year += 100;     /* assume we are in 1970...2069 */
+
+
+       dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       err = rtc_valid_tm(tm);
+       if (err < 0)
+               dev_err(dev, "retrieved date/time is not valid.\n");
+
+       return err;
+}
+
+static int rx4581_set_datetime(struct device *dev, struct rtc_time *tm)
+{
+       struct spi_device *spi = to_spi_device(dev);
+       int err;
+       unsigned char buf[8], data;
+
+       dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
+               "mday=%d, mon=%d, year=%d, wday=%d\n",
+               __func__,
+               tm->tm_sec, tm->tm_min, tm->tm_hour,
+               tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+       buf[0] = 0x00;
+       /* hours, minutes and seconds */
+       buf[RX4581_REG_SC+1] = bin2bcd(tm->tm_sec);
+       buf[RX4581_REG_MN+1] = bin2bcd(tm->tm_min);
+       buf[RX4581_REG_HR+1] = bin2bcd(tm->tm_hour);
+
+       buf[RX4581_REG_DM+1] = bin2bcd(tm->tm_mday);
+
+       /* month, 1 - 12 */
+       buf[RX4581_REG_MO+1] = bin2bcd(tm->tm_mon + 1);
+
+       /* year and century */
+       buf[RX4581_REG_YR+1] = bin2bcd(tm->tm_year % 100);
+       buf[RX4581_REG_DW+1] = (0x1 << tm->tm_wday);
+
+       /* Stop the clock */
+       err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data);
+       if (err != 0) {
+               dev_err(dev, "Unable to read control register\n");
+               return -EIO;
+       }
+
+       err = rx4581_set_reg(dev, RX4581_REG_CTRL,
+               (data | RX4581_CTRL_STOP));
+       if (err != 0) {
+               dev_err(dev, "Unable to write control register\n");
+               return -EIO;
+       }
+
+       /* write register's data */
+       err = spi_write_then_read(spi, buf, 8, NULL, 0);
+       if (err != 0) {
+               dev_err(dev, "Unable to write to date registers\n");
+               return -EIO;
+       }
+
+       /* get VLF and clear it */
+       err = rx4581_get_reg(dev, RX4581_REG_FLAG, &data);
+       if (err != 0) {
+               dev_err(dev, "Unable to read flag register\n");
+               return -EIO;
+       }
+
+       err = rx4581_set_reg(dev, RX4581_REG_FLAG,
+               (data & ~(RX4581_FLAG_VLF)));
+       if (err != 0) {
+               dev_err(dev, "Unable to write flag register\n");
+               return -EIO;
+       }
+
+       /* Restart the clock */
+       err = rx4581_get_reg(dev, RX4581_REG_CTRL, &data);
+       if (err != 0) {
+               dev_err(dev, "Unable to read control register\n");
+               return -EIO;
+       }
+
+       err = rx4581_set_reg(dev, RX4581_REG_CTRL,
+               (data & ~(RX4581_CTRL_STOP)));
+       if (err != 0) {
+               dev_err(dev, "Unable to write control register\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static const struct rtc_class_ops rx4581_rtc_ops = {
+       .read_time      = rx4581_get_datetime,
+       .set_time       = rx4581_set_datetime,
+};
+
+static int rx4581_probe(struct spi_device *spi)
+{
+       struct rtc_device *rtc;
+       unsigned char tmp;
+       int res;
+
+       res = rx4581_get_reg(&spi->dev, RX4581_REG_SC, &tmp);
+       if (res != 0)
+               return res;
+
+       rtc = rtc_device_register("rx4581",
+                               &spi->dev, &rx4581_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+
+       dev_set_drvdata(&spi->dev, rtc);
+       return 0;
+}
+
+static int rx4581_remove(struct spi_device *spi)
+{
+       struct rtc_device *rtc = dev_get_drvdata(&spi->dev);
+
+       rtc_device_unregister(rtc);
+       return 0;
+}
+
+static const struct spi_device_id rx4581_id[] = {
+       { "rx4581", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, rx4581_id);
+
+static struct spi_driver rx4581_driver = {
+       .driver = {
+               .name   = "rtc-rx4581",
+               .owner  = THIS_MODULE,
+       },
+       .probe  = rx4581_probe,
+       .remove = rx4581_remove,
+       .id_table = rx4581_id,
+};
+
+module_spi_driver(rx4581_driver);
+
+MODULE_DESCRIPTION("rx4581 spi RTC driver");
+MODULE_AUTHOR("Torben Hohn");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:rtc-rx4581");
index 0c397ac..fb994e9 100644 (file)
@@ -115,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
        unsigned int tmp;
 
-       pr_debug("%s: aie=%d\n", __func__, enabled);
+       dev_dbg(dev, "%s: aie=%d\n", __func__, enabled);
 
        clk_enable(rtc_clk);
        tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
@@ -203,7 +203,7 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 
        rtc_tm->tm_year += 100;
 
-       pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
+       dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
                 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
                 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
 
@@ -218,7 +218,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
        void __iomem *base = s3c_rtc_base;
        int year = tm->tm_year - 100;
 
-       pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
+       dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
                 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
                 tm->tm_hour, tm->tm_min, tm->tm_sec);
 
@@ -259,7 +259,7 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
 
-       pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
+       dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
                 alm_en,
                 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
                 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
@@ -310,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        unsigned int alrm_en;
 
        clk_enable(rtc_clk);
-       pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
+       dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
                 alrm->enabled,
                 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
                 tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -333,7 +333,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
                writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
        }
 
-       pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
+       dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en);
 
        writeb(alrm_en, base + S3C2410_RTCALM);
 
@@ -459,7 +459,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
        int ret;
        int tmp;
 
-       pr_debug("%s: probe=%p\n", __func__, pdev);
+       dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev);
 
        /* find the IRQs */
 
@@ -475,7 +475,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                return s3c_rtc_alarmno;
        }
 
-       pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
+       dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
                 s3c_rtc_tickno, s3c_rtc_alarmno);
 
        /* get the memory region */
@@ -504,7 +504,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        s3c_rtc_enable(pdev, 1);
 
-       pr_debug("s3c2410_rtc: RTCCON=%02x\n",
+       dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
                 readw(s3c_rtc_base + S3C2410_RTCCON));
 
        device_init_wakeup(&pdev->dev, 1);
index 50a5c4a..5ec5036 100644 (file)
@@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev)
        struct rtc_device *rtc = info->rtc;
        int ret;
 
-       ret = clk_prepare_enable(info->clk);
-       if (ret)
-               goto fail_clk;
        ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
        if (ret) {
                dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
@@ -130,7 +127,6 @@ static int sa1100_rtc_open(struct device *dev)
        free_irq(info->irq_1hz, dev);
  fail_ui:
        clk_disable_unprepare(info->clk);
- fail_clk:
        return ret;
 }
 
@@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev)
 
        free_irq(info->irq_alarm, dev);
        free_irq(info->irq_1hz, dev);
-       clk_disable_unprepare(info->clk);
 }
 
 static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
@@ -253,6 +248,9 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
        spin_lock_init(&info->lock);
        platform_set_drvdata(pdev, info);
 
+       ret = clk_prepare_enable(info->clk);
+       if (ret)
+               goto err_enable_clk;
        /*
         * According to the manual we should be able to let RTTR be zero
         * and then a default diviser for a 32.768KHz clock is used.
@@ -305,6 +303,8 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
 
        return 0;
 err_dev:
+       clk_disable_unprepare(info->clk);
+err_enable_clk:
        platform_set_drvdata(pdev, NULL);
        clk_put(info->clk);
 err_clk:
@@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 
        if (info) {
                rtc_device_unregister(info->rtc);
+               clk_disable_unprepare(info->clk);
                clk_put(info->clk);
                platform_set_drvdata(pdev, NULL);
                kfree(info);
@@ -349,12 +350,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = {
 };
 #endif
 
+#ifdef CONFIG_OF
 static struct of_device_id sa1100_rtc_dt_ids[] = {
        { .compatible = "mrvl,sa1100-rtc", },
        { .compatible = "mrvl,mmp-rtc", },
        {}
 };
 MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
+#endif
 
 static struct platform_driver sa1100_rtc_driver = {
        .probe          = sa1100_rtc_probe,
@@ -364,7 +367,7 @@ static struct platform_driver sa1100_rtc_driver = {
 #ifdef CONFIG_PM
                .pm     = &sa1100_rtc_pm_ops,
 #endif
-               .of_match_table = sa1100_rtc_dt_ids,
+               .of_match_table = of_match_ptr(sa1100_rtc_dt_ids),
        },
 };
 
index 40662e9..f7d9070 100644 (file)
@@ -338,7 +338,7 @@ static struct platform_driver snvs_rtc_driver = {
                .name   = "snvs_rtc",
                .owner  = THIS_MODULE,
                .pm     = &snvs_rtc_pm_ops,
-               .of_match_table = snvs_dt_ids,
+               .of_match_table = of_match_ptr(snvs_dt_ids),
        },
        .probe          = snvs_rtc_probe,
        .remove         = snvs_rtc_remove,
index 739ef55..b2a8ed9 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
+#include <linux/of.h>
 
 #include <mach/common.h>
 
@@ -280,7 +281,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {
        .driver         = {
                .name   = "stmp3xxx-rtc",
                .owner  = THIS_MODULE,
-               .of_match_table = rtc_dt_ids,
+               .of_match_table = of_match_ptr(rtc_dt_ids),
        },
 };
 
index 5b22610..59b5c2d 100644 (file)
@@ -3,6 +3,8 @@
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -26,10 +28,10 @@ retry:
                        udelay(100);
                        goto retry;
                }
-               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+               pr_warn("tod_get() timed out.\n");
                return 0;
        }
-       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+       pr_warn("tod_get() not supported.\n");
        return 0;
 }
 
@@ -53,10 +55,10 @@ retry:
                        udelay(100);
                        goto retry;
                }
-               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+               pr_warn("tod_set() timed out.\n");
                return -EAGAIN;
        }
-       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+       pr_warn("tod_set() not supported.\n");
        return -EOPNOTSUPP;
 }
 
index 70f61b8..aab4e8c 100644 (file)
@@ -282,7 +282,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
                goto fail_rtc_register;
        }
 
-       ret = request_threaded_irq(rtc->irq, NULL, tps6586x_rtc_irq,
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                               tps6586x_rtc_irq,
                                IRQF_ONESHOT | IRQF_EARLY_RESUME,
                                dev_name(&pdev->dev), rtc);
        if (ret < 0) {
@@ -311,7 +312,6 @@ static int tps6586x_rtc_remove(struct platform_device *pdev)
        tps6586x_update(tps_dev, RTC_CTRL, 0,
                RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
        rtc_device_unregister(rtc->rtc);
-       free_irq(rtc->irq, rtc);
        return 0;
 }
 
index e5fef14..8bd8115 100644 (file)
 #include <linux/rtc.h>
 #include <linux/bcd.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/tps65910.h>
 
 struct tps65910_rtc {
        struct rtc_device       *rtc;
-       /* To store the list of enabled interrupts */
-       u32 irqstat;
+       int irq;
 };
 
 /* Total number of RTC registers needed to set time*/
@@ -267,13 +267,14 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
-               tps65910_rtc_interrupt, IRQF_TRIGGER_LOW,
+               tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME,
                dev_name(&pdev->dev), &pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "IRQ is not free.\n");
                return ret;
        }
-       device_init_wakeup(&pdev->dev, 1);
+       tps_rtc->irq = irq;
+       device_set_wakeup_capable(&pdev->dev, 1);
 
        tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
                &tps65910_rtc_ops, THIS_MODULE);
@@ -304,49 +305,36 @@ static int tps65910_rtc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-
 static int tps65910_rtc_suspend(struct device *dev)
 {
-       struct tps65910 *tps = dev_get_drvdata(dev->parent);
-       u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM;
-       int ret;
-
-       /* Store current list of enabled interrupts*/
-       ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS,
-               &tps->rtc->irqstat);
-       if (ret < 0)
-               return ret;
+       struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
 
-       /* Enable RTC ALARM interrupt only */
-       return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm);
+       if (device_may_wakeup(dev))
+               enable_irq_wake(tps_rtc->irq);
+       return 0;
 }
 
 static int tps65910_rtc_resume(struct device *dev)
 {
-       struct tps65910 *tps = dev_get_drvdata(dev->parent);
+       struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev);
 
-       /* Restore list of enabled interrupts before suspend */
-       return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS,
-               tps->rtc->irqstat);
+       if (device_may_wakeup(dev))
+               disable_irq_wake(tps_rtc->irq);
+       return 0;
 }
+#endif
 
 static const struct dev_pm_ops tps65910_rtc_pm_ops = {
-       .suspend        = tps65910_rtc_suspend,
-       .resume         = tps65910_rtc_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume)
 };
 
-#define DEV_PM_OPS     (&tps65910_rtc_pm_ops)
-#else
-#define DEV_PM_OPS     NULL
-#endif
-
 static struct platform_driver tps65910_rtc_driver = {
        .probe          = tps65910_rtc_probe,
        .remove         = tps65910_rtc_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "tps65910-rtc",
-               .pm     = DEV_PM_OPS,
+               .pm     = &tps65910_rtc_pm_ops,
        },
 };
 
diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c
new file mode 100644 (file)
index 0000000..9aaf8aa
--- /dev/null
@@ -0,0 +1,349 @@
+/*
+ * rtc-tps80031.c -- TI TPS80031/TPS80032 RTC driver
+ *
+ * RTC driver for TI TPS80031/TPS80032 Fully Integrated
+ * Power Management with Power Path and Battery Charger
+ *
+ * Copyright (c) 2012, NVIDIA Corporation.
+ *
+ * Author: Laxman Dewangan <ldewangan@nvidia.com>
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; 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/bcd.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/tps80031.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+
+#define ENABLE_ALARM_INT                       0x08
+#define ALARM_INT_STATUS                       0x40
+
+/**
+ * Setting bit to 1 in STOP_RTC will run the RTC and
+ * setting this bit to 0 will freeze RTC.
+ */
+#define STOP_RTC                               0x1
+
+/* Power on reset Values of RTC registers */
+#define TPS80031_RTC_POR_YEAR                  0
+#define TPS80031_RTC_POR_MONTH                 1
+#define TPS80031_RTC_POR_DAY                   1
+
+/* Numbers of registers for time and alarms */
+#define TPS80031_RTC_TIME_NUM_REGS             7
+#define TPS80031_RTC_ALARM_NUM_REGS            6
+
+/**
+ * PMU RTC have only 2 nibbles to store year information, so using an
+ * offset of 100 to set the base year as 2000 for our driver.
+ */
+#define RTC_YEAR_OFFSET 100
+
+struct tps80031_rtc {
+       struct rtc_device       *rtc;
+       int                     irq;
+};
+
+static int tps80031_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       u8 buff[TPS80031_RTC_TIME_NUM_REGS];
+       int ret;
+
+       ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
+                       TPS80031_SECONDS_REG, TPS80031_RTC_TIME_NUM_REGS, buff);
+       if (ret < 0) {
+               dev_err(dev, "reading RTC_SECONDS_REG failed, err = %d\n", ret);
+               return ret;
+       }
+
+       tm->tm_sec = bcd2bin(buff[0]);
+       tm->tm_min = bcd2bin(buff[1]);
+       tm->tm_hour = bcd2bin(buff[2]);
+       tm->tm_mday = bcd2bin(buff[3]);
+       tm->tm_mon = bcd2bin(buff[4]) - 1;
+       tm->tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
+       tm->tm_wday = bcd2bin(buff[6]);
+       return 0;
+}
+
+static int tps80031_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       u8 buff[7];
+       int ret;
+
+       buff[0] = bin2bcd(tm->tm_sec);
+       buff[1] = bin2bcd(tm->tm_min);
+       buff[2] = bin2bcd(tm->tm_hour);
+       buff[3] = bin2bcd(tm->tm_mday);
+       buff[4] = bin2bcd(tm->tm_mon + 1);
+       buff[5] = bin2bcd(tm->tm_year % RTC_YEAR_OFFSET);
+       buff[6] = bin2bcd(tm->tm_wday);
+
+       /* Stop RTC while updating the RTC time registers */
+       ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
+                               TPS80031_RTC_CTRL_REG, STOP_RTC);
+       if (ret < 0) {
+               dev_err(dev->parent, "Stop RTC failed, err = %d\n", ret);
+               return ret;
+       }
+
+       ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
+                       TPS80031_SECONDS_REG,
+                       TPS80031_RTC_TIME_NUM_REGS, buff);
+       if (ret < 0) {
+               dev_err(dev, "writing RTC_SECONDS_REG failed, err %d\n", ret);
+               return ret;
+       }
+
+       ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
+                               TPS80031_RTC_CTRL_REG, STOP_RTC);
+       if (ret < 0)
+               dev_err(dev->parent, "Start RTC failed, err = %d\n", ret);
+       return ret;
+}
+
+static int tps80031_rtc_alarm_irq_enable(struct device *dev,
+                                        unsigned int enable)
+{
+       int ret;
+
+       if (enable)
+               ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
+                               TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
+       else
+               ret = tps80031_clr_bits(dev->parent, TPS80031_SLAVE_ID1,
+                               TPS80031_RTC_INTERRUPTS_REG, ENABLE_ALARM_INT);
+       if (ret < 0) {
+               dev_err(dev, "Update on RTC_INT failed, err = %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int tps80031_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       u8 buff[TPS80031_RTC_ALARM_NUM_REGS];
+       int ret;
+
+       buff[0] = bin2bcd(alrm->time.tm_sec);
+       buff[1] = bin2bcd(alrm->time.tm_min);
+       buff[2] = bin2bcd(alrm->time.tm_hour);
+       buff[3] = bin2bcd(alrm->time.tm_mday);
+       buff[4] = bin2bcd(alrm->time.tm_mon + 1);
+       buff[5] = bin2bcd(alrm->time.tm_year % RTC_YEAR_OFFSET);
+       ret = tps80031_writes(dev->parent, TPS80031_SLAVE_ID1,
+                       TPS80031_ALARM_SECONDS_REG,
+                       TPS80031_RTC_ALARM_NUM_REGS, buff);
+       if (ret < 0) {
+               dev_err(dev, "Writing RTC_ALARM failed, err %d\n", ret);
+               return ret;
+       }
+       return tps80031_rtc_alarm_irq_enable(dev, alrm->enabled);
+}
+
+static int tps80031_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       u8 buff[6];
+       int ret;
+
+       ret = tps80031_reads(dev->parent, TPS80031_SLAVE_ID1,
+                       TPS80031_ALARM_SECONDS_REG,
+                       TPS80031_RTC_ALARM_NUM_REGS, buff);
+       if (ret < 0) {
+               dev_err(dev->parent,
+                       "reading RTC_ALARM failed, err = %d\n", ret);
+               return ret;
+       }
+
+       alrm->time.tm_sec = bcd2bin(buff[0]);
+       alrm->time.tm_min = bcd2bin(buff[1]);
+       alrm->time.tm_hour = bcd2bin(buff[2]);
+       alrm->time.tm_mday = bcd2bin(buff[3]);
+       alrm->time.tm_mon = bcd2bin(buff[4]) - 1;
+       alrm->time.tm_year = bcd2bin(buff[5]) + RTC_YEAR_OFFSET;
+       return 0;
+}
+
+static int clear_alarm_int_status(struct device *dev, struct tps80031_rtc *rtc)
+{
+       int ret;
+       u8 buf;
+
+       /**
+        * As per datasheet, A dummy read of this  RTC_STATUS_REG register
+        * is necessary before each I2C read in order to update the status
+        * register value.
+        */
+       ret = tps80031_read(dev->parent, TPS80031_SLAVE_ID1,
+                               TPS80031_RTC_STATUS_REG, &buf);
+       if (ret < 0) {
+               dev_err(dev, "reading RTC_STATUS failed. err = %d\n", ret);
+               return ret;
+       }
+
+       /* clear Alarm status bits.*/
+       ret = tps80031_set_bits(dev->parent, TPS80031_SLAVE_ID1,
+                       TPS80031_RTC_STATUS_REG, ALARM_INT_STATUS);
+       if (ret < 0) {
+               dev_err(dev, "clear Alarm INT failed, err = %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static irqreturn_t tps80031_rtc_irq(int irq, void *data)
+{
+       struct device *dev = data;
+       struct tps80031_rtc *rtc = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clear_alarm_int_status(dev, rtc);
+       if (ret < 0)
+               return ret;
+
+       rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+       return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops tps80031_rtc_ops = {
+       .read_time = tps80031_rtc_read_time,
+       .set_time = tps80031_rtc_set_time,
+       .set_alarm = tps80031_rtc_set_alarm,
+       .read_alarm = tps80031_rtc_read_alarm,
+       .alarm_irq_enable = tps80031_rtc_alarm_irq_enable,
+};
+
+static int tps80031_rtc_probe(struct platform_device *pdev)
+{
+       struct tps80031_rtc *rtc;
+       struct rtc_time tm;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->irq = platform_get_irq(pdev, 0);
+       platform_set_drvdata(pdev, rtc);
+
+       /* Start RTC */
+       ret = tps80031_set_bits(pdev->dev.parent, TPS80031_SLAVE_ID1,
+                       TPS80031_RTC_CTRL_REG, STOP_RTC);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to start RTC. err = %d\n", ret);
+               return ret;
+       }
+
+       /* If RTC have POR values, set time 01:01:2000 */
+       tps80031_rtc_read_time(&pdev->dev, &tm);
+       if ((tm.tm_year == RTC_YEAR_OFFSET + TPS80031_RTC_POR_YEAR) &&
+               (tm.tm_mon == (TPS80031_RTC_POR_MONTH - 1)) &&
+               (tm.tm_mday == TPS80031_RTC_POR_DAY)) {
+               tm.tm_year = 2000;
+               tm.tm_mday = 1;
+               tm.tm_mon = 1;
+               ret = tps80031_rtc_set_time(&pdev->dev, &tm);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "RTC set time failed, err = %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Clear alarm intretupt status if it is there */
+       ret = clear_alarm_int_status(&pdev->dev, rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Clear alarm int failed, err = %d\n", ret);
+               return ret;
+       }
+
+       rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+                              &tps80031_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc)) {
+               ret = PTR_ERR(rtc->rtc);
+               dev_err(&pdev->dev, "RTC registration failed, err %d\n", ret);
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                       tps80031_rtc_irq,
+                       IRQF_ONESHOT | IRQF_EARLY_RESUME,
+                       dev_name(&pdev->dev), rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request IRQ:%d failed, err = %d\n",
+                        rtc->irq, ret);
+               rtc_device_unregister(rtc->rtc);
+               return ret;
+       }
+       device_set_wakeup_capable(&pdev->dev, 1);
+       return 0;
+}
+
+static int tps80031_rtc_remove(struct platform_device *pdev)
+{
+       struct tps80031_rtc *rtc = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(rtc->rtc);
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tps80031_rtc_suspend(struct device *dev)
+{
+       struct tps80031_rtc *rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(rtc->irq);
+       return 0;
+}
+
+static int tps80031_rtc_resume(struct device *dev)
+{
+       struct tps80031_rtc *rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(rtc->irq);
+       return 0;
+};
+#endif
+
+static const struct dev_pm_ops tps80031_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(tps80031_rtc_suspend, tps80031_rtc_resume)
+};
+
+static struct platform_driver tps80031_rtc_driver = {
+       .driver = {
+               .name   = "tps80031-rtc",
+               .owner  = THIS_MODULE,
+               .pm     = &tps80031_pm_ops,
+       },
+       .probe  = tps80031_rtc_probe,
+       .remove = tps80031_rtc_remove,
+};
+
+module_platform_driver(tps80031_rtc_driver);
+
+MODULE_ALIAS("platform:tps80031-rtc");
+MODULE_DESCRIPTION("TI TPS80031/TPS80032 RTC driver");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index ccd4ad3..8bc6c80 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/bcd.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 
 #include <linux/i2c/twl.h>
 
@@ -588,11 +589,14 @@ static int twl_rtc_resume(struct platform_device *pdev)
 #define twl_rtc_resume  NULL
 #endif
 
+#ifdef CONFIG_OF
 static const struct of_device_id twl_rtc_of_match[] = {
        {.compatible = "ti,twl4030-rtc", },
        { },
 };
 MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
+#endif
+
 MODULE_ALIAS("platform:twl_rtc");
 
 static struct platform_driver twl4030rtc_driver = {
@@ -604,7 +608,7 @@ static struct platform_driver twl4030rtc_driver = {
        .driver         = {
                .owner          = THIS_MODULE,
                .name           = "twl_rtc",
-               .of_match_table = twl_rtc_of_match,
+               .of_match_table = of_match_ptr(twl_rtc_of_match),
        },
 };
 
index 6c3774c..f91be04 100644 (file)
@@ -352,7 +352,7 @@ static int rtc_probe(struct platform_device *pdev)
        disable_irq(aie_irq);
        disable_irq(pie_irq);
 
-       printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
+       dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n");
 
        return 0;
 
index 2730533..a000bc0 100644 (file)
@@ -231,20 +231,21 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
-                                            resource_size(vt8500_rtc->res),
-                                            "vt8500-rtc");
+       vt8500_rtc->res = devm_request_mem_region(&pdev->dev,
+                                       vt8500_rtc->res->start,
+                                       resource_size(vt8500_rtc->res),
+                                       "vt8500-rtc");
        if (vt8500_rtc->res == NULL) {
                dev_err(&pdev->dev, "failed to request I/O memory\n");
                return -EBUSY;
        }
 
-       vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
+       vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start,
                                      resource_size(vt8500_rtc->res));
        if (!vt8500_rtc->regbase) {
                dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
                ret = -EBUSY;
-               goto err_release;
+               goto err_return;
        }
 
        /* Enable RTC and set it to 24-hour mode */
@@ -257,11 +258,11 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
                ret = PTR_ERR(vt8500_rtc->rtc);
                dev_err(&pdev->dev,
                        "Failed to register RTC device -> %d\n", ret);
-               goto err_unmap;
+               goto err_return;
        }
 
-       ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
-                         "rtc alarm", vt8500_rtc);
+       ret = devm_request_irq(&pdev->dev, vt8500_rtc->irq_alarm,
+                               vt8500_rtc_irq, 0, "rtc alarm", vt8500_rtc);
        if (ret < 0) {
                dev_err(&pdev->dev, "can't get irq %i, err %d\n",
                        vt8500_rtc->irq_alarm, ret);
@@ -272,11 +273,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
 
 err_unreg:
        rtc_device_unregister(vt8500_rtc->rtc);
-err_unmap:
-       iounmap(vt8500_rtc->regbase);
-err_release:
-       release_mem_region(vt8500_rtc->res->start,
-                          resource_size(vt8500_rtc->res));
+err_return:
        return ret;
 }
 
@@ -284,15 +281,10 @@ static int vt8500_rtc_remove(struct platform_device *pdev)
 {
        struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
 
-       free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
-
        rtc_device_unregister(vt8500_rtc->rtc);
 
        /* Disable alarm matching */
        writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
-       iounmap(vt8500_rtc->regbase);
-       release_mem_region(vt8500_rtc->res->start,
-                          resource_size(vt8500_rtc->res));
 
        platform_set_drvdata(pdev, NULL);
 
index 1b0affb..2f0ac7b 100644 (file)
@@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
                goto err;
        }
 
-       ret = request_threaded_irq(alm_irq, NULL, wm831x_alm_irq,
-                                  IRQF_TRIGGER_RISING, "RTC alarm",
-                                  wm831x_rtc);
+       ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
+                               wm831x_alm_irq,
+                               IRQF_TRIGGER_RISING, "RTC alarm",
+                               wm831x_rtc);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
                        alm_irq, ret);
@@ -462,9 +463,7 @@ err:
 static int wm831x_rtc_remove(struct platform_device *pdev)
 {
        struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(pdev);
-       int alm_irq = platform_get_irq_byname(pdev, "ALM");
 
-       free_irq(alm_irq, wm831x_rtc);
        rtc_device_unregister(wm831x_rtc->rtc);
 
        return 0;
index e4e1765..80cbd21 100644 (file)
@@ -364,7 +364,7 @@ config FB_SA1100
          Y here.
 
 config FB_IMX
-       tristate "Freescale i.MX LCD support"
+       tristate "Freescale i.MX1/21/25/27 LCD support"
        depends on FB && IMX_HAVE_PLATFORM_IMX_FB
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -2025,7 +2025,8 @@ config FB_TMIO_ACCELL
 
 config FB_S3C
        tristate "Samsung S3C framebuffer support"
-       depends on FB && (S3C_DEV_FB || S5P_DEV_FIMD0)
+       depends on FB && (CPU_S3C2416 || ARCH_S3C64XX || ARCH_S5P64X0 || \
+               ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS)
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
@@ -2183,6 +2184,15 @@ config FB_XILINX
          framebuffer. ML300 carries a 640*480 LCD display on the board,
          ML403 uses a standard DB15 VGA connector.
 
+config FB_GOLDFISH
+       tristate "Goldfish Framebuffer"
+       depends on FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       ---help---
+         Framebuffer driver for Goldfish Virtual Platform
+
 config FB_COBALT
        tristate "Cobalt server LCD frame buffer support"
        depends on FB && (MIPS_COBALT || MIPS_SEAD3)
@@ -2422,6 +2432,7 @@ config FB_PUV3_UNIGFX
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 source "drivers/video/exynos/Kconfig"
+source "drivers/video/mmp/Kconfig"
 source "drivers/video/backlight/Kconfig"
 
 if VT
index 768a137..0577f83 100644 (file)
@@ -98,6 +98,7 @@ obj-$(CONFIG_FB_ATMEL)                  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)         += amba-clcd.o
+obj-$(CONFIG_FB_GOLDFISH)         += goldfishfb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
 obj-$(CONFIG_FB_GBE)              += gbefb.o
 obj-$(CONFIG_FB_CIRRUS)                  += cirrusfb.o
@@ -105,6 +106,7 @@ obj-$(CONFIG_FB_ASILIANT)     += asiliantfb.o
 obj-$(CONFIG_FB_PXA)             += pxafb.o
 obj-$(CONFIG_FB_PXA168)                  += pxa168fb.o
 obj-$(CONFIG_PXA3XX_GCU)         += pxa3xx-gcu.o
+obj-$(CONFIG_MMP_DISP)           += mmp/
 obj-$(CONFIG_FB_W100)            += w100fb.o
 obj-$(CONFIG_FB_TMIO)            += tmiofb.o
 obj-$(CONFIG_FB_AU1100)                  += au1100fb.o
index c072ed9..2cd6350 100644 (file)
@@ -165,8 +165,10 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev,
                                    struct pm860x_backlight_data *data,
                                    char *name)
 {
-       struct device_node *nproot = pdev->dev.parent->of_node, *np;
+       struct device_node *nproot, *np;
        int iset = 0;
+
+       nproot = of_node_get(pdev->dev.parent->of_node);
        if (!nproot)
                return -ENODEV;
        nproot = of_find_node_by_name(nproot, "backlights");
@@ -184,6 +186,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev,
                        break;
                }
        }
+       of_node_put(nproot);
        return 0;
 }
 #else
index 765a945..be27b55 100644 (file)
@@ -126,6 +126,21 @@ config LCD_AMS369FG06
          If you have an AMS369FG06 AMOLED Panel, say Y to enable its
          LCD control driver.
 
+config LCD_LMS501KF03
+       tristate "LMS501KF03 LCD Driver"
+       depends on SPI
+       default n
+       help
+         If you have an LMS501KF03 LCD Panel, say Y to enable its
+         LCD control driver.
+
+config LCD_HX8357
+       tristate "Himax HX-8357 LCD Driver"
+       depends on SPI
+       help
+         If you have a HX-8357 LCD panel, say Y to enable its LCD control
+         driver.
+
 endif # LCD_CLASS_DEVICE
 
 #
@@ -366,7 +381,7 @@ config BACKLIGHT_LP855X
        tristate "Backlight driver for TI LP855X"
        depends on BACKLIGHT_CLASS_DEVICE && I2C
        help
-         This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556
+         This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557
          backlight driver.
 
 config BACKLIGHT_OT200
@@ -390,6 +405,13 @@ config BACKLIGHT_TPS65217
          If you have a Texas Instruments TPS65217 say Y to enable the
          backlight driver.
 
+config BACKLIGHT_AS3711
+       tristate "AS3711 Backlight"
+       depends on BACKLIGHT_CLASS_DEVICE && MFD_AS3711
+       help
+         If you have an Austrian Microsystems AS3711 say Y to enable the
+         backlight driver.
+
 endif # BACKLIGHT_CLASS_DEVICE
 
 endif # BACKLIGHT_LCD_SUPPORT
index e7ce729..4606c21 100644 (file)
@@ -1,47 +1,50 @@
 # Backlight & LCD drivers
 
-obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
-obj-$(CONFIG_LCD_CORGI)                   += corgi_lcd.o
-obj-$(CONFIG_LCD_HP700)                   += jornada720_lcd.o
-obj-$(CONFIG_LCD_L4F00242T03)     += l4f00242t03.o
-obj-$(CONFIG_LCD_LMS283GF05)      += lms283gf05.o
-obj-$(CONFIG_LCD_LTV350QV)        += ltv350qv.o
-obj-$(CONFIG_LCD_ILI9320)         += ili9320.o
-obj-$(CONFIG_LCD_PLATFORM)        += platform_lcd.o
-obj-$(CONFIG_LCD_VGG2432A4)       += vgg2432a4.o
-obj-$(CONFIG_LCD_TDO24M)          += tdo24m.o
-obj-$(CONFIG_LCD_TOSA)            += tosa_lcd.o
-obj-$(CONFIG_LCD_S6E63M0)      += s6e63m0.o
-obj-$(CONFIG_LCD_LD9040)       += ld9040.o
-obj-$(CONFIG_LCD_AMS369FG06)   += ams369fg06.o
+obj-$(CONFIG_LCD_AMS369FG06)           += ams369fg06.o
+obj-$(CONFIG_LCD_CLASS_DEVICE)         += lcd.o
+obj-$(CONFIG_LCD_CORGI)                        += corgi_lcd.o
+obj-$(CONFIG_LCD_HP700)                        += jornada720_lcd.o
+obj-$(CONFIG_LCD_HX8357)               += hx8357.o
+obj-$(CONFIG_LCD_ILI9320)              += ili9320.o
+obj-$(CONFIG_LCD_L4F00242T03)          += l4f00242t03.o
+obj-$(CONFIG_LCD_LD9040)               += ld9040.o
+obj-$(CONFIG_LCD_LMS283GF05)           += lms283gf05.o
+obj-$(CONFIG_LCD_LMS501KF03)           += lms501kf03.o
+obj-$(CONFIG_LCD_LTV350QV)             += ltv350qv.o
+obj-$(CONFIG_LCD_PLATFORM)             += platform_lcd.o
+obj-$(CONFIG_LCD_S6E63M0)              += s6e63m0.o
+obj-$(CONFIG_LCD_TDO24M)               += tdo24m.o
+obj-$(CONFIG_LCD_TOSA)                 += tosa_lcd.o
+obj-$(CONFIG_LCD_VGG2432A4)            += vgg2432a4.o
 
-obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
-obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
-obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o
-obj-$(CONFIG_BACKLIGHT_GENERIC)        += generic_bl.o
-obj-$(CONFIG_BACKLIGHT_HP700)  += jornada720_bl.o
-obj-$(CONFIG_BACKLIGHT_HP680)  += hp680_bl.o
-obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
-obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
-obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o
-obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
-obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
-obj-$(CONFIG_BACKLIGHT_OMAP1)  += omap1_bl.o
-obj-$(CONFIG_BACKLIGHT_PANDORA)        += pandora_bl.o
-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_DA9052) += da9052_bl.o
-obj-$(CONFIG_BACKLIGHT_MAX8925)        += max8925_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
-obj-$(CONFIG_BACKLIGHT_ADP5520)        += adp5520_bl.o
-obj-$(CONFIG_BACKLIGHT_ADP8860)        += adp8860_bl.o
-obj-$(CONFIG_BACKLIGHT_ADP8870)        += adp8870_bl.o
-obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o
+obj-$(CONFIG_BACKLIGHT_88PM860X)       += 88pm860x_bl.o
+obj-$(CONFIG_BACKLIGHT_AAT2870)                += aat2870_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP5520)                += adp5520_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP8860)                += adp8860_bl.o
+obj-$(CONFIG_BACKLIGHT_ADP8870)                += adp8870_bl.o
+obj-$(CONFIG_BACKLIGHT_APPLE)          += apple_bl.o
+obj-$(CONFIG_BACKLIGHT_AS3711)         += as3711_bl.o
+obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)      += atmel-pwm-bl.o
+obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH)  += cr_bllcd.o
+obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE)   += backlight.o
+obj-$(CONFIG_BACKLIGHT_DA903X)         += da903x_bl.o
+obj-$(CONFIG_BACKLIGHT_DA9052)         += da9052_bl.o
+obj-$(CONFIG_BACKLIGHT_EP93XX)         += ep93xx_bl.o
+obj-$(CONFIG_BACKLIGHT_GENERIC)                += generic_bl.o
+obj-$(CONFIG_BACKLIGHT_HP680)          += hp680_bl.o
+obj-$(CONFIG_BACKLIGHT_HP700)          += jornada720_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3533)         += lm3533_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3630)         += lm3630_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3639)         += lm3639_bl.o
+obj-$(CONFIG_BACKLIGHT_LOCOMO)         += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LP855X)         += lp855x_bl.o
+obj-$(CONFIG_BACKLIGHT_MAX8925)                += max8925_bl.o
+obj-$(CONFIG_BACKLIGHT_OMAP1)          += omap1_bl.o
+obj-$(CONFIG_BACKLIGHT_OT200)          += ot200_bl.o
+obj-$(CONFIG_BACKLIGHT_PANDORA)                += pandora_bl.o
 obj-$(CONFIG_BACKLIGHT_PCF50633)       += pcf50633-backlight.o
-obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o
-obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o
-obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
+obj-$(CONFIG_BACKLIGHT_PWM)            += pwm_bl.o
+obj-$(CONFIG_BACKLIGHT_SAHARA)         += kb3886_bl.o
+obj-$(CONFIG_BACKLIGHT_TOSA)           += tosa_bl.o
+obj-$(CONFIG_BACKLIGHT_TPS65217)       += tps65217_bl.o
+obj-$(CONFIG_BACKLIGHT_WM831X)         += wm831x_bl.o
index 7ff7522..c6fc668 100644 (file)
@@ -74,7 +74,7 @@ static int aat2870_bl_get_brightness(struct backlight_device *bd)
 
 static int aat2870_bl_update_status(struct backlight_device *bd)
 {
-       struct aat2870_bl_driver_data *aat2870_bl = dev_get_drvdata(&bd->dev);
+       struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd);
        struct aat2870_data *aat2870 =
                        dev_get_drvdata(aat2870_bl->pdev->dev.parent);
        int brightness = bd->props.brightness;
index 6bb72c0..a77c9ca 100644 (file)
@@ -783,7 +783,7 @@ static int adp8860_i2c_suspend(struct i2c_client *client, pm_message_t message)
 
 static int adp8860_i2c_resume(struct i2c_client *client)
 {
-       adp8860_set_bits(client, ADP8860_MDCR, NSTBY);
+       adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN);
 
        return 0;
 }
index 63c882b..712c25a 100644 (file)
@@ -957,7 +957,7 @@ static int adp8870_i2c_suspend(struct i2c_client *client, pm_message_t message)
 
 static int adp8870_i2c_resume(struct i2c_client *client)
 {
-       adp8870_set_bits(client, ADP8870_MDCR, NSTBY);
+       adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN);
 
        return 0;
 }
index f57e190..d29e494 100644 (file)
  * 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/module.h>
-#include <linux/fb.h>
+#include <linux/backlight.h>
 #include <linux/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
 #include <linux/lcd.h>
-#include <linux/backlight.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
 
 #define SLEEPMSEC              0x1000
 #define ENDDEF                 0x2000
@@ -210,8 +201,9 @@ static int ams369fg06_panel_send_sequence(struct ams369fg06 *lcd,
                        ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]);
                        if (ret)
                                break;
-               } else
-                       mdelay(wbuf[i+1]);
+               } else {
+                       msleep(wbuf[i+1]);
+               }
                i += 2;
        }
 
@@ -313,41 +305,32 @@ static int ams369fg06_ldi_disable(struct ams369fg06 *lcd)
 
 static int ams369fg06_power_is_on(int power)
 {
-       return ((power) <= FB_BLANK_NORMAL);
+       return power <= FB_BLANK_NORMAL;
 }
 
 static int ams369fg06_power_on(struct ams369fg06 *lcd)
 {
        int ret = 0;
-       struct lcd_platform_data *pd = NULL;
-       struct backlight_device *bd = NULL;
+       struct lcd_platform_data *pd;
+       struct backlight_device *bd;
 
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL.\n");
-               return -EFAULT;
-       }
-
        bd = lcd->bd;
-       if (!bd) {
-               dev_err(lcd->dev, "backlight device is NULL.\n");
-               return -EFAULT;
-       }
 
        if (!pd->power_on) {
                dev_err(lcd->dev, "power_on is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        } else {
                pd->power_on(lcd->ld, 1);
-               mdelay(pd->power_on_delay);
+               msleep(pd->power_on_delay);
        }
 
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        } else {
                pd->reset(lcd->ld);
-               mdelay(pd->reset_delay);
+               msleep(pd->reset_delay);
        }
 
        ret = ams369fg06_ldi_init(lcd);
@@ -374,14 +357,10 @@ static int ams369fg06_power_on(struct ams369fg06 *lcd)
 
 static int ams369fg06_power_off(struct ams369fg06 *lcd)
 {
-       int ret = 0;
-       struct lcd_platform_data *pd = NULL;
+       int ret;
+       struct lcd_platform_data *pd;
 
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL\n");
-               return -EFAULT;
-       }
 
        ret = ams369fg06_ldi_disable(lcd);
        if (ret) {
@@ -389,13 +368,9 @@ static int ams369fg06_power_off(struct ams369fg06 *lcd)
                return -EIO;
        }
 
-       mdelay(pd->power_off_delay);
+       msleep(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);
+       pd->power_on(lcd->ld, 0);
 
        return 0;
 }
@@ -446,7 +421,7 @@ static int ams369fg06_set_brightness(struct backlight_device *bd)
 {
        int ret = 0;
        int brightness = bd->props.brightness;
-       struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev);
+       struct ams369fg06 *lcd = bl_get_data(bd);
 
        if (brightness < MIN_BRIGHTNESS ||
                brightness > bd->props.max_brightness) {
@@ -501,7 +476,7 @@ static int ams369fg06_probe(struct spi_device *spi)
        lcd->lcd_pd = spi->dev.platform_data;
        if (!lcd->lcd_pd) {
                dev_err(&spi->dev, "platform data is NULL\n");
-               return -EFAULT;
+               return -EINVAL;
        }
 
        ld = lcd_device_register("ams369fg06", &spi->dev, lcd,
@@ -534,10 +509,11 @@ static int ams369fg06_probe(struct spi_device *spi)
                lcd->power = FB_BLANK_POWERDOWN;
 
                ams369fg06_power(lcd, FB_BLANK_UNBLANK);
-       } else
+       } else {
                lcd->power = FB_BLANK_UNBLANK;
+       }
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
 
        dev_info(&spi->dev, "ams369fg06 panel driver has been probed.\n");
 
@@ -550,7 +526,7 @@ out_lcd_unregister:
 
 static int ams369fg06_remove(struct spi_device *spi)
 {
-       struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+       struct ams369fg06 *lcd = spi_get_drvdata(spi);
 
        ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
        backlight_device_unregister(lcd->bd);
@@ -560,44 +536,26 @@ static int ams369fg06_remove(struct spi_device *spi)
 }
 
 #if defined(CONFIG_PM)
-static unsigned int before_power;
-
 static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
 {
-       int ret = 0;
-       struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+       struct ams369fg06 *lcd = spi_get_drvdata(spi);
 
        dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 
-       before_power = lcd->power;
-
        /*
         * when lcd panel is suspend, lcd panel becomes off
         * regardless of status.
         */
-       ret = ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
-
-       return ret;
+       return ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
 }
 
 static int ams369fg06_resume(struct spi_device *spi)
 {
-       int ret = 0;
-       struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+       struct ams369fg06 *lcd = spi_get_drvdata(spi);
 
-       /*
-        * after suspended, if lcd panel status is FB_BLANK_UNBLANK
-        * (at that time, before_power is FB_BLANK_UNBLANK) then
-        * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
-        */
-       if (before_power == FB_BLANK_UNBLANK)
-               lcd->power = FB_BLANK_POWERDOWN;
-
-       dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+       lcd->power = FB_BLANK_POWERDOWN;
 
-       ret = ams369fg06_power(lcd, before_power);
-
-       return ret;
+       return ams369fg06_power(lcd, FB_BLANK_UNBLANK);
 }
 #else
 #define ams369fg06_suspend     NULL
@@ -606,7 +564,7 @@ static int ams369fg06_resume(struct spi_device *spi)
 
 static void ams369fg06_shutdown(struct spi_device *spi)
 {
-       struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev);
+       struct ams369fg06 *lcd = spi_get_drvdata(spi);
 
        ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
 }
diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c
new file mode 100644 (file)
index 0000000..41d52fe
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * AS3711 PMIC backlight driver, using DCDC Step Up Converters
+ *
+ * Copyright (C) 2012 Renesas Electronics Corporation
+ * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License as
+ * published by the Free Software Foundation
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/mfd/as3711.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+enum as3711_bl_type {
+       AS3711_BL_SU1,
+       AS3711_BL_SU2,
+};
+
+struct as3711_bl_data {
+       bool powered;
+       const char *fb_name;
+       struct device *fb_dev;
+       enum as3711_bl_type type;
+       int brightness;
+       struct backlight_device *bl;
+};
+
+struct as3711_bl_supply {
+       struct as3711_bl_data su1;
+       struct as3711_bl_data su2;
+       const struct as3711_bl_pdata *pdata;
+       struct as3711 *as3711;
+};
+
+static struct as3711_bl_supply *to_supply(struct as3711_bl_data *su)
+{
+       switch (su->type) {
+       case AS3711_BL_SU1:
+               return container_of(su, struct as3711_bl_supply, su1);
+       case AS3711_BL_SU2:
+               return container_of(su, struct as3711_bl_supply, su2);
+       }
+       return NULL;
+}
+
+static int as3711_set_brightness_auto_i(struct as3711_bl_data *data,
+                                       unsigned int brightness)
+{
+       struct as3711_bl_supply *supply = to_supply(data);
+       struct as3711 *as3711 = supply->as3711;
+       const struct as3711_bl_pdata *pdata = supply->pdata;
+       int ret = 0;
+
+       /* Only all equal current values are supported */
+       if (pdata->su2_auto_curr1)
+               ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE,
+                                  brightness);
+       if (!ret && pdata->su2_auto_curr2)
+               ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE,
+                                  brightness);
+       if (!ret && pdata->su2_auto_curr3)
+               ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE,
+                                  brightness);
+
+       return ret;
+}
+
+static int as3711_set_brightness_v(struct as3711 *as3711,
+                                  unsigned int brightness,
+                                  unsigned int reg)
+{
+       if (brightness > 31)
+               return -EINVAL;
+
+       return regmap_update_bits(as3711->regmap, reg, 0xf0,
+                                 brightness << 4);
+}
+
+static int as3711_bl_su2_reset(struct as3711_bl_supply *supply)
+{
+       struct as3711 *as3711 = supply->as3711;
+       int ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_5,
+                                    3, supply->pdata->su2_fbprot);
+       if (!ret)
+               ret = regmap_update_bits(as3711->regmap,
+                                        AS3711_STEPUP_CONTROL_2, 1, 0);
+       if (!ret)
+               ret = regmap_update_bits(as3711->regmap,
+                                        AS3711_STEPUP_CONTROL_2, 1, 1);
+       return ret;
+}
+
+/*
+ * Someone with less fragile or less expensive hardware could try to simplify
+ * the brightness adjustment procedure.
+ */
+static int as3711_bl_update_status(struct backlight_device *bl)
+{
+       struct as3711_bl_data *data = bl_get_data(bl);
+       struct as3711_bl_supply *supply = to_supply(data);
+       struct as3711 *as3711 = supply->as3711;
+       int brightness = bl->props.brightness;
+       int ret = 0;
+
+       dev_dbg(&bl->dev, "%s(): brightness %u, pwr %x, blank %x, state %x\n",
+               __func__, bl->props.brightness, bl->props.power,
+               bl->props.fb_blank, bl->props.state);
+
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.fb_blank != FB_BLANK_UNBLANK ||
+           bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
+               brightness = 0;
+
+       if (data->type == AS3711_BL_SU1) {
+               ret = as3711_set_brightness_v(as3711, brightness,
+                                             AS3711_STEPUP_CONTROL_1);
+       } else {
+               const struct as3711_bl_pdata *pdata = supply->pdata;
+
+               switch (pdata->su2_feedback) {
+               case AS3711_SU2_VOLTAGE:
+                       ret = as3711_set_brightness_v(as3711, brightness,
+                                                     AS3711_STEPUP_CONTROL_2);
+                       break;
+               case AS3711_SU2_CURR_AUTO:
+                       ret = as3711_set_brightness_auto_i(data, brightness / 4);
+                       if (ret < 0)
+                               return ret;
+                       if (brightness) {
+                               ret = as3711_bl_su2_reset(supply);
+                               if (ret < 0)
+                                       return ret;
+                               udelay(500);
+                               ret = as3711_set_brightness_auto_i(data, brightness);
+                       } else {
+                               ret = regmap_update_bits(as3711->regmap,
+                                               AS3711_STEPUP_CONTROL_2, 1, 0);
+                       }
+                       break;
+               /* Manual one current feedback pin below */
+               case AS3711_SU2_CURR1:
+                       ret = regmap_write(as3711->regmap, AS3711_CURR1_VALUE,
+                                          brightness);
+                       break;
+               case AS3711_SU2_CURR2:
+                       ret = regmap_write(as3711->regmap, AS3711_CURR2_VALUE,
+                                          brightness);
+                       break;
+               case AS3711_SU2_CURR3:
+                       ret = regmap_write(as3711->regmap, AS3711_CURR3_VALUE,
+                                          brightness);
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       }
+       if (!ret)
+               data->brightness = brightness;
+
+       return ret;
+}
+
+static int as3711_bl_get_brightness(struct backlight_device *bl)
+{
+       struct as3711_bl_data *data = bl_get_data(bl);
+
+       return data->brightness;
+}
+
+static const struct backlight_ops as3711_bl_ops = {
+       .update_status  = as3711_bl_update_status,
+       .get_brightness = as3711_bl_get_brightness,
+};
+
+static int as3711_bl_init_su2(struct as3711_bl_supply *supply)
+{
+       struct as3711 *as3711 = supply->as3711;
+       const struct as3711_bl_pdata *pdata = supply->pdata;
+       u8 ctl = 0;
+       int ret;
+
+       dev_dbg(as3711->dev, "%s(): use %u\n", __func__, pdata->su2_feedback);
+
+       /* Turn SU2 off */
+       ret = regmap_write(as3711->regmap, AS3711_STEPUP_CONTROL_2, 0);
+       if (ret < 0)
+               return ret;
+
+       switch (pdata->su2_feedback) {
+       case AS3711_SU2_VOLTAGE:
+               ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 0);
+               break;
+       case AS3711_SU2_CURR1:
+               ctl = 1;
+               ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 1);
+               break;
+       case AS3711_SU2_CURR2:
+               ctl = 4;
+               ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 2);
+               break;
+       case AS3711_SU2_CURR3:
+               ctl = 0x10;
+               ret = regmap_update_bits(as3711->regmap, AS3711_STEPUP_CONTROL_4, 3, 3);
+               break;
+       case AS3711_SU2_CURR_AUTO:
+               if (pdata->su2_auto_curr1)
+                       ctl = 2;
+               if (pdata->su2_auto_curr2)
+                       ctl |= 8;
+               if (pdata->su2_auto_curr3)
+                       ctl |= 0x20;
+               ret = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!ret)
+               ret = regmap_write(as3711->regmap, AS3711_CURR_CONTROL, ctl);
+
+       return ret;
+}
+
+static int as3711_bl_register(struct platform_device *pdev,
+                             unsigned int max_brightness, struct as3711_bl_data *su)
+{
+       struct backlight_properties props = {.type = BACKLIGHT_RAW,};
+       struct backlight_device *bl;
+
+       /* max tuning I = 31uA for voltage- and 38250uA for current-feedback */
+       props.max_brightness = max_brightness;
+
+       bl = backlight_device_register(su->type == AS3711_BL_SU1 ?
+                                      "as3711-su1" : "as3711-su2",
+                                      &pdev->dev, su,
+                                      &as3711_bl_ops, &props);
+       if (IS_ERR(bl)) {
+               dev_err(&pdev->dev, "failed to register backlight\n");
+               return PTR_ERR(bl);
+       }
+
+       bl->props.brightness = props.max_brightness;
+
+       backlight_update_status(bl);
+
+       su->bl = bl;
+
+       return 0;
+}
+
+static int as3711_backlight_probe(struct platform_device *pdev)
+{
+       struct as3711_bl_pdata *pdata = dev_get_platdata(&pdev->dev);
+       struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent);
+       struct as3711_bl_supply *supply;
+       struct as3711_bl_data *su;
+       unsigned int max_brightness;
+       int ret;
+
+       if (!pdata || (!pdata->su1_fb && !pdata->su2_fb)) {
+               dev_err(&pdev->dev, "No platform data, exiting...\n");
+               return -ENODEV;
+       }
+
+       /*
+        * Due to possible hardware damage I chose to block all modes,
+        * unsupported on my hardware. Anyone, wishing to use any of those modes
+        * will have to first review the code, then activate and test it.
+        */
+       if (pdata->su1_fb ||
+           pdata->su2_fbprot != AS3711_SU2_GPIO4 ||
+           pdata->su2_feedback != AS3711_SU2_CURR_AUTO) {
+               dev_warn(&pdev->dev,
+                        "Attention! An untested mode has been chosen!\n"
+                        "Please, review the code, enable, test, and report success:-)\n");
+               return -EINVAL;
+       }
+
+       supply = devm_kzalloc(&pdev->dev, sizeof(*supply), GFP_KERNEL);
+       if (!supply)
+               return -ENOMEM;
+
+       supply->as3711 = as3711;
+       supply->pdata = pdata;
+
+       if (pdata->su1_fb) {
+               su = &supply->su1;
+               su->fb_name = pdata->su1_fb;
+               su->type = AS3711_BL_SU1;
+
+               max_brightness = min(pdata->su1_max_uA, 31);
+               ret = as3711_bl_register(pdev, max_brightness, su);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (pdata->su2_fb) {
+               su = &supply->su2;
+               su->fb_name = pdata->su2_fb;
+               su->type = AS3711_BL_SU2;
+
+               switch (pdata->su2_fbprot) {
+               case AS3711_SU2_GPIO2:
+               case AS3711_SU2_GPIO3:
+               case AS3711_SU2_GPIO4:
+               case AS3711_SU2_LX_SD4:
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto esu2;
+               }
+
+               switch (pdata->su2_feedback) {
+               case AS3711_SU2_VOLTAGE:
+                       max_brightness = min(pdata->su2_max_uA, 31);
+                       break;
+               case AS3711_SU2_CURR1:
+               case AS3711_SU2_CURR2:
+               case AS3711_SU2_CURR3:
+               case AS3711_SU2_CURR_AUTO:
+                       max_brightness = min(pdata->su2_max_uA / 150, 255);
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto esu2;
+               }
+
+               ret = as3711_bl_init_su2(supply);
+               if (ret < 0)
+                       return ret;
+
+               ret = as3711_bl_register(pdev, max_brightness, su);
+               if (ret < 0)
+                       goto esu2;
+       }
+
+       platform_set_drvdata(pdev, supply);
+
+       return 0;
+
+esu2:
+       backlight_device_unregister(supply->su1.bl);
+       return ret;
+}
+
+static int as3711_backlight_remove(struct platform_device *pdev)
+{
+       struct as3711_bl_supply *supply = platform_get_drvdata(pdev);
+
+       backlight_device_unregister(supply->su1.bl);
+       backlight_device_unregister(supply->su2.bl);
+
+       return 0;
+}
+
+static struct platform_driver as3711_backlight_driver = {
+       .driver         = {
+               .name   = "as3711-backlight",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = as3711_backlight_probe,
+       .remove         = as3711_backlight_remove,
+};
+
+module_platform_driver(as3711_backlight_driver);
+
+MODULE_DESCRIPTION("Backlight Driver for AS3711 PMICs");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:as3711-backlight");
index e323fcb..aa782f3 100644 (file)
@@ -337,7 +337,7 @@ static void corgi_lcd_power_off(struct corgi_lcd *lcd)
 
 static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+       struct corgi_lcd *lcd = lcd_get_data(ld);
        int mode = CORGI_LCD_MODE_QVGA;
 
        if (m->xres == 640 || m->xres == 480)
@@ -364,7 +364,7 @@ static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m)
 
 static int corgi_lcd_set_power(struct lcd_device *ld, int power)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+       struct corgi_lcd *lcd = lcd_get_data(ld);
 
        if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
                corgi_lcd_power_on(lcd);
@@ -378,7 +378,7 @@ static int corgi_lcd_set_power(struct lcd_device *ld, int power)
 
 static int corgi_lcd_get_power(struct lcd_device *ld)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev);
+       struct corgi_lcd *lcd = lcd_get_data(ld);
 
        return lcd->power;
 }
@@ -391,7 +391,7 @@ static struct lcd_ops corgi_lcd_ops = {
 
 static int corgi_bl_get_intensity(struct backlight_device *bd)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
+       struct corgi_lcd *lcd = bl_get_data(bd);
 
        return lcd->intensity;
 }
@@ -423,7 +423,7 @@ static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity)
 
 static int corgi_bl_update_status(struct backlight_device *bd)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev);
+       struct corgi_lcd *lcd = bl_get_data(bd);
        int intensity = bd->props.brightness;
 
        if (bd->props.power != FB_BLANK_UNBLANK)
@@ -460,7 +460,7 @@ static const struct backlight_ops corgi_bl_ops = {
 #ifdef CONFIG_PM
 static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+       struct corgi_lcd *lcd = spi_get_drvdata(spi);
 
        corgibl_flags |= CORGIBL_SUSPENDED;
        corgi_bl_set_intensity(lcd, 0);
@@ -470,7 +470,7 @@ static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
 
 static int corgi_lcd_resume(struct spi_device *spi)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+       struct corgi_lcd *lcd = spi_get_drvdata(spi);
 
        corgibl_flags &= ~CORGIBL_SUSPENDED;
        corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
@@ -577,7 +577,7 @@ static int corgi_lcd_probe(struct spi_device *spi)
 
        lcd->kick_battery = pdata->kick_battery;
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
        corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
        backlight_update_status(lcd->bl_dev);
 
@@ -594,7 +594,7 @@ err_unregister_lcd:
 
 static int corgi_lcd_remove(struct spi_device *spi)
 {
-       struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev);
+       struct corgi_lcd *lcd = spi_get_drvdata(spi);
 
        lcd->bl_dev->props.power = FB_BLANK_UNBLANK;
        lcd->bl_dev->props.brightness = 0;
diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c
new file mode 100644 (file)
index 0000000..a0482b5
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Driver for the Himax HX-8357 LCD Controller
+ *
+ * Copyright 2012 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/delay.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+
+#define HX8357_NUM_IM_PINS     3
+
+#define HX8357_SWRESET                 0x01
+#define HX8357_GET_RED_CHANNEL         0x06
+#define HX8357_GET_GREEN_CHANNEL       0x07
+#define HX8357_GET_BLUE_CHANNEL                0x08
+#define HX8357_GET_POWER_MODE          0x0a
+#define HX8357_GET_MADCTL              0x0b
+#define HX8357_GET_PIXEL_FORMAT                0x0c
+#define HX8357_GET_DISPLAY_MODE                0x0d
+#define HX8357_GET_SIGNAL_MODE         0x0e
+#define HX8357_GET_DIAGNOSTIC_RESULT   0x0f
+#define HX8357_ENTER_SLEEP_MODE                0x10
+#define HX8357_EXIT_SLEEP_MODE         0x11
+#define HX8357_ENTER_PARTIAL_MODE      0x12
+#define HX8357_ENTER_NORMAL_MODE       0x13
+#define HX8357_EXIT_INVERSION_MODE     0x20
+#define HX8357_ENTER_INVERSION_MODE    0x21
+#define HX8357_SET_DISPLAY_OFF         0x28
+#define HX8357_SET_DISPLAY_ON          0x29
+#define HX8357_SET_COLUMN_ADDRESS      0x2a
+#define HX8357_SET_PAGE_ADDRESS                0x2b
+#define HX8357_WRITE_MEMORY_START      0x2c
+#define HX8357_READ_MEMORY_START       0x2e
+#define HX8357_SET_PARTIAL_AREA                0x30
+#define HX8357_SET_SCROLL_AREA         0x33
+#define HX8357_SET_TEAR_OFF            0x34
+#define HX8357_SET_TEAR_ON             0x35
+#define HX8357_SET_ADDRESS_MODE                0x36
+#define HX8357_SET_SCROLL_START                0x37
+#define HX8357_EXIT_IDLE_MODE          0x38
+#define HX8357_ENTER_IDLE_MODE         0x39
+#define HX8357_SET_PIXEL_FORMAT                0x3a
+#define HX8357_SET_PIXEL_FORMAT_DBI_3BIT       (0x1)
+#define HX8357_SET_PIXEL_FORMAT_DBI_16BIT      (0x5)
+#define HX8357_SET_PIXEL_FORMAT_DBI_18BIT      (0x6)
+#define HX8357_SET_PIXEL_FORMAT_DPI_3BIT       (0x1 << 4)
+#define HX8357_SET_PIXEL_FORMAT_DPI_16BIT      (0x5 << 4)
+#define HX8357_SET_PIXEL_FORMAT_DPI_18BIT      (0x6 << 4)
+#define HX8357_WRITE_MEMORY_CONTINUE   0x3c
+#define HX8357_READ_MEMORY_CONTINUE    0x3e
+#define HX8357_SET_TEAR_SCAN_LINES     0x44
+#define HX8357_GET_SCAN_LINES          0x45
+#define HX8357_READ_DDB_START          0xa1
+#define HX8357_SET_DISPLAY_MODE                0xb4
+#define HX8357_SET_DISPLAY_MODE_RGB_THROUGH    (0x3)
+#define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE  (1 << 4)
+#define HX8357_SET_PANEL_DRIVING       0xc0
+#define HX8357_SET_DISPLAY_FRAME       0xc5
+#define HX8357_SET_RGB                 0xc6
+#define HX8357_SET_RGB_ENABLE_HIGH             (1 << 1)
+#define HX8357_SET_GAMMA               0xc8
+#define HX8357_SET_POWER               0xd0
+#define HX8357_SET_VCOM                        0xd1
+#define HX8357_SET_POWER_NORMAL                0xd2
+#define HX8357_SET_PANEL_RELATED       0xe9
+
+struct hx8357_data {
+       unsigned                im_pins[HX8357_NUM_IM_PINS];
+       unsigned                reset;
+       struct spi_device       *spi;
+       int                     state;
+};
+
+static u8 hx8357_seq_power[] = {
+       HX8357_SET_POWER, 0x44, 0x41, 0x06,
+};
+
+static u8 hx8357_seq_vcom[] = {
+       HX8357_SET_VCOM, 0x40, 0x10,
+};
+
+static u8 hx8357_seq_power_normal[] = {
+       HX8357_SET_POWER_NORMAL, 0x05, 0x12,
+};
+
+static u8 hx8357_seq_panel_driving[] = {
+       HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
+};
+
+static u8 hx8357_seq_display_frame[] = {
+       HX8357_SET_DISPLAY_FRAME, 0x0c,
+};
+
+static u8 hx8357_seq_panel_related[] = {
+       HX8357_SET_PANEL_RELATED, 0x01,
+};
+
+static u8 hx8357_seq_undefined1[] = {
+       0xea, 0x03, 0x00, 0x00,
+};
+
+static u8 hx8357_seq_undefined2[] = {
+       0xeb, 0x40, 0x54, 0x26, 0xdb,
+};
+
+static u8 hx8357_seq_gamma[] = {
+       HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
+       0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
+};
+
+static u8 hx8357_seq_address_mode[] = {
+       HX8357_SET_ADDRESS_MODE, 0xc0,
+};
+
+static u8 hx8357_seq_pixel_format[] = {
+       HX8357_SET_PIXEL_FORMAT,
+       HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
+       HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
+};
+
+static u8 hx8357_seq_column_address[] = {
+       HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
+};
+
+static u8 hx8357_seq_page_address[] = {
+       HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
+};
+
+static u8 hx8357_seq_rgb[] = {
+       HX8357_SET_RGB, 0x02,
+};
+
+static u8 hx8357_seq_display_mode[] = {
+       HX8357_SET_DISPLAY_MODE,
+       HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
+       HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
+};
+
+static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
+                               u8 *txbuf, u16 txlen,
+                               u8 *rxbuf, u16 rxlen)
+{
+       struct hx8357_data *lcd = lcd_get_data(lcdev);
+       struct spi_message msg;
+       struct spi_transfer xfer[2];
+       u16 *local_txbuf = NULL;
+       int ret = 0;
+
+       memset(xfer, 0, sizeof(xfer));
+       spi_message_init(&msg);
+
+       if (txlen) {
+               int i;
+
+               local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
+
+               if (!local_txbuf)
+                       return -ENOMEM;
+
+               for (i = 0; i < txlen; i++) {
+                       local_txbuf[i] = txbuf[i];
+                       if (i > 0)
+                               local_txbuf[i] |= 1 << 8;
+               }
+
+               xfer[0].len = 2 * txlen;
+               xfer[0].bits_per_word = 9;
+               xfer[0].tx_buf = local_txbuf;
+               spi_message_add_tail(&xfer[0], &msg);
+       }
+
+       if (rxlen) {
+               xfer[1].len = rxlen;
+               xfer[1].bits_per_word = 8;
+               xfer[1].rx_buf = rxbuf;
+               spi_message_add_tail(&xfer[1], &msg);
+       }
+
+       ret = spi_sync(lcd->spi, &msg);
+       if (ret < 0)
+               dev_err(&lcdev->dev, "Couldn't send SPI data\n");
+
+       if (txlen)
+               kfree(local_txbuf);
+
+       return ret;
+}
+
+static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
+                                       u8 *value, u8 len)
+{
+       return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
+}
+
+static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
+                                       u8 value)
+{
+       return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
+}
+
+static int hx8357_enter_standby(struct lcd_device *lcdev)
+{
+       int ret;
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(10000, 12000);
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
+       if (ret < 0)
+               return ret;
+
+       msleep(120);
+
+       return 0;
+}
+
+static int hx8357_exit_standby(struct lcd_device *lcdev)
+{
+       int ret;
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
+       if (ret < 0)
+               return ret;
+
+       msleep(120);
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int hx8357_lcd_init(struct lcd_device *lcdev)
+{
+       struct hx8357_data *lcd = lcd_get_data(lcdev);
+       int ret;
+
+       /*
+        * Set the interface selection pins to SPI mode, with three
+        * wires
+        */
+       gpio_set_value_cansleep(lcd->im_pins[0], 1);
+       gpio_set_value_cansleep(lcd->im_pins[1], 0);
+       gpio_set_value_cansleep(lcd->im_pins[2], 1);
+
+       /* Reset the screen */
+       gpio_set_value(lcd->reset, 1);
+       usleep_range(10000, 12000);
+       gpio_set_value(lcd->reset, 0);
+       usleep_range(10000, 12000);
+       gpio_set_value(lcd->reset, 1);
+       msleep(120);
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
+                               ARRAY_SIZE(hx8357_seq_power));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
+                               ARRAY_SIZE(hx8357_seq_vcom));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
+                               ARRAY_SIZE(hx8357_seq_power_normal));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
+                               ARRAY_SIZE(hx8357_seq_panel_driving));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
+                               ARRAY_SIZE(hx8357_seq_display_frame));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
+                               ARRAY_SIZE(hx8357_seq_panel_related));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
+                               ARRAY_SIZE(hx8357_seq_undefined1));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
+                               ARRAY_SIZE(hx8357_seq_undefined2));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
+                               ARRAY_SIZE(hx8357_seq_gamma));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
+                               ARRAY_SIZE(hx8357_seq_address_mode));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
+                               ARRAY_SIZE(hx8357_seq_pixel_format));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
+                               ARRAY_SIZE(hx8357_seq_column_address));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
+                               ARRAY_SIZE(hx8357_seq_page_address));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
+                               ARRAY_SIZE(hx8357_seq_rgb));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
+                               ARRAY_SIZE(hx8357_seq_display_mode));
+       if (ret < 0)
+               return ret;
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
+       if (ret < 0)
+               return ret;
+
+       msleep(120);
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
+       if (ret < 0)
+               return ret;
+
+       usleep_range(5000, 7000);
+
+       ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+#define POWER_IS_ON(pwr)       ((pwr) <= FB_BLANK_NORMAL)
+
+static int hx8357_set_power(struct lcd_device *lcdev, int power)
+{
+       struct hx8357_data *lcd = lcd_get_data(lcdev);
+       int ret = 0;
+
+       if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
+               ret = hx8357_exit_standby(lcdev);
+       else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
+               ret = hx8357_enter_standby(lcdev);
+
+       if (ret == 0)
+               lcd->state = power;
+       else
+               dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
+
+       return ret;
+}
+
+static int hx8357_get_power(struct lcd_device *lcdev)
+{
+       struct hx8357_data *lcd = lcd_get_data(lcdev);
+
+       return lcd->state;
+}
+
+static struct lcd_ops hx8357_ops = {
+       .set_power      = hx8357_set_power,
+       .get_power      = hx8357_get_power,
+};
+
+static int hx8357_probe(struct spi_device *spi)
+{
+       struct lcd_device *lcdev;
+       struct hx8357_data *lcd;
+       int i, ret;
+
+       lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
+       if (!lcd) {
+               dev_err(&spi->dev, "Couldn't allocate lcd internal structure!\n");
+               return -ENOMEM;
+       }
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "SPI setup failed.\n");
+               return ret;
+       }
+
+       lcd->spi = spi;
+
+       lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
+       if (!gpio_is_valid(lcd->reset)) {
+               dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
+               return -EINVAL;
+       }
+
+       ret = devm_gpio_request_one(&spi->dev, lcd->reset,
+                                   GPIOF_OUT_INIT_HIGH,
+                                   "hx8357-reset");
+       if (ret) {
+               dev_err(&spi->dev,
+                       "failed to request gpio %d: %d\n",
+                       lcd->reset, ret);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
+               lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
+                                               "im-gpios", i);
+               if (lcd->im_pins[i] == -EPROBE_DEFER) {
+                       dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
+                       return -EPROBE_DEFER;
+               }
+               if (!gpio_is_valid(lcd->im_pins[i])) {
+                       dev_err(&spi->dev, "Missing dt property: im-gpios\n");
+                       return -EINVAL;
+               }
+
+               ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
+                                       GPIOF_OUT_INIT_LOW, "im_pins");
+               if (ret) {
+                       dev_err(&spi->dev, "failed to request gpio %d: %d\n",
+                               lcd->im_pins[i], ret);
+                       return -EINVAL;
+               }
+       }
+
+       lcdev = lcd_device_register("mxsfb", &spi->dev, lcd, &hx8357_ops);
+       if (IS_ERR(lcdev)) {
+               ret = PTR_ERR(lcdev);
+               return ret;
+       }
+       spi_set_drvdata(spi, lcdev);
+
+       ret = hx8357_lcd_init(lcdev);
+       if (ret) {
+               dev_err(&spi->dev, "Couldn't initialize panel\n");
+               goto init_error;
+       }
+
+       dev_info(&spi->dev, "Panel probed\n");
+
+       return 0;
+
+init_error:
+       lcd_device_unregister(lcdev);
+       return ret;
+}
+
+static int hx8357_remove(struct spi_device *spi)
+{
+       struct lcd_device *lcdev = spi_get_drvdata(spi);
+
+       lcd_device_unregister(lcdev);
+       return 0;
+}
+
+static const struct of_device_id hx8357_dt_ids[] = {
+       { .compatible = "himax,hx8357" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
+
+static struct spi_driver hx8357_driver = {
+       .probe  = hx8357_probe,
+       .remove = hx8357_remove,
+       .driver = {
+               .name = "hx8357",
+               .of_match_table = of_match_ptr(hx8357_dt_ids),
+       },
+};
+
+module_spi_driver(hx8357_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
+MODULE_LICENSE("GPL");
index 9a35196..fb61557 100644 (file)
@@ -49,7 +49,7 @@ static void l4f00242t03_reset(unsigned int gpio)
 static void l4f00242t03_lcd_init(struct spi_device *spi)
 {
        struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
-       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
        const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
 
        dev_dbg(&spi->dev, "initializing LCD\n");
@@ -70,7 +70,7 @@ static void l4f00242t03_lcd_init(struct spi_device *spi)
 static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
 {
        struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
-       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
 
        dev_dbg(&spi->dev, "Powering down LCD\n");
 
@@ -168,7 +168,7 @@ static int l4f00242t03_probe(struct spi_device *spi)
                return -ENOMEM;
        }
 
-       dev_set_drvdata(&spi->dev, priv);
+       spi_set_drvdata(spi, priv);
        spi->bits_per_word = 9;
        spi_setup(spi);
 
@@ -190,27 +190,24 @@ static int l4f00242t03_probe(struct spi_device *spi)
                return ret;
        }
 
-       priv->io_reg = regulator_get(&spi->dev, "vdd");
+       priv->io_reg = devm_regulator_get(&spi->dev, "vdd");
        if (IS_ERR(priv->io_reg)) {
                dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
                       __func__);
                return PTR_ERR(priv->io_reg);
        }
 
-       priv->core_reg = regulator_get(&spi->dev, "vcore");
+       priv->core_reg = devm_regulator_get(&spi->dev, "vcore");
        if (IS_ERR(priv->core_reg)) {
-               ret = PTR_ERR(priv->core_reg);
                dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
                       __func__);
-               goto err1;
+               return PTR_ERR(priv->core_reg);
        }
 
        priv->ld = lcd_device_register("l4f00242t03",
                                        &spi->dev, priv, &l4f_ops);
-       if (IS_ERR(priv->ld)) {
-               ret = PTR_ERR(priv->ld);
-               goto err2;
-       }
+       if (IS_ERR(priv->ld))
+               return PTR_ERR(priv->ld);
 
        /* Init the LCD */
        l4f00242t03_lcd_init(spi);
@@ -220,33 +217,22 @@ static int l4f00242t03_probe(struct spi_device *spi)
        dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
 
        return 0;
-
-err2:
-       regulator_put(priv->core_reg);
-err1:
-       regulator_put(priv->io_reg);
-
-       return ret;
 }
 
 static int l4f00242t03_remove(struct spi_device *spi)
 {
-       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
 
        l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
        lcd_device_unregister(priv->ld);
-
-       dev_set_drvdata(&spi->dev, NULL);
-
-       regulator_put(priv->io_reg);
-       regulator_put(priv->core_reg);
+       spi_set_drvdata(spi, NULL);
 
        return 0;
 }
 
 static void l4f00242t03_shutdown(struct spi_device *spi)
 {
-       struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev);
+       struct l4f00242t03_priv *priv = spi_get_drvdata(spi);
 
        if (priv)
                l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
index 1cb3524..1b642f5 100644 (file)
@@ -9,29 +9,20 @@
  * 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/backlight.h>
 #include <linux/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/lcd.h>
-#include <linux/backlight.h>
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
 
 #include "ld9040_gamma.h"
 
@@ -43,7 +34,6 @@
 
 #define MIN_BRIGHTNESS         0
 #define MAX_BRIGHTNESS         24
-#define power_is_on(pwr)       ((pwr) <= FB_BLANK_NORMAL)
 
 struct ld9040 {
        struct device                   *dev;
@@ -78,7 +68,7 @@ static void ld9040_regulator_enable(struct ld9040 *lcd)
 
                lcd->enabled = true;
        }
-       mdelay(pd->power_on_delay);
+       msleep(pd->power_on_delay);
 out:
        mutex_unlock(&lcd->lock);
 }
@@ -474,8 +464,9 @@ static int ld9040_panel_send_sequence(struct ld9040 *lcd,
                        ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
                        if (ret)
                                break;
-               } else
-                       udelay(wbuf[i+1]*1000);
+               } else {
+                       msleep(wbuf[i+1]);
+               }
                i += 2;
        }
 
@@ -513,14 +504,9 @@ gamma_err:
 
 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;
+       return _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
 }
 
-
 static int ld9040_ldi_init(struct ld9040 *lcd)
 {
        int ret, i;
@@ -539,7 +525,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd)
        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);
+               usleep_range(300, 310);
                if (ret)
                        break;
        }
@@ -549,11 +535,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd)
 
 static int ld9040_ldi_enable(struct ld9040 *lcd)
 {
-       int ret = 0;
-
-       ret = ld9040_panel_send_sequence(lcd, seq_display_on);
-
-       return ret;
+       return ld9040_panel_send_sequence(lcd, seq_display_on);
 }
 
 static int ld9040_ldi_disable(struct ld9040 *lcd)
@@ -566,25 +548,27 @@ static int ld9040_ldi_disable(struct ld9040 *lcd)
        return ret;
 }
 
+static int ld9040_power_is_on(int power)
+{
+       return power <= FB_BLANK_NORMAL;
+}
+
 static int ld9040_power_on(struct ld9040 *lcd)
 {
        int ret = 0;
-       struct lcd_platform_data *pd = NULL;
+       struct lcd_platform_data *pd;
+
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL.\n");
-               return -EFAULT;
-       }
 
        /* lcd power on */
        ld9040_regulator_enable(lcd);
 
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        } else {
                pd->reset(lcd->ld);
-               mdelay(pd->reset_delay);
+               msleep(pd->reset_delay);
        }
 
        ret = ld9040_ldi_init(lcd);
@@ -604,14 +588,10 @@ static int ld9040_power_on(struct ld9040 *lcd)
 
 static int ld9040_power_off(struct ld9040 *lcd)
 {
-       int ret = 0;
-       struct lcd_platform_data *pd = NULL;
+       int ret;
+       struct lcd_platform_data *pd;
 
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL.\n");
-               return -EFAULT;
-       }
 
        ret = ld9040_ldi_disable(lcd);
        if (ret) {
@@ -619,7 +599,7 @@ static int ld9040_power_off(struct ld9040 *lcd)
                return -EIO;
        }
 
-       mdelay(pd->power_off_delay);
+       msleep(pd->power_off_delay);
 
        /* lcd power off */
        ld9040_regulator_disable(lcd);
@@ -631,9 +611,9 @@ static int ld9040_power(struct ld9040 *lcd, int power)
 {
        int ret = 0;
 
-       if (power_is_on(power) && !power_is_on(lcd->power))
+       if (ld9040_power_is_on(power) && !ld9040_power_is_on(lcd->power))
                ret = ld9040_power_on(lcd);
-       else if (!power_is_on(power) && power_is_on(lcd->power))
+       else if (!ld9040_power_is_on(power) && ld9040_power_is_on(lcd->power))
                ret = ld9040_power_off(lcd);
 
        if (!ret)
@@ -698,7 +678,6 @@ static const struct backlight_ops ld9040_backlight_ops  = {
        .update_status = ld9040_set_brightness,
 };
 
-
 static int ld9040_probe(struct spi_device *spi)
 {
        int ret = 0;
@@ -726,22 +705,20 @@ static int ld9040_probe(struct spi_device *spi)
        lcd->lcd_pd = spi->dev.platform_data;
        if (!lcd->lcd_pd) {
                dev_err(&spi->dev, "platform data is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        }
 
        mutex_init(&lcd->lock);
 
-       ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+       ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
        if (ret) {
                dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
                return ret;
        }
 
        ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
-       if (IS_ERR(ld)) {
-               ret = PTR_ERR(ld);
-               goto out_free_regulator;
-       }
+       if (IS_ERR(ld))
+               return PTR_ERR(ld);
 
        lcd->ld = ld;
 
@@ -772,30 +749,28 @@ static int ld9040_probe(struct spi_device *spi)
                lcd->power = FB_BLANK_POWERDOWN;
 
                ld9040_power(lcd, FB_BLANK_UNBLANK);
-       } else
+       } else {
                lcd->power = FB_BLANK_UNBLANK;
+       }
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
 
        dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
        return 0;
 
 out_unregister_lcd:
        lcd_device_unregister(lcd->ld);
-out_free_regulator:
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 
        return ret;
 }
 
 static int ld9040_remove(struct spi_device *spi)
 {
-       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+       struct ld9040 *lcd = spi_get_drvdata(spi);
 
        ld9040_power(lcd, FB_BLANK_POWERDOWN);
        backlight_device_unregister(lcd->bd);
        lcd_device_unregister(lcd->ld);
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 
        return 0;
 }
@@ -803,8 +778,7 @@ static int ld9040_remove(struct spi_device *spi)
 #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);
+       struct ld9040 *lcd = spi_get_drvdata(spi);
 
        dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 
@@ -812,21 +786,16 @@ static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
         * when lcd panel is suspend, lcd panel becomes off
         * regardless of status.
         */
-       ret = ld9040_power(lcd, FB_BLANK_POWERDOWN);
-
-       return ret;
+       return ld9040_power(lcd, FB_BLANK_POWERDOWN);
 }
 
 static int ld9040_resume(struct spi_device *spi)
 {
-       int ret = 0;
-       struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+       struct ld9040 *lcd = spi_get_drvdata(spi);
 
        lcd->power = FB_BLANK_POWERDOWN;
 
-       ret = ld9040_power(lcd, FB_BLANK_UNBLANK);
-
-       return ret;
+       return ld9040_power(lcd, FB_BLANK_UNBLANK);
 }
 #else
 #define ld9040_suspend         NULL
@@ -836,7 +805,7 @@ static int ld9040_resume(struct spi_device *spi)
 /* 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);
+       struct ld9040 *lcd = spi_get_drvdata(spi);
 
        ld9040_power(lcd, FB_BLANK_POWERDOWN);
 }
index a6d637b..76a62e9 100644 (file)
@@ -320,7 +320,7 @@ static int lm3630_backlight_register(struct lm3630_chip_data *pchip,
                    backlight_device_register(name, pchip->dev, pchip,
                                              &lm3630_bank_a_ops, &props);
                if (IS_ERR(pchip->bled1))
-                       return -EIO;
+                       return PTR_ERR(pchip->bled1);
                break;
        case BLED_2:
                props.brightness = pdata->init_brt_led2;
@@ -329,7 +329,7 @@ static int lm3630_backlight_register(struct lm3630_chip_data *pchip,
                    backlight_device_register(name, pchip->dev, pchip,
                                              &lm3630_bank_b_ops, &props);
                if (IS_ERR(pchip->bled2))
-                       return -EIO;
+                       return PTR_ERR(pchip->bled2);
                break;
        }
        return 0;
index 7ab2d2a..053964d 100644 (file)
@@ -350,14 +350,13 @@ static int lm3639_probe(struct i2c_client *client,
                                      &lm3639_bled_ops, &props);
        if (IS_ERR(pchip->bled)) {
                dev_err(&client->dev, "fail : backlight register\n");
-               ret = -EIO;
+               ret = PTR_ERR(pchip->bled);
                goto err_out;
        }
 
        ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
        if (ret < 0) {
                dev_err(&client->dev, "failed : add sysfs entries\n");
-               ret = -EIO;
                goto err_bled_mode;
        }
 
@@ -369,7 +368,6 @@ static int lm3639_probe(struct i2c_client *client,
                                    &client->dev, &pchip->cdev_flash);
        if (ret < 0) {
                dev_err(&client->dev, "fail : flash register\n");
-               ret = -EIO;
                goto err_flash;
        }
 
@@ -381,7 +379,6 @@ static int lm3639_probe(struct i2c_client *client,
                                    &client->dev, &pchip->cdev_torch);
        if (ret < 0) {
                dev_err(&client->dev, "fail : torch register\n");
-               ret = -EIO;
                goto err_torch;
        }
 
index 55819b3..4eec472 100644 (file)
@@ -180,7 +180,7 @@ static int lms283gf05_probe(struct spi_device *spi)
        st->spi = spi;
        st->ld = ld;
 
-       dev_set_drvdata(&spi->dev, st);
+       spi_set_drvdata(spi, st);
 
        /* kick in the LCD */
        if (pdata)
@@ -192,7 +192,7 @@ static int lms283gf05_probe(struct spi_device *spi)
 
 static int lms283gf05_remove(struct spi_device *spi)
 {
-       struct lms283gf05_state *st = dev_get_drvdata(&spi->dev);
+       struct lms283gf05_state *st = spi_get_drvdata(spi);
 
        lcd_device_unregister(st->ld);
 
diff --git a/drivers/video/backlight/lms501kf03.c b/drivers/video/backlight/lms501kf03.c
new file mode 100644 (file)
index 0000000..b43882a
--- /dev/null
@@ -0,0 +1,441 @@
+/*
+ * lms501kf03 TFT LCD panel driver.
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han  <jg1.han@samsung.com>
+ *
+ * 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.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
+
+#define COMMAND_ONLY           0x00
+#define DATA_ONLY              0x01
+
+struct lms501kf03 {
+       struct device                   *dev;
+       struct spi_device               *spi;
+       unsigned int                    power;
+       struct lcd_device               *ld;
+       struct lcd_platform_data        *lcd_pd;
+};
+
+static const unsigned char seq_password[] = {
+       0xb9, 0xff, 0x83, 0x69,
+};
+
+static const unsigned char seq_power[] = {
+       0xb1, 0x01, 0x00, 0x34, 0x06, 0x00, 0x14, 0x14, 0x20, 0x28,
+       0x12, 0x12, 0x17, 0x0a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
+};
+
+static const unsigned char seq_display[] = {
+       0xb2, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00, 0xff, 0x00, 0x00,
+       0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
+};
+
+static const unsigned char seq_rgb_if[] = {
+       0xb3, 0x09,
+};
+
+static const unsigned char seq_display_inv[] = {
+       0xb4, 0x01, 0x08, 0x77, 0x0e, 0x06,
+};
+
+static const unsigned char seq_vcom[] = {
+       0xb6, 0x4c, 0x2e,
+};
+
+static const unsigned char seq_gate[] = {
+       0xd5, 0x00, 0x05, 0x03, 0x29, 0x01, 0x07, 0x17, 0x68, 0x13,
+       0x37, 0x20, 0x31, 0x8a, 0x46, 0x9b, 0x57, 0x13, 0x02, 0x75,
+       0xb9, 0x64, 0xa8, 0x07, 0x0f, 0x04, 0x07,
+};
+
+static const unsigned char seq_panel[] = {
+       0xcc, 0x02,
+};
+
+static const unsigned char seq_col_mod[] = {
+       0x3a, 0x77,
+};
+
+static const unsigned char seq_w_gamma[] = {
+       0xe0, 0x00, 0x04, 0x09, 0x0f, 0x1f, 0x3f, 0x1f, 0x2f, 0x0a,
+       0x0f, 0x10, 0x16, 0x18, 0x16, 0x17, 0x0d, 0x15, 0x00, 0x04,
+       0x09, 0x0f, 0x38, 0x3f, 0x20, 0x39, 0x0a, 0x0f, 0x10, 0x16,
+       0x18, 0x16, 0x17, 0x0d, 0x15,
+};
+
+static const unsigned char seq_rgb_gamma[] = {
+       0xc1, 0x01, 0x03, 0x07, 0x0f, 0x1a, 0x22, 0x2c, 0x33, 0x3c,
+       0x46, 0x4f, 0x58, 0x60, 0x69, 0x71, 0x79, 0x82, 0x89, 0x92,
+       0x9a, 0xa1, 0xa9, 0xb1, 0xb9, 0xc1, 0xc9, 0xcf, 0xd6, 0xde,
+       0xe5, 0xec, 0xf3, 0xf9, 0xff, 0xdd, 0x39, 0x07, 0x1c, 0xcb,
+       0xab, 0x5f, 0x49, 0x80, 0x03, 0x07, 0x0f, 0x19, 0x20, 0x2a,
+       0x31, 0x39, 0x42, 0x4b, 0x53, 0x5b, 0x63, 0x6b, 0x73, 0x7b,
+       0x83, 0x8a, 0x92, 0x9b, 0xa2, 0xaa, 0xb2, 0xba, 0xc2, 0xca,
+       0xd0, 0xd8, 0xe1, 0xe8, 0xf0, 0xf8, 0xff, 0xf7, 0xd8, 0xbe,
+       0xa7, 0x39, 0x40, 0x85, 0x8c, 0xc0, 0x04, 0x07, 0x0c, 0x17,
+       0x1c, 0x23, 0x2b, 0x34, 0x3b, 0x43, 0x4c, 0x54, 0x5b, 0x63,
+       0x6a, 0x73, 0x7a, 0x82, 0x8a, 0x91, 0x98, 0xa1, 0xa8, 0xb0,
+       0xb7, 0xc1, 0xc9, 0xcf, 0xd9, 0xe3, 0xea, 0xf4, 0xff, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char seq_up_dn[] = {
+       0x36, 0x10,
+};
+
+static const unsigned char seq_sleep_in[] = {
+       0x10,
+};
+
+static const unsigned char seq_sleep_out[] = {
+       0x11,
+};
+
+static const unsigned char seq_display_on[] = {
+       0x29,
+};
+
+static const unsigned char seq_display_off[] = {
+       0x10,
+};
+
+static int lms501kf03_spi_write_byte(struct lms501kf03 *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 lms501kf03_spi_write(struct lms501kf03 *lcd, unsigned char address,
+                               unsigned char command)
+{
+       return lms501kf03_spi_write_byte(lcd, address, command);
+}
+
+static int lms501kf03_panel_send_sequence(struct lms501kf03 *lcd,
+                                       const unsigned char *wbuf,
+                                       unsigned int len)
+{
+       int ret = 0, i = 0;
+
+       while (i < len) {
+               if (i == 0)
+                       ret = lms501kf03_spi_write(lcd, COMMAND_ONLY, wbuf[i]);
+               else
+                       ret = lms501kf03_spi_write(lcd, DATA_ONLY, wbuf[i]);
+               if (ret)
+                       break;
+               i += 1;
+       }
+
+       return ret;
+}
+
+static int lms501kf03_ldi_init(struct lms501kf03 *lcd)
+{
+       int ret, i;
+       static const unsigned char *init_seq[] = {
+               seq_password,
+               seq_power,
+               seq_display,
+               seq_rgb_if,
+               seq_display_inv,
+               seq_vcom,
+               seq_gate,
+               seq_panel,
+               seq_col_mod,
+               seq_w_gamma,
+               seq_rgb_gamma,
+               seq_sleep_out,
+       };
+
+       static const unsigned int size_seq[] = {
+               ARRAY_SIZE(seq_password),
+               ARRAY_SIZE(seq_power),
+               ARRAY_SIZE(seq_display),
+               ARRAY_SIZE(seq_rgb_if),
+               ARRAY_SIZE(seq_display_inv),
+               ARRAY_SIZE(seq_vcom),
+               ARRAY_SIZE(seq_gate),
+               ARRAY_SIZE(seq_panel),
+               ARRAY_SIZE(seq_col_mod),
+               ARRAY_SIZE(seq_w_gamma),
+               ARRAY_SIZE(seq_rgb_gamma),
+               ARRAY_SIZE(seq_sleep_out),
+       };
+
+       for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+               ret = lms501kf03_panel_send_sequence(lcd, init_seq[i],
+                                               size_seq[i]);
+               if (ret)
+                       break;
+       }
+       /*
+        * According to the datasheet, 120ms delay time is required.
+        * After sleep out sequence, command is blocked for 120ms.
+        * Thus, LDI should wait for 120ms.
+        */
+       msleep(120);
+
+       return ret;
+}
+
+static int lms501kf03_ldi_enable(struct lms501kf03 *lcd)
+{
+       return lms501kf03_panel_send_sequence(lcd, seq_display_on,
+                                       ARRAY_SIZE(seq_display_on));
+}
+
+static int lms501kf03_ldi_disable(struct lms501kf03 *lcd)
+{
+       return lms501kf03_panel_send_sequence(lcd, seq_display_off,
+                                       ARRAY_SIZE(seq_display_off));
+}
+
+static int lms501kf03_power_is_on(int power)
+{
+       return (power) <= FB_BLANK_NORMAL;
+}
+
+static int lms501kf03_power_on(struct lms501kf03 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd;
+
+       pd = lcd->lcd_pd;
+
+       if (!pd->power_on) {
+               dev_err(lcd->dev, "power_on is NULL.\n");
+               return -EINVAL;
+       } else {
+               pd->power_on(lcd->ld, 1);
+               msleep(pd->power_on_delay);
+       }
+
+       if (!pd->reset) {
+               dev_err(lcd->dev, "reset is NULL.\n");
+               return -EINVAL;
+       } else {
+               pd->reset(lcd->ld);
+               msleep(pd->reset_delay);
+       }
+
+       ret = lms501kf03_ldi_init(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to initialize ldi.\n");
+               return ret;
+       }
+
+       ret = lms501kf03_ldi_enable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "failed to enable ldi.\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int lms501kf03_power_off(struct lms501kf03 *lcd)
+{
+       int ret = 0;
+       struct lcd_platform_data *pd;
+
+       pd = lcd->lcd_pd;
+
+       ret = lms501kf03_ldi_disable(lcd);
+       if (ret) {
+               dev_err(lcd->dev, "lcd setting failed.\n");
+               return -EIO;
+       }
+
+       msleep(pd->power_off_delay);
+
+       pd->power_on(lcd->ld, 0);
+
+       return 0;
+}
+
+static int lms501kf03_power(struct lms501kf03 *lcd, int power)
+{
+       int ret = 0;
+
+       if (lms501kf03_power_is_on(power) &&
+               !lms501kf03_power_is_on(lcd->power))
+               ret = lms501kf03_power_on(lcd);
+       else if (!lms501kf03_power_is_on(power) &&
+               lms501kf03_power_is_on(lcd->power))
+               ret = lms501kf03_power_off(lcd);
+
+       if (!ret)
+               lcd->power = power;
+
+       return ret;
+}
+
+static int lms501kf03_get_power(struct lcd_device *ld)
+{
+       struct lms501kf03 *lcd = lcd_get_data(ld);
+
+       return lcd->power;
+}
+
+static int lms501kf03_set_power(struct lcd_device *ld, int power)
+{
+       struct lms501kf03 *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 lms501kf03_power(lcd, power);
+}
+
+static struct lcd_ops lms501kf03_lcd_ops = {
+       .get_power = lms501kf03_get_power,
+       .set_power = lms501kf03_set_power,
+};
+
+static int lms501kf03_probe(struct spi_device *spi)
+{
+       struct lms501kf03 *lcd = NULL;
+       struct lcd_device *ld = NULL;
+       int ret = 0;
+
+       lcd = devm_kzalloc(&spi->dev, sizeof(struct lms501kf03), GFP_KERNEL);
+       if (!lcd)
+               return -ENOMEM;
+
+       /* lms501kf03 lcd panel uses 3-wire 9-bit SPI Mode. */
+       spi->bits_per_word = 9;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "spi setup failed.\n");
+               return ret;
+       }
+
+       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");
+               return -EINVAL;
+       }
+
+       ld = lcd_device_register("lms501kf03", &spi->dev, lcd,
+                               &lms501kf03_lcd_ops);
+       if (IS_ERR(ld))
+               return PTR_ERR(ld);
+
+       lcd->ld = ld;
+
+       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;
+
+               lms501kf03_power(lcd, FB_BLANK_UNBLANK);
+       } else {
+               lcd->power = FB_BLANK_UNBLANK;
+       }
+
+       spi_set_drvdata(spi, lcd);
+
+       dev_info(&spi->dev, "lms501kf03 panel driver has been probed.\n");
+
+       return 0;
+}
+
+static int lms501kf03_remove(struct spi_device *spi)
+{
+       struct lms501kf03 *lcd = spi_get_drvdata(spi);
+
+       lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+       lcd_device_unregister(lcd->ld);
+
+       return 0;
+}
+
+#if defined(CONFIG_PM)
+
+static int lms501kf03_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+       struct lms501kf03 *lcd = spi_get_drvdata(spi);
+
+       dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+       /*
+        * when lcd panel is suspend, lcd panel becomes off
+        * regardless of status.
+        */
+       return lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static int lms501kf03_resume(struct spi_device *spi)
+{
+       struct lms501kf03 *lcd = spi_get_drvdata(spi);
+
+       lcd->power = FB_BLANK_POWERDOWN;
+
+       return lms501kf03_power(lcd, FB_BLANK_UNBLANK);
+}
+#else
+#define lms501kf03_suspend     NULL
+#define lms501kf03_resume      NULL
+#endif
+
+static void lms501kf03_shutdown(struct spi_device *spi)
+{
+       struct lms501kf03 *lcd = spi_get_drvdata(spi);
+
+       lms501kf03_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver lms501kf03_driver = {
+       .driver = {
+               .name   = "lms501kf03",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = lms501kf03_probe,
+       .remove         = lms501kf03_remove,
+       .shutdown       = lms501kf03_shutdown,
+       .suspend        = lms501kf03_suspend,
+       .resume         = lms501kf03_resume,
+};
+
+module_spi_driver(lms501kf03_driver);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("lms501kf03 LCD Driver");
+MODULE_LICENSE("GPL");
index 6e4db0c..7ae9ae6 100644 (file)
 #include <linux/platform_data/lp855x.h>
 #include <linux/pwm.h>
 
-/* Registers */
-#define BRIGHTNESS_CTRL                0x00
-#define DEVICE_CTRL            0x01
-#define EEPROM_START           0xA0
-#define EEPROM_END             0xA7
-#define EPROM_START            0xA0
-#define EPROM_END              0xAF
+/* LP8550/1/2/3/6 Registers */
+#define LP855X_BRIGHTNESS_CTRL         0x00
+#define LP855X_DEVICE_CTRL             0x01
+#define LP855X_EEPROM_START            0xA0
+#define LP855X_EEPROM_END              0xA7
+#define LP8556_EPROM_START             0xA0
+#define LP8556_EPROM_END               0xAF
+
+/* LP8557 Registers */
+#define LP8557_BL_CMD                  0x00
+#define LP8557_BL_MASK                 0x01
+#define LP8557_BL_ON                   0x01
+#define LP8557_BL_OFF                  0x00
+#define LP8557_BRIGHTNESS_CTRL         0x04
+#define LP8557_CONFIG                  0x10
+#define LP8557_EPROM_START             0x10
+#define LP8557_EPROM_END               0x1E
 
 #define BUF_SIZE               20
 #define DEFAULT_BL_NAME                "lcd-backlight"
 #define MAX_BRIGHTNESS         255
 
+struct lp855x;
+
+/*
+ * struct lp855x_device_config
+ * @pre_init_device: init device function call before updating the brightness
+ * @reg_brightness: register address for brigthenss control
+ * @reg_devicectrl: register address for device control
+ * @post_init_device: late init device function call
+ */
+struct lp855x_device_config {
+       int (*pre_init_device)(struct lp855x *);
+       u8 reg_brightness;
+       u8 reg_devicectrl;
+       int (*post_init_device)(struct lp855x *);
+};
+
 struct lp855x {
        const char *chipname;
        enum lp855x_chip_id chip_id;
+       struct lp855x_device_config *cfg;
        struct i2c_client *client;
        struct backlight_device *bl;
        struct device *dev;
@@ -39,9 +66,15 @@ struct lp855x {
        struct pwm_device *pwm;
 };
 
-static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
+static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
+{
+       return i2c_smbus_write_byte_data(lp->client, reg, data);
+}
+
+static int lp855x_update_bit(struct lp855x *lp, u8 reg, u8 mask, u8 data)
 {
        int ret;
+       u8 tmp;
 
        ret = i2c_smbus_read_byte_data(lp->client, reg);
        if (ret < 0) {
@@ -49,13 +82,11 @@ static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
                return ret;
        }
 
-       *data = (u8)ret;
-       return 0;
-}
+       tmp = (u8)ret;
+       tmp &= ~mask;
+       tmp |= data & mask;
 
-static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data)
-{
-       return i2c_smbus_write_byte_data(lp->client, reg, data);
+       return lp855x_write_byte(lp, reg, tmp);
 }
 
 static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
@@ -67,12 +98,16 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
        case LP8551:
        case LP8552:
        case LP8553:
-               start = EEPROM_START;
-               end = EEPROM_END;
+               start = LP855X_EEPROM_START;
+               end = LP855X_EEPROM_END;
                break;
        case LP8556:
-               start = EPROM_START;
-               end = EPROM_END;
+               start = LP8556_EPROM_START;
+               end = LP8556_EPROM_END;
+               break;
+       case LP8557:
+               start = LP8557_EPROM_START;
+               end = LP8557_EPROM_END;
                break;
        default:
                return false;
@@ -81,21 +116,76 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
        return (addr >= start && addr <= end);
 }
 
-static int lp855x_init_registers(struct lp855x *lp)
+static int lp8557_bl_off(struct lp855x *lp)
+{
+       /* BL_ON = 0 before updating EPROM settings */
+       return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
+                               LP8557_BL_OFF);
+}
+
+static int lp8557_bl_on(struct lp855x *lp)
+{
+       /* BL_ON = 1 after updating EPROM settings */
+       return lp855x_update_bit(lp, LP8557_BL_CMD, LP8557_BL_MASK,
+                               LP8557_BL_ON);
+}
+
+static struct lp855x_device_config lp855x_dev_cfg = {
+       .reg_brightness = LP855X_BRIGHTNESS_CTRL,
+       .reg_devicectrl = LP855X_DEVICE_CTRL,
+};
+
+static struct lp855x_device_config lp8557_dev_cfg = {
+       .reg_brightness = LP8557_BRIGHTNESS_CTRL,
+       .reg_devicectrl = LP8557_CONFIG,
+       .pre_init_device = lp8557_bl_off,
+       .post_init_device = lp8557_bl_on,
+};
+
+/*
+ * Device specific configuration flow
+ *
+ *    a) pre_init_device(optional)
+ *    b) update the brightness register
+ *    c) update device control register
+ *    d) update ROM area(optional)
+ *    e) post_init_device(optional)
+ *
+ */
+static int lp855x_configure(struct lp855x *lp)
 {
        u8 val, addr;
        int i, ret;
        struct lp855x_platform_data *pd = lp->pdata;
 
+       switch (lp->chip_id) {
+       case LP8550 ... LP8556:
+               lp->cfg = &lp855x_dev_cfg;
+               break;
+       case LP8557:
+               lp->cfg = &lp8557_dev_cfg;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (lp->cfg->pre_init_device) {
+               ret = lp->cfg->pre_init_device(lp);
+               if (ret) {
+                       dev_err(lp->dev, "pre init device err: %d\n", ret);
+                       goto err;
+               }
+       }
+
        val = pd->initial_brightness;
-       ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+       ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
        if (ret)
-               return ret;
+               goto err;
 
        val = pd->device_control;
-       ret = lp855x_write_byte(lp, DEVICE_CTRL, val);
+       ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
        if (ret)
-               return ret;
+               goto err;
 
        if (pd->load_new_rom_data && pd->size_program) {
                for (i = 0; i < pd->size_program; i++) {
@@ -106,10 +196,21 @@ static int lp855x_init_registers(struct lp855x *lp)
 
                        ret = lp855x_write_byte(lp, addr, val);
                        if (ret)
-                               return ret;
+                               goto err;
+               }
+       }
+
+       if (lp->cfg->post_init_device) {
+               ret = lp->cfg->post_init_device(lp);
+               if (ret) {
+                       dev_err(lp->dev, "post init device err: %d\n", ret);
+                       goto err;
                }
        }
 
+       return 0;
+
+err:
        return ret;
 }
 
@@ -151,7 +252,7 @@ static int lp855x_bl_update_status(struct backlight_device *bl)
 
        } else if (mode == REGISTER_BASED) {
                u8 val = bl->props.brightness;
-               lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+               lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
        }
 
        return 0;
@@ -159,16 +260,6 @@ static int lp855x_bl_update_status(struct backlight_device *bl)
 
 static int lp855x_bl_get_brightness(struct backlight_device *bl)
 {
-       struct lp855x *lp = bl_get_data(bl);
-       enum lp855x_brightness_ctrl_mode mode = lp->pdata->mode;
-
-       if (mode == REGISTER_BASED) {
-               u8 val = 0;
-
-               lp855x_read_byte(lp, BRIGHTNESS_CTRL, &val);
-               bl->props.brightness = val;
-       }
-
        return bl->props.brightness;
 }
 
@@ -271,11 +362,10 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
        lp->chip_id = id->driver_data;
        i2c_set_clientdata(cl, lp);
 
-       ret = lp855x_init_registers(lp);
+       ret = lp855x_configure(lp);
        if (ret) {
-               dev_err(lp->dev, "i2c communication err: %d", ret);
-               if (mode == REGISTER_BASED)
-                       goto err_dev;
+               dev_err(lp->dev, "device config err: %d", ret);
+               goto err_dev;
        }
 
        ret = lp855x_backlight_register(lp);
@@ -318,6 +408,7 @@ static const struct i2c_device_id lp855x_ids[] = {
        {"lp8552", LP8552},
        {"lp8553", LP8553},
        {"lp8556", LP8556},
+       {"lp8557", LP8557},
        { }
 };
 MODULE_DEVICE_TABLE(i2c, lp855x_ids);
index 226d813..c0b4b8f 100644 (file)
@@ -252,7 +252,7 @@ static int ltv350qv_probe(struct spi_device *spi)
        if (ret)
                goto out_unregister;
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
 
        return 0;
 
@@ -263,7 +263,7 @@ out_unregister:
 
 static int ltv350qv_remove(struct spi_device *spi)
 {
-       struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+       struct ltv350qv *lcd = spi_get_drvdata(spi);
 
        ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
        lcd_device_unregister(lcd->ld);
@@ -274,14 +274,14 @@ static int ltv350qv_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
 {
-       struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+       struct ltv350qv *lcd = spi_get_drvdata(spi);
 
        return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
 }
 
 static int ltv350qv_resume(struct spi_device *spi)
 {
-       struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+       struct ltv350qv *lcd = spi_get_drvdata(spi);
 
        return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
 }
@@ -293,7 +293,7 @@ static int ltv350qv_resume(struct spi_device *spi)
 /* Power down all displays on reboot, poweroff or halt */
 static void ltv350qv_shutdown(struct spi_device *spi)
 {
-       struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+       struct ltv350qv *lcd = spi_get_drvdata(spi);
 
        ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
 }
index af31c26..6271101 100644 (file)
@@ -77,7 +77,7 @@ static void omapbl_blank(struct omap_backlight *bl, int mode)
 static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct backlight_device *dev = platform_get_drvdata(pdev);
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       struct omap_backlight *bl = bl_get_data(dev);
 
        omapbl_blank(bl, FB_BLANK_POWERDOWN);
        return 0;
@@ -86,7 +86,7 @@ static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
 static int omapbl_resume(struct platform_device *pdev)
 {
        struct backlight_device *dev = platform_get_drvdata(pdev);
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       struct omap_backlight *bl = bl_get_data(dev);
 
        omapbl_blank(bl, bl->powermode);
        return 0;
@@ -98,7 +98,7 @@ static int omapbl_resume(struct platform_device *pdev)
 
 static int omapbl_set_power(struct backlight_device *dev, int state)
 {
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       struct omap_backlight *bl = bl_get_data(dev);
 
        omapbl_blank(bl, state);
        bl->powermode = state;
@@ -108,7 +108,7 @@ static int omapbl_set_power(struct backlight_device *dev, int state)
 
 static int omapbl_update_status(struct backlight_device *dev)
 {
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       struct omap_backlight *bl = bl_get_data(dev);
 
        if (bl->current_intensity != dev->props.brightness) {
                if (bl->powermode == FB_BLANK_UNBLANK)
@@ -124,7 +124,7 @@ static int omapbl_update_status(struct backlight_device *dev)
 
 static int omapbl_get_intensity(struct backlight_device *dev)
 {
-       struct omap_backlight *bl = dev_get_drvdata(&dev->dev);
+       struct omap_backlight *bl = bl_get_data(dev);
        return bl->current_intensity;
 }
 
index 069983c..f2f4c43 100644 (file)
@@ -37,7 +37,7 @@ struct pwm_bl_data {
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
 {
-       struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+       struct pwm_bl_data *pb = bl_get_data(bl);
        int brightness = bl->props.brightness;
        int max = bl->props.max_brightness;
 
@@ -83,7 +83,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
 static int pwm_backlight_check_fb(struct backlight_device *bl,
                                  struct fb_info *info)
 {
-       struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+       struct pwm_bl_data *pb = bl_get_data(bl);
 
        return !pb->check_fb || pb->check_fb(pb->dev, info);
 }
@@ -264,7 +264,7 @@ err_alloc:
 static int pwm_backlight_remove(struct platform_device *pdev)
 {
        struct backlight_device *bl = platform_get_drvdata(pdev);
-       struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+       struct pwm_bl_data *pb = bl_get_data(bl);
 
        backlight_device_unregister(bl);
        pwm_config(pb->pwm, 0, pb->period);
@@ -278,7 +278,7 @@ static int pwm_backlight_remove(struct platform_device *pdev)
 static int pwm_backlight_suspend(struct device *dev)
 {
        struct backlight_device *bl = dev_get_drvdata(dev);
-       struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
+       struct pwm_bl_data *pb = bl_get_data(bl);
 
        if (pb->notify)
                pb->notify(pb->dev, 0);
index 3e1c113..9c2677f 100644 (file)
@@ -9,28 +9,19 @@
  * 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/backlight.h>
 #include <linux/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/lcd.h>
-#include <linux/backlight.h>
 #include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
 
 #include "s6e63m0_gamma.h"
 
@@ -43,8 +34,6 @@
 #define MIN_BRIGHTNESS         0
 #define MAX_BRIGHTNESS         10
 
-#define POWER_IS_ON(pwr)       ((pwr) <= FB_BLANK_NORMAL)
-
 struct s6e63m0 {
        struct device                   *dev;
        struct spi_device               *spi;
@@ -57,7 +46,7 @@ struct s6e63m0 {
        struct lcd_platform_data        *lcd_pd;
 };
 
-static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
+static const unsigned short seq_panel_condition_set[] = {
        0xF8, 0x01,
        DATA_ONLY, 0x27,
        DATA_ONLY, 0x27,
@@ -76,7 +65,7 @@ static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
+static const unsigned short seq_display_condition_set[] = {
        0xf2, 0x02,
        DATA_ONLY, 0x03,
        DATA_ONLY, 0x1c,
@@ -90,7 +79,7 @@ static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_GAMMA_SETTING[] = {
+static const unsigned short seq_gamma_setting[] = {
        0xfa, 0x00,
        DATA_ONLY, 0x18,
        DATA_ONLY, 0x08,
@@ -119,7 +108,7 @@ static const unsigned short SEQ_GAMMA_SETTING[] = {
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_ETC_CONDITION_SET[] = {
+static const unsigned short seq_etc_condition_set[] = {
        0xf6, 0x00,
        DATA_ONLY, 0x8c,
        DATA_ONLY, 0x07,
@@ -318,47 +307,47 @@ static const unsigned short SEQ_ETC_CONDITION_SET[] = {
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_ACL_ON[] = {
+static const unsigned short seq_acl_on[] = {
        /* ACL on */
        0xc0, 0x01,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_ACL_OFF[] = {
+static const unsigned short seq_acl_off[] = {
        /* ACL off */
        0xc0, 0x00,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_ELVSS_ON[] = {
+static const unsigned short seq_elvss_on[] = {
        /* ELVSS on */
        0xb1, 0x0b,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_ELVSS_OFF[] = {
+static const unsigned short seq_elvss_off[] = {
        /* ELVSS off */
        0xb1, 0x0a,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_STAND_BY_OFF[] = {
+static const unsigned short seq_stand_by_off[] = {
        0x11, COMMAND_ONLY,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_STAND_BY_ON[] = {
+static const unsigned short seq_stand_by_on[] = {
        0x10, COMMAND_ONLY,
 
        ENDDEF, 0x0000
 };
 
-static const unsigned short SEQ_DISPLAY_ON[] = {
+static const unsigned short seq_display_on[] = {
        0x29, COMMAND_ONLY,
 
        ENDDEF, 0x0000
@@ -406,8 +395,9 @@ static int s6e63m0_panel_send_sequence(struct s6e63m0 *lcd,
                        ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
                        if (ret)
                                break;
-               } else
-                       udelay(wbuf[i+1]*1000);
+               } else {
+                       msleep(wbuf[i+1]);
+               }
                i += 2;
        }
 
@@ -457,12 +447,12 @@ static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
 {
        int ret, i;
        const unsigned short *init_seq[] = {
-               SEQ_PANEL_CONDITION_SET,
-               SEQ_DISPLAY_CONDITION_SET,
-               SEQ_GAMMA_SETTING,
-               SEQ_ETC_CONDITION_SET,
-               SEQ_ACL_ON,
-               SEQ_ELVSS_ON,
+               seq_panel_condition_set,
+               seq_display_condition_set,
+               seq_gamma_setting,
+               seq_etc_condition_set,
+               seq_acl_on,
+               seq_elvss_on,
        };
 
        for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
@@ -478,8 +468,8 @@ static int s6e63m0_ldi_enable(struct s6e63m0 *lcd)
 {
        int ret = 0, i;
        const unsigned short *enable_seq[] = {
-               SEQ_STAND_BY_OFF,
-               SEQ_DISPLAY_ON,
+               seq_stand_by_off,
+               seq_display_on,
        };
 
        for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
@@ -495,43 +485,39 @@ static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
 {
        int ret;
 
-       ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON);
+       ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on);
 
        return ret;
 }
 
+static int s6e63m0_power_is_on(int power)
+{
+       return power <= FB_BLANK_NORMAL;
+}
+
 static int s6e63m0_power_on(struct s6e63m0 *lcd)
 {
        int ret = 0;
-       struct lcd_platform_data *pd = NULL;
-       struct backlight_device *bd = NULL;
+       struct lcd_platform_data *pd;
+       struct backlight_device *bd;
 
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL.\n");
-               return -EFAULT;
-       }
-
        bd = lcd->bd;
-       if (!bd) {
-               dev_err(lcd->dev, "backlight device is NULL.\n");
-               return -EFAULT;
-       }
 
        if (!pd->power_on) {
                dev_err(lcd->dev, "power_on is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        } else {
                pd->power_on(lcd->ld, 1);
-               mdelay(pd->power_on_delay);
+               msleep(pd->power_on_delay);
        }
 
        if (!pd->reset) {
                dev_err(lcd->dev, "reset is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        } else {
                pd->reset(lcd->ld);
-               mdelay(pd->reset_delay);
+               msleep(pd->reset_delay);
        }
 
        ret = s6e63m0_ldi_init(lcd);
@@ -558,14 +544,10 @@ static int s6e63m0_power_on(struct s6e63m0 *lcd)
 
 static int s6e63m0_power_off(struct s6e63m0 *lcd)
 {
-       int ret = 0;
-       struct lcd_platform_data *pd = NULL;
+       int ret;
+       struct lcd_platform_data *pd;
 
        pd = lcd->lcd_pd;
-       if (!pd) {
-               dev_err(lcd->dev, "platform data is NULL.\n");
-               return -EFAULT;
-       }
 
        ret = s6e63m0_ldi_disable(lcd);
        if (ret) {
@@ -573,13 +555,9 @@ static int s6e63m0_power_off(struct s6e63m0 *lcd)
                return -EIO;
        }
 
-       mdelay(pd->power_off_delay);
+       msleep(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);
+       pd->power_on(lcd->ld, 0);
 
        return 0;
 }
@@ -588,9 +566,9 @@ static int s6e63m0_power(struct s6e63m0 *lcd, int power)
 {
        int ret = 0;
 
-       if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+       if (s6e63m0_power_is_on(power) && !s6e63m0_power_is_on(lcd->power))
                ret = s6e63m0_power_on(lcd);
-       else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+       else if (!s6e63m0_power_is_on(power) && s6e63m0_power_is_on(lcd->power))
                ret = s6e63m0_power_off(lcd);
 
        if (!ret)
@@ -760,7 +738,7 @@ static int s6e63m0_probe(struct spi_device *spi)
        lcd->lcd_pd = spi->dev.platform_data;
        if (!lcd->lcd_pd) {
                dev_err(&spi->dev, "platform data is NULL.\n");
-               return -EFAULT;
+               return -EINVAL;
        }
 
        ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops);
@@ -788,7 +766,7 @@ static int s6e63m0_probe(struct spi_device *spi)
         * know that.
         */
        lcd->gamma_table_count =
-           sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int));
+           sizeof(gamma_table) / (MAX_GAMMA_LEVEL * sizeof(int *));
 
        ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
        if (ret < 0)
@@ -811,10 +789,11 @@ static int s6e63m0_probe(struct spi_device *spi)
                lcd->power = FB_BLANK_POWERDOWN;
 
                s6e63m0_power(lcd, FB_BLANK_UNBLANK);
-       } else
+       } else {
                lcd->power = FB_BLANK_UNBLANK;
+       }
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
 
        dev_info(&spi->dev, "s6e63m0 panel driver has been probed.\n");
 
@@ -827,7 +806,7 @@ out_lcd_unregister:
 
 static int s6e63m0_remove(struct spi_device *spi)
 {
-       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+       struct s6e63m0 *lcd = spi_get_drvdata(spi);
 
        s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
        device_remove_file(&spi->dev, &dev_attr_gamma_table);
@@ -839,44 +818,26 @@ static int s6e63m0_remove(struct spi_device *spi)
 }
 
 #if defined(CONFIG_PM)
-static unsigned int before_power;
-
 static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
 {
-       int ret = 0;
-       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+       struct s6e63m0 *lcd = spi_get_drvdata(spi);
 
        dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 
-       before_power = lcd->power;
-
        /*
         * when lcd panel is suspend, lcd panel becomes off
         * regardless of status.
         */
-       ret = s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
-
-       return ret;
+       return s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
 }
 
 static int s6e63m0_resume(struct spi_device *spi)
 {
-       int ret = 0;
-       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
-
-       /*
-        * after suspended, if lcd panel status is FB_BLANK_UNBLANK
-        * (at that time, before_power is FB_BLANK_UNBLANK) then
-        * it changes that status to FB_BLANK_POWERDOWN to get lcd on.
-        */
-       if (before_power == FB_BLANK_UNBLANK)
-               lcd->power = FB_BLANK_POWERDOWN;
+       struct s6e63m0 *lcd = spi_get_drvdata(spi);
 
-       dev_dbg(&spi->dev, "before_power = %d\n", before_power);
+       lcd->power = FB_BLANK_POWERDOWN;
 
-       ret = s6e63m0_power(lcd, before_power);
-
-       return ret;
+       return s6e63m0_power(lcd, FB_BLANK_UNBLANK);
 }
 #else
 #define s6e63m0_suspend                NULL
@@ -886,7 +847,7 @@ static int s6e63m0_resume(struct spi_device *spi)
 /* Power down all displays on reboot, poweroff or halt. */
 static void s6e63m0_shutdown(struct spi_device *spi)
 {
-       struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev);
+       struct s6e63m0 *lcd = spi_get_drvdata(spi);
 
        s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
 }
index ad2325f..0016208 100644 (file)
@@ -390,7 +390,7 @@ static int tdo24m_probe(struct spi_device *spi)
        if (IS_ERR(lcd->lcd_dev))
                return PTR_ERR(lcd->lcd_dev);
 
-       dev_set_drvdata(&spi->dev, lcd);
+       spi_set_drvdata(spi, lcd);
        err = tdo24m_power(lcd, FB_BLANK_UNBLANK);
        if (err)
                goto out_unregister;
@@ -404,7 +404,7 @@ out_unregister:
 
 static int tdo24m_remove(struct spi_device *spi)
 {
-       struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+       struct tdo24m *lcd = spi_get_drvdata(spi);
 
        tdo24m_power(lcd, FB_BLANK_POWERDOWN);
        lcd_device_unregister(lcd->lcd_dev);
@@ -415,14 +415,14 @@ static int tdo24m_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
 {
-       struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+       struct tdo24m *lcd = spi_get_drvdata(spi);
 
        return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
 }
 
 static int tdo24m_resume(struct spi_device *spi)
 {
-       struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+       struct tdo24m *lcd = spi_get_drvdata(spi);
 
        return tdo24m_power(lcd, FB_BLANK_UNBLANK);
 }
@@ -434,7 +434,7 @@ static int tdo24m_resume(struct spi_device *spi)
 /* Power down all displays on reboot, poweroff or halt */
 static void tdo24m_shutdown(struct spi_device *spi)
 {
-       struct tdo24m *lcd = dev_get_drvdata(&spi->dev);
+       struct tdo24m *lcd = spi_get_drvdata(spi);
 
        tdo24m_power(lcd, FB_BLANK_POWERDOWN);
 }
index 588682c..2326fa8 100644 (file)
@@ -54,7 +54,7 @@ static void tosa_bl_set_backlight(struct tosa_bl_data *data, int brightness)
 static int tosa_bl_update_status(struct backlight_device *dev)
 {
        struct backlight_properties *props = &dev->props;
-       struct tosa_bl_data *data = dev_get_drvdata(&dev->dev);
+       struct tosa_bl_data *data = bl_get_data(dev);
        int power = max(props->power, props->fb_blank);
        int brightness = props->brightness;
 
index 96bae94..666fe25 100644 (file)
@@ -193,7 +193,7 @@ static int tosa_lcd_probe(struct spi_device *spi)
                return ret;
 
        data->spi = spi;
-       dev_set_drvdata(&spi->dev, data);
+       spi_set_drvdata(spi, data);
 
        ret = devm_gpio_request_one(&spi->dev, TOSA_GPIO_TG_ON,
                                GPIOF_OUT_INIT_LOW, "tg #pwr");
@@ -220,13 +220,13 @@ static int tosa_lcd_probe(struct spi_device *spi)
 err_register:
        tosa_lcd_tg_off(data);
 err_gpio_tg:
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        return ret;
 }
 
 static int tosa_lcd_remove(struct spi_device *spi)
 {
-       struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
+       struct tosa_lcd_data *data = spi_get_drvdata(spi);
 
        lcd_device_unregister(data->lcd);
 
@@ -235,7 +235,7 @@ static int tosa_lcd_remove(struct spi_device *spi)
 
        tosa_lcd_tg_off(data);
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
 
        return 0;
 }
@@ -243,7 +243,7 @@ static int tosa_lcd_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state)
 {
-       struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
+       struct tosa_lcd_data *data = spi_get_drvdata(spi);
 
        tosa_lcd_tg_off(data);
 
@@ -252,7 +252,7 @@ static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state)
 
 static int tosa_lcd_resume(struct spi_device *spi)
 {
-       struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev);
+       struct tosa_lcd_data *data = spi_get_drvdata(spi);
 
        tosa_lcd_tg_init(data);
        if (POWER_IS_ON(data->lcd_power))
index 45e81b4..84d582f 100644 (file)
@@ -208,12 +208,11 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd,
 #ifdef CONFIG_PM
 static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state)
 {
-       return ili9320_suspend(dev_get_drvdata(&spi->dev), state);
+       return ili9320_suspend(spi_get_drvdata(spi), state);
 }
-
 static int vgg2432a4_resume(struct spi_device *spi)
 {
-       return ili9320_resume(dev_get_drvdata(&spi->dev));
+       return ili9320_resume(spi_get_drvdata(spi));
 }
 #else
 #define vgg2432a4_suspend      NULL
@@ -242,12 +241,12 @@ static int vgg2432a4_probe(struct spi_device *spi)
 
 static int vgg2432a4_remove(struct spi_device *spi)
 {
-       return ili9320_remove(dev_get_drvdata(&spi->dev));
+       return ili9320_remove(spi_get_drvdata(spi));
 }
 
 static void vgg2432a4_shutdown(struct spi_device *spi)
 {
-       ili9320_shutdown(dev_get_drvdata(&spi->dev));
+       ili9320_shutdown(spi_get_drvdata(spi));
 }
 
 static struct spi_driver vgg2432a4_driver = {
index fdefa8f..f8a61e2 100644 (file)
@@ -1242,8 +1242,16 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
        if (!height || !width)
                return;
 
-       if (sy < vc->vc_top && vc->vc_top == logo_lines)
+       if (sy < vc->vc_top && vc->vc_top == logo_lines) {
                vc->vc_top = 0;
+               /*
+                * If the font dimensions are not an integral of the display
+                * dimensions then the ops->clear below won't end up clearing
+                * the margins.  Call clear_margins here in case the logo
+                * bitmap stretched into the margin area.
+                */
+               fbcon_clear_margins(vc, 0);
+       }
 
        /* Split blits that cross physical y_wrap boundary */
 
index 2ed9776..de9d4da 100644 (file)
@@ -965,10 +965,11 @@ static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
 
 static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
 {
-       struct device_node *dp_phy_node;
+       struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
        u32 phy_base;
+       int ret = 0;
 
-       dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy");
+       dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
        if (!dp_phy_node) {
                dev_err(dp->dev, "could not find dptx-phy node\n");
                return -ENODEV;
@@ -976,22 +977,28 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
 
        if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
                dev_err(dp->dev, "faild to get reg for dptx-phy\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
                                &dp->enable_mask)) {
                dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err;
        }
 
        dp->phy_addr = ioremap(phy_base, SZ_4);
        if (!dp->phy_addr) {
                dev_err(dp->dev, "failed to ioremap dp-phy\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err;
        }
 
-       return 0;
+err:
+       of_node_put(dp_phy_node);
+
+       return ret;
 }
 
 static void exynos_dp_phy_init(struct exynos_dp_device *dp)
@@ -1117,8 +1124,6 @@ static int exynos_dp_remove(struct platform_device *pdev)
        struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
        struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
-       disable_irq(dp->irq);
-
        flush_work(&dp->hotplug_work);
 
        if (pdev->dev.of_node) {
@@ -1141,6 +1146,8 @@ static int exynos_dp_suspend(struct device *dev)
        struct exynos_dp_platdata *pdata = dev->platform_data;
        struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
+       disable_irq(dp->irq);
+
        flush_work(&dp->hotplug_work);
 
        if (dev->of_node) {
index 4a17cdc..fac7df6 100644 (file)
@@ -338,7 +338,8 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
        struct mipi_dsim_ddi *dsim_ddi;
        int ret = -EINVAL;
 
-       dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
+       dsim = devm_kzalloc(&pdev->dev, sizeof(struct mipi_dsim_device),
+                               GFP_KERNEL);
        if (!dsim) {
                dev_err(&pdev->dev, "failed to allocate dsim object.\n");
                return -ENOMEM;
@@ -352,13 +353,13 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
        dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
        if (dsim_pd == NULL) {
                dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
-               goto err_clock_get;
+               return -EINVAL;
        }
        /* get mipi_dsim_config. */
        dsim_config = dsim_pd->dsim_config;
        if (dsim_config == NULL) {
                dev_err(&pdev->dev, "failed to get dsim config data.\n");
-               goto err_clock_get;
+               return -EINVAL;
        }
 
        dsim->dsim_config = dsim_config;
@@ -366,41 +367,28 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 
        mutex_init(&dsim->lock);
 
-       ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies);
+       ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies),
+                                       supplies);
        if (ret) {
                dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
-               goto err_clock_get;
+               return ret;
        }
 
-       dsim->clock = clk_get(&pdev->dev, "dsim0");
+       dsim->clock = devm_clk_get(&pdev->dev, "dsim0");
        if (IS_ERR(dsim->clock)) {
                dev_err(&pdev->dev, "failed to get dsim clock source\n");
-               ret = -ENODEV;
-               goto err_clock_get;
+               return -ENODEV;
        }
 
        clk_enable(dsim->clock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get io memory region\n");
-               ret = -ENODEV;
-               goto err_platform_get;
-       }
-
-       dsim->res = request_mem_region(res->start, resource_size(res),
-                                       dev_name(&pdev->dev));
-       if (!dsim->res) {
-               dev_err(&pdev->dev, "failed to request io memory region\n");
-               ret = -ENOMEM;
-               goto err_mem_region;
-       }
 
-       dsim->reg_base = ioremap(res->start, resource_size(res));
+       dsim->reg_base = devm_request_and_ioremap(&pdev->dev, res);
        if (!dsim->reg_base) {
                dev_err(&pdev->dev, "failed to remap io region\n");
                ret = -ENOMEM;
-               goto err_ioremap;
+               goto error;
        }
 
        mutex_init(&dsim->lock);
@@ -410,26 +398,27 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
        if (!dsim_ddi) {
                dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
                ret = -EINVAL;
-               goto err_bind;
+               goto error;
        }
 
        dsim->irq = platform_get_irq(pdev, 0);
-       if (dsim->irq < 0) {
+       if (IS_ERR_VALUE(dsim->irq)) {
                dev_err(&pdev->dev, "failed to request dsim irq resource\n");
                ret = -EINVAL;
-               goto err_platform_get_irq;
+               goto error;
        }
 
        init_completion(&dsim_wr_comp);
        init_completion(&dsim_rd_comp);
        platform_set_drvdata(pdev, dsim);
 
-       ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler,
+       ret = devm_request_irq(&pdev->dev, dsim->irq,
+                       exynos_mipi_dsi_interrupt_handler,
                        IRQF_SHARED, dev_name(&pdev->dev), dsim);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to request dsim irq\n");
                ret = -EINVAL;
-               goto err_bind;
+               goto error;
        }
 
        /* enable interrupts */
@@ -471,22 +460,8 @@ done:
 
        return 0;
 
-err_bind:
-       iounmap(dsim->reg_base);
-
-err_ioremap:
-       release_mem_region(dsim->res->start, resource_size(dsim->res));
-
-err_mem_region:
-       release_resource(dsim->res);
-
-err_platform_get:
+error:
        clk_disable(dsim->clock);
-       clk_put(dsim->clock);
-err_clock_get:
-       kfree(dsim);
-
-err_platform_get_irq:
        return ret;
 }
 
@@ -496,13 +471,7 @@ static int exynos_mipi_dsi_remove(struct platform_device *pdev)
        struct mipi_dsim_ddi *dsim_ddi, *next;
        struct mipi_dsim_lcd_driver *dsim_lcd_drv;
 
-       iounmap(dsim->reg_base);
-
        clk_disable(dsim->clock);
-       clk_put(dsim->clock);
-
-       release_resource(dsim->res);
-       release_mem_region(dsim->res->start, resource_size(dsim->res));
 
        list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
                if (dsim_ddi) {
@@ -518,9 +487,6 @@ static int exynos_mipi_dsi_remove(struct platform_device *pdev)
                }
        }
 
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-       kfree(dsim);
-
        return 0;
 }
 
index 05d080b..ca26024 100644 (file)
@@ -776,7 +776,7 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
        int ret;
        u8 mtp_id[3] = {0, };
 
-       lcd = kzalloc(sizeof(struct s6e8ax0), GFP_KERNEL);
+       lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct s6e8ax0), GFP_KERNEL);
        if (!lcd) {
                dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
                return -ENOMEM;
@@ -788,18 +788,17 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
 
        mutex_init(&lcd->lock);
 
-       ret = regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
+       ret = devm_regulator_bulk_get(lcd->dev, ARRAY_SIZE(supplies), supplies);
        if (ret) {
                dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
-               goto err_lcd_register;
+               return ret;
        }
 
        lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
                        &s6e8ax0_lcd_ops);
        if (IS_ERR(lcd->ld)) {
                dev_err(lcd->dev, "failed to register lcd ops.\n");
-               ret = PTR_ERR(lcd->ld);
-               goto err_lcd_register;
+               return PTR_ERR(lcd->ld);
        }
 
        lcd->bd = backlight_device_register("s6e8ax0-bl", lcd->dev, lcd,
@@ -838,11 +837,6 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
 
 err_backlight_register:
        lcd_device_unregister(lcd->ld);
-
-err_lcd_register:
-       regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-       kfree(lcd);
-
        return ret;
 }
 
diff --git a/drivers/video/goldfishfb.c b/drivers/video/goldfishfb.c
new file mode 100644 (file)
index 0000000..489abb3
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (C) 2012 Intel, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+enum {
+       FB_GET_WIDTH        = 0x00,
+       FB_GET_HEIGHT       = 0x04,
+       FB_INT_STATUS       = 0x08,
+       FB_INT_ENABLE       = 0x0c,
+       FB_SET_BASE         = 0x10,
+       FB_SET_ROTATION     = 0x14,
+       FB_SET_BLANK        = 0x18,
+       FB_GET_PHYS_WIDTH   = 0x1c,
+       FB_GET_PHYS_HEIGHT  = 0x20,
+
+       FB_INT_VSYNC             = 1U << 0,
+       FB_INT_BASE_UPDATE_DONE  = 1U << 1
+};
+
+struct goldfish_fb {
+       void __iomem *reg_base;
+       int irq;
+       spinlock_t lock;
+       wait_queue_head_t wait;
+       int base_update_count;
+       int rotation;
+       struct fb_info fb;
+       u32 cmap[16];
+};
+
+static irqreturn_t goldfish_fb_interrupt(int irq, void *dev_id)
+{
+       unsigned long irq_flags;
+       struct goldfish_fb *fb = dev_id;
+       u32 status;
+
+       spin_lock_irqsave(&fb->lock, irq_flags);
+       status = readl(fb->reg_base + FB_INT_STATUS);
+       if (status & FB_INT_BASE_UPDATE_DONE) {
+               fb->base_update_count++;
+               wake_up(&fb->wait);
+       }
+       spin_unlock_irqrestore(&fb->lock, irq_flags);
+       return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
+{
+       unsigned int mask = (1 << bf->length) - 1;
+
+       return (val >> (16 - bf->length) & mask) << bf->offset;
+}
+
+static int
+goldfish_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+                unsigned int blue, unsigned int transp, struct fb_info *info)
+{
+       struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+
+       if (regno < 16) {
+               fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
+                                 convert_bitfield(blue, &fb->fb.var.blue) |
+                                 convert_bitfield(green, &fb->fb.var.green) |
+                                 convert_bitfield(red, &fb->fb.var.red);
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+static int goldfish_fb_check_var(struct fb_var_screeninfo *var,
+                                                       struct fb_info *info)
+{
+       if ((var->rotate & 1) != (info->var.rotate & 1)) {
+               if ((var->xres != info->var.yres) ||
+                               (var->yres != info->var.xres) ||
+                               (var->xres_virtual != info->var.yres) ||
+                               (var->yres_virtual > info->var.xres * 2) ||
+                               (var->yres_virtual < info->var.xres)) {
+                       return -EINVAL;
+               }
+       } else {
+               if ((var->xres != info->var.xres) ||
+                  (var->yres != info->var.yres) ||
+                  (var->xres_virtual != info->var.xres) ||
+                  (var->yres_virtual > info->var.yres * 2) ||
+                  (var->yres_virtual < info->var.yres)) {
+                       return -EINVAL;
+               }
+       }
+       if ((var->xoffset != info->var.xoffset) ||
+                       (var->bits_per_pixel != info->var.bits_per_pixel) ||
+                       (var->grayscale != info->var.grayscale)) {
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int goldfish_fb_set_par(struct fb_info *info)
+{
+       struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+       if (fb->rotation != fb->fb.var.rotate) {
+               info->fix.line_length = info->var.xres * 2;
+               fb->rotation = fb->fb.var.rotate;
+               writel(fb->rotation, fb->reg_base + FB_SET_ROTATION);
+       }
+       return 0;
+}
+
+
+static int goldfish_fb_pan_display(struct fb_var_screeninfo *var,
+                                                       struct fb_info *info)
+{
+       unsigned long irq_flags;
+       int base_update_count;
+       struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+
+       spin_lock_irqsave(&fb->lock, irq_flags);
+       base_update_count = fb->base_update_count;
+       writel(fb->fb.fix.smem_start + fb->fb.var.xres * 2 * var->yoffset,
+                                               fb->reg_base + FB_SET_BASE);
+       spin_unlock_irqrestore(&fb->lock, irq_flags);
+       wait_event_timeout(fb->wait,
+                       fb->base_update_count != base_update_count, HZ / 15);
+       if (fb->base_update_count == base_update_count)
+               pr_err("goldfish_fb_pan_display: timeout wating for base update\n");
+       return 0;
+}
+
+static int goldfish_fb_blank(int blank, struct fb_info *info)
+{
+       struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb);
+       switch (blank) {
+       case FB_BLANK_NORMAL:
+               writel(1, fb->reg_base + FB_SET_BLANK);
+               break;
+       case FB_BLANK_UNBLANK:
+               writel(0, fb->reg_base + FB_SET_BLANK);
+               break;
+       }
+       return 0;
+}
+
+static struct fb_ops goldfish_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = goldfish_fb_check_var,
+       .fb_set_par     = goldfish_fb_set_par,
+       .fb_setcolreg   = goldfish_fb_setcolreg,
+       .fb_pan_display = goldfish_fb_pan_display,
+       .fb_blank       = goldfish_fb_blank,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+
+static int goldfish_fb_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct resource *r;
+       struct goldfish_fb *fb;
+       size_t framesize;
+       u32 width, height;
+       dma_addr_t fbpaddr;
+
+       fb = kzalloc(sizeof(*fb), GFP_KERNEL);
+       if (fb == NULL) {
+               ret = -ENOMEM;
+               goto err_fb_alloc_failed;
+       }
+       spin_lock_init(&fb->lock);
+       init_waitqueue_head(&fb->wait);
+       platform_set_drvdata(pdev, fb);
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (r == NULL) {
+               ret = -ENODEV;
+               goto err_no_io_base;
+       }
+       fb->reg_base = ioremap(r->start, PAGE_SIZE);
+       if (fb->reg_base == NULL) {
+               ret = -ENOMEM;
+               goto err_no_io_base;
+       }
+
+       fb->irq = platform_get_irq(pdev, 0);
+       if (fb->irq <= 0) {
+               ret = -ENODEV;
+               goto err_no_irq;
+       }
+
+       width = readl(fb->reg_base + FB_GET_WIDTH);
+       height = readl(fb->reg_base + FB_GET_HEIGHT);
+
+       fb->fb.fbops            = &goldfish_fb_ops;
+       fb->fb.flags            = FBINFO_FLAG_DEFAULT;
+       fb->fb.pseudo_palette   = fb->cmap;
+       fb->fb.fix.type         = FB_TYPE_PACKED_PIXELS;
+       fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+       fb->fb.fix.line_length = width * 2;
+       fb->fb.fix.accel        = FB_ACCEL_NONE;
+       fb->fb.fix.ypanstep = 1;
+
+       fb->fb.var.xres         = width;
+       fb->fb.var.yres         = height;
+       fb->fb.var.xres_virtual = width;
+       fb->fb.var.yres_virtual = height * 2;
+       fb->fb.var.bits_per_pixel = 16;
+       fb->fb.var.activate     = FB_ACTIVATE_NOW;
+       fb->fb.var.height       = readl(fb->reg_base + FB_GET_PHYS_HEIGHT);
+       fb->fb.var.width        = readl(fb->reg_base + FB_GET_PHYS_WIDTH);
+       fb->fb.var.pixclock     = 10000;
+
+       fb->fb.var.red.offset = 11;
+       fb->fb.var.red.length = 5;
+       fb->fb.var.green.offset = 5;
+       fb->fb.var.green.length = 6;
+       fb->fb.var.blue.offset = 0;
+       fb->fb.var.blue.length = 5;
+
+       framesize = width * height * 2 * 2;
+       fb->fb.screen_base = (char __force __iomem *)dma_alloc_coherent(
+                                               &pdev->dev, framesize,
+                                               &fbpaddr, GFP_KERNEL);
+       pr_debug("allocating frame buffer %d * %d, got %p\n",
+                                       width, height, fb->fb.screen_base);
+       if (fb->fb.screen_base == NULL) {
+               ret = -ENOMEM;
+               goto err_alloc_screen_base_failed;
+       }
+       fb->fb.fix.smem_start = fbpaddr;
+       fb->fb.fix.smem_len = framesize;
+
+       ret = fb_set_var(&fb->fb, &fb->fb.var);
+       if (ret)
+               goto err_fb_set_var_failed;
+
+       ret = request_irq(fb->irq, goldfish_fb_interrupt, IRQF_SHARED,
+                                                       pdev->name, fb);
+       if (ret)
+               goto err_request_irq_failed;
+
+       writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB_INT_ENABLE);
+       goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */
+
+       ret = register_framebuffer(&fb->fb);
+       if (ret)
+               goto err_register_framebuffer_failed;
+       return 0;
+
+err_register_framebuffer_failed:
+       free_irq(fb->irq, fb);
+err_request_irq_failed:
+err_fb_set_var_failed:
+       dma_free_coherent(&pdev->dev, framesize,
+                               (void *)fb->fb.screen_base,
+                               fb->fb.fix.smem_start);
+err_alloc_screen_base_failed:
+err_no_irq:
+       iounmap(fb->reg_base);
+err_no_io_base:
+       kfree(fb);
+err_fb_alloc_failed:
+       return ret;
+}
+
+static int goldfish_fb_remove(struct platform_device *pdev)
+{
+       size_t framesize;
+       struct goldfish_fb *fb = platform_get_drvdata(pdev);
+
+       framesize = fb->fb.var.xres_virtual * fb->fb.var.yres_virtual * 2;
+       unregister_framebuffer(&fb->fb);
+       free_irq(fb->irq, fb);
+
+       dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
+                                               fb->fb.fix.smem_start);
+       iounmap(fb->reg_base);
+       return 0;
+}
+
+
+static struct platform_driver goldfish_fb_driver = {
+       .probe          = goldfish_fb_probe,
+       .remove         = goldfish_fb_remove,
+       .driver = {
+               .name = "goldfish_fb"
+       }
+};
+
+module_platform_driver(goldfish_fb_driver);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/mmp/Kconfig b/drivers/video/mmp/Kconfig
new file mode 100644 (file)
index 0000000..e9ea39e
--- /dev/null
@@ -0,0 +1,11 @@
+menuconfig MMP_DISP
+        tristate "Marvell MMP Display Subsystem support"
+        depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+        help
+         Marvell Display Subsystem support.
+
+if MMP_DISP
+source "drivers/video/mmp/hw/Kconfig"
+source "drivers/video/mmp/panel/Kconfig"
+source "drivers/video/mmp/fb/Kconfig"
+endif
diff --git a/drivers/video/mmp/Makefile b/drivers/video/mmp/Makefile
new file mode 100644 (file)
index 0000000..a014cb3
--- /dev/null
@@ -0,0 +1 @@
+obj-y += core.o hw/ panel/ fb/
diff --git a/drivers/video/mmp/core.c b/drivers/video/mmp/core.c
new file mode 100644 (file)
index 0000000..9ed8341
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * linux/drivers/video/mmp/common.c
+ * This driver is a common framework for Marvell Display Controller
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <video/mmp_disp.h>
+
+static struct mmp_overlay *path_get_overlay(struct mmp_path *path,
+               int overlay_id)
+{
+       if (path && overlay_id < path->overlay_num)
+               return &path->overlays[overlay_id];
+       return 0;
+}
+
+static int path_check_status(struct mmp_path *path)
+{
+       int i;
+       for (i = 0; i < path->overlay_num; i++)
+               if (path->overlays[i].status)
+                       return 1;
+
+       return 0;
+}
+
+/*
+ * Get modelist write pointer of modelist.
+ * It also returns modelist number
+ * this function fetches modelist from phy/panel:
+ *   for HDMI/parallel or dsi to hdmi cases, get from phy
+ *   or get from panel
+ */
+static int path_get_modelist(struct mmp_path *path,
+               struct mmp_mode **modelist)
+{
+       BUG_ON(!path || !modelist);
+
+       if (path->panel && path->panel->get_modelist)
+               return path->panel->get_modelist(path->panel, modelist);
+
+       return 0;
+}
+
+/*
+ * panel list is used to pair panel/path when path/panel registered
+ * path list is used for both buffer driver and platdriver
+ * plat driver do path register/unregister
+ * panel driver do panel register/unregister
+ * buffer driver get registered path
+ */
+static LIST_HEAD(panel_list);
+static LIST_HEAD(path_list);
+static DEFINE_MUTEX(disp_lock);
+
+/*
+ * mmp_register_panel - register panel to panel_list and connect to path
+ * @p: panel to be registered
+ *
+ * this function provides interface for panel drivers to register panel
+ * to panel_list and connect to path which matchs panel->plat_path_name.
+ * no error returns when no matching path is found as path register after
+ * panel register is permitted.
+ */
+void mmp_register_panel(struct mmp_panel *panel)
+{
+       struct mmp_path *path;
+
+       mutex_lock(&disp_lock);
+
+       /* add */
+       list_add_tail(&panel->node, &panel_list);
+
+       /* try to register to path */
+       list_for_each_entry(path, &path_list, node) {
+               if (!strcmp(panel->plat_path_name, path->name)) {
+                       dev_info(panel->dev, "connect to path %s\n",
+                               path->name);
+                       path->panel = panel;
+                       break;
+               }
+       }
+
+       mutex_unlock(&disp_lock);
+}
+EXPORT_SYMBOL_GPL(mmp_register_panel);
+
+/*
+ * mmp_unregister_panel - unregister panel from panel_list and disconnect
+ * @p: panel to be unregistered
+ *
+ * this function provides interface for panel drivers to unregister panel
+ * from panel_list and disconnect from path.
+ */
+void mmp_unregister_panel(struct mmp_panel *panel)
+{
+       struct mmp_path *path;
+
+       mutex_lock(&disp_lock);
+       list_del(&panel->node);
+
+       list_for_each_entry(path, &path_list, node) {
+               if (path->panel && path->panel == panel) {
+                       dev_info(panel->dev, "disconnect from path %s\n",
+                               path->name);
+                       path->panel = NULL;
+                       break;
+               }
+       }
+       mutex_unlock(&disp_lock);
+}
+EXPORT_SYMBOL_GPL(mmp_unregister_panel);
+
+/*
+ * mmp_get_path - get path by name
+ * @p: path name
+ *
+ * this function checks path name in path_list and return matching path
+ * return NULL if no matching path
+ */
+struct mmp_path *mmp_get_path(const char *name)
+{
+       struct mmp_path *path;
+       int found = 0;
+
+       mutex_lock(&disp_lock);
+       list_for_each_entry(path, &path_list, node) {
+               if (!strcmp(name, path->name)) {
+                       found = 1;
+                       break;
+               }
+       }
+       mutex_unlock(&disp_lock);
+
+       return found ? path : NULL;
+}
+EXPORT_SYMBOL_GPL(mmp_get_path);
+
+/*
+ * mmp_register_path - init and register path by path_info
+ * @p: path info provided by display controller
+ *
+ * this function init by path info and register path to path_list
+ * this function also try to connect path with panel by name
+ */
+struct mmp_path *mmp_register_path(struct mmp_path_info *info)
+{
+       int i;
+       size_t size;
+       struct mmp_path *path = NULL;
+       struct mmp_panel *panel;
+
+       size = sizeof(struct mmp_path)
+               + sizeof(struct mmp_overlay) * info->overlay_num;
+       path = kzalloc(size, GFP_KERNEL);
+       if (!path)
+               goto failed;
+
+       /* path set */
+       mutex_init(&path->access_ok);
+       path->dev = info->dev;
+       path->id = info->id;
+       path->name = info->name;
+       path->output_type = info->output_type;
+       path->overlay_num = info->overlay_num;
+       path->plat_data = info->plat_data;
+       path->ops.set_mode = info->set_mode;
+
+       mutex_lock(&disp_lock);
+       /* get panel */
+       list_for_each_entry(panel, &panel_list, node) {
+               if (!strcmp(info->name, panel->plat_path_name)) {
+                       dev_info(path->dev, "get panel %s\n", panel->name);
+                       path->panel = panel;
+                       break;
+               }
+       }
+
+       dev_info(path->dev, "register %s, overlay_num %d\n",
+                       path->name, path->overlay_num);
+
+       /* default op set: if already set by driver, never cover it */
+       if (!path->ops.check_status)
+               path->ops.check_status = path_check_status;
+       if (!path->ops.get_overlay)
+               path->ops.get_overlay = path_get_overlay;
+       if (!path->ops.get_modelist)
+               path->ops.get_modelist = path_get_modelist;
+
+       /* step3: init overlays */
+       for (i = 0; i < path->overlay_num; i++) {
+               path->overlays[i].path = path;
+               path->overlays[i].id = i;
+               mutex_init(&path->overlays[i].access_ok);
+               path->overlays[i].ops = info->overlay_ops;
+       }
+
+       /* add to pathlist */
+       list_add_tail(&path->node, &path_list);
+
+       mutex_unlock(&disp_lock);
+       return path;
+
+failed:
+       kfree(path);
+       mutex_unlock(&disp_lock);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(mmp_register_path);
+
+/*
+ * mmp_unregister_path - unregister and destory path
+ * @p: path to be destoried.
+ *
+ * this function registers path and destorys it.
+ */
+void mmp_unregister_path(struct mmp_path *path)
+{
+       int i;
+
+       if (!path)
+               return;
+
+       mutex_lock(&disp_lock);
+       /* del from pathlist */
+       list_del(&path->node);
+
+       /* deinit overlays */
+       for (i = 0; i < path->overlay_num; i++)
+               mutex_destroy(&path->overlays[i].access_ok);
+
+       mutex_destroy(&path->access_ok);
+
+       kfree(path);
+       mutex_unlock(&disp_lock);
+
+       dev_info(path->dev, "de-register %s\n", path->name);
+}
+EXPORT_SYMBOL_GPL(mmp_unregister_path);
diff --git a/drivers/video/mmp/fb/Kconfig b/drivers/video/mmp/fb/Kconfig
new file mode 100644 (file)
index 0000000..9b0141f
--- /dev/null
@@ -0,0 +1,13 @@
+if MMP_DISP
+
+config MMP_FB
+       bool "fb driver for Marvell MMP Display Subsystem"
+       depends on FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       default y
+       help
+               fb driver for Marvell MMP Display Subsystem
+
+endif
diff --git a/drivers/video/mmp/fb/Makefile b/drivers/video/mmp/fb/Makefile
new file mode 100644 (file)
index 0000000..709fd1f
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_MMP_FB)  += mmpfb.o
diff --git a/drivers/video/mmp/fb/mmpfb.c b/drivers/video/mmp/fb/mmpfb.c
new file mode 100644 (file)
index 0000000..6d1fa96
--- /dev/null
@@ -0,0 +1,685 @@
+/*
+ * linux/drivers/video/mmp/fb/mmpfb.c
+ * Framebuffer driver for Marvell Display controller.
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include "mmpfb.h"
+
+static int var_to_pixfmt(struct fb_var_screeninfo *var)
+{
+       /*
+        * Pseudocolor mode?
+        */
+       if (var->bits_per_pixel == 8)
+               return PIXFMT_PSEUDOCOLOR;
+
+       /*
+        * Check for YUV422PLANAR.
+        */
+       if (var->bits_per_pixel == 16 && var->red.length == 8 &&
+                       var->green.length == 4 && var->blue.length == 4) {
+               if (var->green.offset >= var->blue.offset)
+                       return PIXFMT_YUV422P;
+               else
+                       return PIXFMT_YVU422P;
+       }
+
+       /*
+        * Check for YUV420PLANAR.
+        */
+       if (var->bits_per_pixel == 12 && var->red.length == 8 &&
+                       var->green.length == 2 && var->blue.length == 2) {
+               if (var->green.offset >= var->blue.offset)
+                       return PIXFMT_YUV420P;
+               else
+                       return PIXFMT_YVU420P;
+       }
+
+       /*
+        * Check for YUV422PACK.
+        */
+       if (var->bits_per_pixel == 16 && var->red.length == 16 &&
+                       var->green.length == 16 && var->blue.length == 16) {
+               if (var->red.offset == 0)
+                       return PIXFMT_YUYV;
+               else if (var->green.offset >= var->blue.offset)
+                       return PIXFMT_UYVY;
+               else
+                       return PIXFMT_VYUY;
+       }
+
+       /*
+        * Check for 565/1555.
+        */
+       if (var->bits_per_pixel == 16 && var->red.length <= 5 &&
+                       var->green.length <= 6 && var->blue.length <= 5) {
+               if (var->transp.length == 0) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIXFMT_RGB565;
+                       else
+                               return PIXFMT_BGR565;
+               }
+       }
+
+       /*
+        * Check for 888/A888.
+        */
+       if (var->bits_per_pixel <= 32 && var->red.length <= 8 &&
+                       var->green.length <= 8 && var->blue.length <= 8) {
+               if (var->bits_per_pixel == 24 && var->transp.length == 0) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIXFMT_RGB888PACK;
+                       else
+                               return PIXFMT_BGR888PACK;
+               }
+
+               if (var->bits_per_pixel == 32 && var->transp.offset == 24) {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIXFMT_RGBA888;
+                       else
+                               return PIXFMT_BGRA888;
+               } else {
+                       if (var->red.offset >= var->blue.offset)
+                               return PIXFMT_RGB888UNPACK;
+                       else
+                               return PIXFMT_BGR888UNPACK;
+               }
+
+               /* fall through */
+       }
+
+       return -EINVAL;
+}
+
+static void pixfmt_to_var(struct fb_var_screeninfo *var, int pix_fmt)
+{
+       switch (pix_fmt) {
+       case PIXFMT_RGB565:
+               var->bits_per_pixel = 16;
+               var->red.offset = 11;   var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 6;
+               var->blue.offset = 0;   var->blue.length = 5;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_BGR565:
+               var->bits_per_pixel = 16;
+               var->red.offset = 0;    var->red.length = 5;
+               var->green.offset = 5;   var->green.length = 6;
+               var->blue.offset = 11;  var->blue.length = 5;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_RGB888UNPACK:
+               var->bits_per_pixel = 32;
+               var->red.offset = 16;   var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 0;   var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_BGR888UNPACK:
+               var->bits_per_pixel = 32;
+               var->red.offset = 0;    var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 16;  var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_RGBA888:
+               var->bits_per_pixel = 32;
+               var->red.offset = 16;   var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 0;   var->blue.length = 8;
+               var->transp.offset = 24; var->transp.length = 8;
+               break;
+       case PIXFMT_BGRA888:
+               var->bits_per_pixel = 32;
+               var->red.offset = 0;    var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 16;  var->blue.length = 8;
+               var->transp.offset = 24; var->transp.length = 8;
+               break;
+       case PIXFMT_RGB888PACK:
+               var->bits_per_pixel = 24;
+               var->red.offset = 16;   var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 0;   var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_BGR888PACK:
+               var->bits_per_pixel = 24;
+               var->red.offset = 0;    var->red.length = 8;
+               var->green.offset = 8;   var->green.length = 8;
+               var->blue.offset = 16;  var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_YUV420P:
+               var->bits_per_pixel = 12;
+               var->red.offset = 4;     var->red.length = 8;
+               var->green.offset = 2;   var->green.length = 2;
+               var->blue.offset = 0;   var->blue.length = 2;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_YVU420P:
+               var->bits_per_pixel = 12;
+               var->red.offset = 4;     var->red.length = 8;
+               var->green.offset = 0;   var->green.length = 2;
+               var->blue.offset = 2;   var->blue.length = 2;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_YUV422P:
+               var->bits_per_pixel = 16;
+               var->red.offset = 8;     var->red.length = 8;
+               var->green.offset = 4;   var->green.length = 4;
+               var->blue.offset = 0;   var->blue.length = 4;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_YVU422P:
+               var->bits_per_pixel = 16;
+               var->red.offset = 8;     var->red.length = 8;
+               var->green.offset = 0;   var->green.length = 4;
+               var->blue.offset = 4;   var->blue.length = 4;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_UYVY:
+               var->bits_per_pixel = 16;
+               var->red.offset = 8;     var->red.length = 16;
+               var->green.offset = 4;   var->green.length = 16;
+               var->blue.offset = 0;   var->blue.length = 16;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_VYUY:
+               var->bits_per_pixel = 16;
+               var->red.offset = 8;     var->red.length = 16;
+               var->green.offset = 0;   var->green.length = 16;
+               var->blue.offset = 4;   var->blue.length = 16;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_YUYV:
+               var->bits_per_pixel = 16;
+               var->red.offset = 0;     var->red.length = 16;
+               var->green.offset = 4;   var->green.length = 16;
+               var->blue.offset = 8;   var->blue.length = 16;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       case PIXFMT_PSEUDOCOLOR:
+               var->bits_per_pixel = 8;
+               var->red.offset = 0;     var->red.length = 8;
+               var->green.offset = 0;   var->green.length = 8;
+               var->blue.offset = 0;   var->blue.length = 8;
+               var->transp.offset = 0;  var->transp.length = 0;
+               break;
+       }
+}
+
+/*
+ * fb framework has its limitation:
+ * 1. input color/output color is not seprated
+ * 2. fb_videomode not include output color
+ * so for fb usage, we keep a output format which is not changed
+ *  then it's added for mmpmode
+ */
+static void fbmode_to_mmpmode(struct mmp_mode *mode,
+               struct fb_videomode *videomode, int output_fmt)
+{
+       u64 div_result = 1000000000000ll;
+       mode->name = videomode->name;
+       mode->refresh = videomode->refresh;
+       mode->xres = videomode->xres;
+       mode->yres = videomode->yres;
+
+       do_div(div_result, videomode->pixclock);
+       mode->pixclock_freq = (u32)div_result;
+
+       mode->left_margin = videomode->left_margin;
+       mode->right_margin = videomode->right_margin;
+       mode->upper_margin = videomode->upper_margin;
+       mode->lower_margin = videomode->lower_margin;
+       mode->hsync_len = videomode->hsync_len;
+       mode->vsync_len = videomode->vsync_len;
+       mode->hsync_invert = !!(videomode->sync & FB_SYNC_HOR_HIGH_ACT);
+       mode->vsync_invert = !!(videomode->sync & FB_SYNC_VERT_HIGH_ACT);
+       /* no defined flag in fb, use vmode>>3*/
+       mode->invert_pixclock = !!(videomode->vmode & 8);
+       mode->pix_fmt_out = output_fmt;
+}
+
+static void mmpmode_to_fbmode(struct fb_videomode *videomode,
+               struct mmp_mode *mode)
+{
+       u64 div_result = 1000000000000ll;
+
+       videomode->name = mode->name;
+       videomode->refresh = mode->refresh;
+       videomode->xres = mode->xres;
+       videomode->yres = mode->yres;
+
+       do_div(div_result, mode->pixclock_freq);
+       videomode->pixclock = (u32)div_result;
+
+       videomode->left_margin = mode->left_margin;
+       videomode->right_margin = mode->right_margin;
+       videomode->upper_margin = mode->upper_margin;
+       videomode->lower_margin = mode->lower_margin;
+       videomode->hsync_len = mode->hsync_len;
+       videomode->vsync_len = mode->vsync_len;
+       videomode->sync = (mode->hsync_invert ? FB_SYNC_HOR_HIGH_ACT : 0)
+               | (mode->vsync_invert ? FB_SYNC_VERT_HIGH_ACT : 0);
+       videomode->vmode = mode->invert_pixclock ? 8 : 0;
+}
+
+static int mmpfb_check_var(struct fb_var_screeninfo *var,
+               struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+
+       if (var->bits_per_pixel == 8)
+               return -EINVAL;
+       /*
+        * Basic geometry sanity checks.
+        */
+       if (var->xoffset + var->xres > var->xres_virtual)
+               return -EINVAL;
+       if (var->yoffset + var->yres > var->yres_virtual)
+               return -EINVAL;
+
+       /*
+        * Check size of framebuffer.
+        */
+       if (var->xres_virtual * var->yres_virtual *
+                       (var->bits_per_pixel >> 3) > fbi->fb_size)
+               return -EINVAL;
+
+       return 0;
+}
+
+static unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
+{
+       return ((chan & 0xffff) >> (16 - bf->length)) << bf->offset;
+}
+
+static u32 to_rgb(u16 red, u16 green, u16 blue)
+{
+       red >>= 8;
+       green >>= 8;
+       blue >>= 8;
+
+       return (red << 16) | (green << 8) | blue;
+}
+
+static int mmpfb_setcolreg(unsigned int regno, unsigned int red,
+               unsigned int green, unsigned int blue,
+               unsigned int trans, struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+       u32 val;
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR && regno < 16) {
+               val =  chan_to_field(red,   &info->var.red);
+               val |= chan_to_field(green, &info->var.green);
+               val |= chan_to_field(blue , &info->var.blue);
+               fbi->pseudo_palette[regno] = val;
+       }
+
+       if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
+               val = to_rgb(red, green, blue);
+               /* TODO */
+       }
+
+       return 0;
+}
+
+static int mmpfb_pan_display(struct fb_var_screeninfo *var,
+               struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+       struct mmp_addr addr;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
+               * var->bits_per_pixel / 8 + fbi->fb_start_dma;
+       mmp_overlay_set_addr(fbi->overlay, &addr);
+
+       return 0;
+}
+
+static int var_update(struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       struct fb_videomode *m;
+       int pix_fmt;
+
+       /* set pix_fmt */
+       pix_fmt = var_to_pixfmt(var);
+       if (pix_fmt < 0)
+               return -EINVAL;
+       pixfmt_to_var(var, pix_fmt);
+       fbi->pix_fmt = pix_fmt;
+
+       /* set var according to best video mode*/
+       m = (struct fb_videomode *)fb_match_mode(var, &info->modelist);
+       if (!m) {
+               dev_err(fbi->dev, "set par: no match mode, use best mode\n");
+               m = (struct fb_videomode *)fb_find_best_mode(var,
+                               &info->modelist);
+               fb_videomode_to_var(var, m);
+       }
+       memcpy(&fbi->mode, m, sizeof(struct fb_videomode));
+
+       /* fix to 2* yres */
+       var->yres_virtual = var->yres * 2;
+       info->fix.visual = (pix_fmt == PIXFMT_PSEUDOCOLOR) ?
+               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+       info->fix.ypanstep = var->yres;
+       return 0;
+}
+
+static int mmpfb_set_par(struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+       struct mmp_addr addr;
+       struct mmp_win win;
+       struct mmp_mode mode;
+       int ret;
+
+       ret = var_update(info);
+       if (ret != 0)
+               return ret;
+
+       /* set window/path according to new videomode */
+       fbmode_to_mmpmode(&mode, &fbi->mode, fbi->output_fmt);
+       mmp_path_set_mode(fbi->path, &mode);
+
+       memset(&win, 0, sizeof(win));
+       win.xsrc = win.xdst = fbi->mode.xres;
+       win.ysrc = win.ydst = fbi->mode.yres;
+       win.pix_fmt = fbi->pix_fmt;
+       mmp_overlay_set_win(fbi->overlay, &win);
+
+       /* set address always */
+       memset(&addr, 0, sizeof(addr));
+       addr.phys[0] = (var->yoffset * var->xres_virtual + var->xoffset)
+               * var->bits_per_pixel / 8 + fbi->fb_start_dma;
+       mmp_overlay_set_addr(fbi->overlay, &addr);
+
+       return 0;
+}
+
+static void mmpfb_power(struct mmpfb_info *fbi, int power)
+{
+       struct mmp_addr addr;
+       struct mmp_win win;
+       struct fb_var_screeninfo *var = &fbi->fb_info->var;
+
+       /* for power on, always set address/window again */
+       if (power) {
+               memset(&win, 0, sizeof(win));
+               win.xsrc = win.xdst = fbi->mode.xres;
+               win.ysrc = win.ydst = fbi->mode.yres;
+               win.pix_fmt = fbi->pix_fmt;
+               mmp_overlay_set_win(fbi->overlay, &win);
+
+               /* set address always */
+               memset(&addr, 0, sizeof(addr));
+               addr.phys[0] = fbi->fb_start_dma +
+                       (var->yoffset * var->xres_virtual + var->xoffset)
+                       * var->bits_per_pixel / 8;
+               mmp_overlay_set_addr(fbi->overlay, &addr);
+       }
+       mmp_overlay_set_onoff(fbi->overlay, power);
+}
+
+static int mmpfb_blank(int blank, struct fb_info *info)
+{
+       struct mmpfb_info *fbi = info->par;
+
+       mmpfb_power(fbi, (blank == FB_BLANK_UNBLANK));
+
+       return 0;
+}
+
+static struct fb_ops mmpfb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_blank       = mmpfb_blank,
+       .fb_check_var   = mmpfb_check_var,
+       .fb_set_par     = mmpfb_set_par,
+       .fb_setcolreg   = mmpfb_setcolreg,
+       .fb_pan_display = mmpfb_pan_display,
+       .fb_fillrect    = cfb_fillrect,
+       .fb_copyarea    = cfb_copyarea,
+       .fb_imageblit   = cfb_imageblit,
+};
+
+static int modes_setup(struct mmpfb_info *fbi)
+{
+       struct fb_videomode *videomodes;
+       struct mmp_mode *mmp_modes;
+       struct fb_info *info = fbi->fb_info;
+       int videomode_num, i;
+
+       /* get videomodes from path */
+       videomode_num = mmp_path_get_modelist(fbi->path, &mmp_modes);
+       if (!videomode_num) {
+               dev_warn(fbi->dev, "can't get videomode num\n");
+               return 0;
+       }
+       /* put videomode list to info structure */
+       videomodes = kzalloc(sizeof(struct fb_videomode) * videomode_num,
+                       GFP_KERNEL);
+       if (!videomodes) {
+               dev_err(fbi->dev, "can't malloc video modes\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < videomode_num; i++)
+               mmpmode_to_fbmode(&videomodes[i], &mmp_modes[i]);
+       fb_videomode_to_modelist(videomodes, videomode_num, &info->modelist);
+
+       /* set videomode[0] as default mode */
+       memcpy(&fbi->mode, &videomodes[0], sizeof(struct fb_videomode));
+       fbi->output_fmt = mmp_modes[0].pix_fmt_out;
+       fb_videomode_to_var(&info->var, &fbi->mode);
+       mmp_path_set_mode(fbi->path, &mmp_modes[0]);
+
+       kfree(videomodes);
+       return videomode_num;
+}
+
+static int fb_info_setup(struct fb_info *info,
+                       struct mmpfb_info *fbi)
+{
+       int ret = 0;
+       /* Initialise static fb parameters.*/
+       info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK |
+               FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
+       info->node = -1;
+       strcpy(info->fix.id, fbi->name);
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 0;
+       info->fix.ypanstep = info->var.yres;
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_NONE;
+       info->fix.smem_start = fbi->fb_start_dma;
+       info->fix.smem_len = fbi->fb_size;
+       info->fix.visual = (fbi->pix_fmt == PIXFMT_PSEUDOCOLOR) ?
+               FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+       info->fix.line_length = info->var.xres_virtual *
+               info->var.bits_per_pixel / 8;
+       info->fbops = &mmpfb_ops;
+       info->pseudo_palette = fbi->pseudo_palette;
+       info->screen_base = fbi->fb_start;
+       info->screen_size = fbi->fb_size;
+
+       /* For FB framework: Allocate color map and Register framebuffer*/
+       if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
+               ret = -ENOMEM;
+
+       return ret;
+}
+
+static void fb_info_clear(struct fb_info *info)
+{
+       fb_dealloc_cmap(&info->cmap);
+}
+
+static int mmpfb_probe(struct platform_device *pdev)
+{
+       struct mmp_buffer_driver_mach_info *mi;
+       struct fb_info *info = 0;
+       struct mmpfb_info *fbi = 0;
+       int ret, modes_num;
+
+       mi = pdev->dev.platform_data;
+       if (mi == NULL) {
+               dev_err(&pdev->dev, "no platform data defined\n");
+               return -EINVAL;
+       }
+
+       /* initialize fb */
+       info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev);
+       if (info == NULL)
+               return -ENOMEM;
+       fbi = info->par;
+       if (!fbi) {
+               ret = -EINVAL;
+               goto failed;
+       }
+
+       /* init fb */
+       fbi->fb_info = info;
+       platform_set_drvdata(pdev, fbi);
+       fbi->dev = &pdev->dev;
+       fbi->name = mi->name;
+       fbi->pix_fmt = mi->default_pixfmt;
+       pixfmt_to_var(&info->var, fbi->pix_fmt);
+       mutex_init(&fbi->access_ok);
+
+       /* get display path by name */
+       fbi->path = mmp_get_path(mi->path_name);
+       if (!fbi->path) {
+               dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name);
+               ret = -EINVAL;
+               goto failed_destroy_mutex;
+       }
+
+       dev_info(fbi->dev, "path %s get\n", fbi->path->name);
+
+       /* get overlay */
+       fbi->overlay = mmp_path_get_overlay(fbi->path, mi->overlay_id);
+       if (!fbi->overlay) {
+               ret = -EINVAL;
+               goto failed_destroy_mutex;
+       }
+       /* set fetch used */
+       mmp_overlay_set_fetch(fbi->overlay, mi->dmafetch_id);
+
+       modes_num = modes_setup(fbi);
+       if (modes_num < 0) {
+               ret = modes_num;
+               goto failed_destroy_mutex;
+       }
+
+       /*
+        * if get modes success, means not hotplug panels, use caculated buffer
+        * or use default size
+        */
+       if (modes_num > 0) {
+               /* fix to 2* yres */
+               info->var.yres_virtual = info->var.yres * 2;
+
+               /* Allocate framebuffer memory: size = modes xy *4 */
+               fbi->fb_size = info->var.xres_virtual * info->var.yres_virtual
+                               * info->var.bits_per_pixel / 8;
+       } else {
+               fbi->fb_size = MMPFB_DEFAULT_SIZE;
+       }
+
+       fbi->fb_start = dma_alloc_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size),
+                               &fbi->fb_start_dma, GFP_KERNEL);
+       if (fbi->fb_start == NULL) {
+               dev_err(&pdev->dev, "can't alloc framebuffer\n");
+               ret = -ENOMEM;
+               goto failed_destroy_mutex;
+       }
+       memset(fbi->fb_start, 0, fbi->fb_size);
+       dev_info(fbi->dev, "fb %dk allocated\n", fbi->fb_size/1024);
+
+       /* fb power on */
+       if (modes_num > 0)
+               mmpfb_power(fbi, 1);
+
+       ret = fb_info_setup(info, fbi);
+       if (ret < 0)
+               goto failed_free_buff;
+
+       ret = register_framebuffer(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register fb: %d\n", ret);
+               ret = -ENXIO;
+               goto failed_clear_info;
+       }
+
+       dev_info(fbi->dev, "loaded to /dev/fb%d <%s>.\n",
+               info->node, info->fix.id);
+
+#ifdef CONFIG_LOGO
+       if (fbi->fb_start) {
+               fb_prepare_logo(info, 0);
+               fb_show_logo(info, 0);
+       }
+#endif
+
+       return 0;
+
+failed_clear_info:
+       fb_info_clear(info);
+failed_free_buff:
+       dma_free_coherent(&pdev->dev, PAGE_ALIGN(fbi->fb_size), fbi->fb_start,
+               fbi->fb_start_dma);
+failed_destroy_mutex:
+       mutex_destroy(&fbi->access_ok);
+failed:
+       dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
+       platform_set_drvdata(pdev, NULL);
+
+       framebuffer_release(info);
+
+       return ret;
+}
+
+static struct platform_driver mmpfb_driver = {
+       .driver         = {
+               .name   = "mmp-fb",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mmpfb_probe,
+};
+
+static int mmpfb_init(void)
+{
+       return platform_driver_register(&mmpfb_driver);
+}
+module_init(mmpfb_init);
+
+MODULE_AUTHOR("Zhou Zhu <zhou.zhu@marvell.com>");
+MODULE_DESCRIPTION("Framebuffer driver for Marvell displays");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mmp/fb/mmpfb.h b/drivers/video/mmp/fb/mmpfb.h
new file mode 100644 (file)
index 0000000..88c23c1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * linux/drivers/video/mmp/fb/mmpfb.h
+ * Framebuffer driver for Marvell Display controller.
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _MMP_FB_H_
+#define _MMP_FB_H_
+
+#include <video/mmp_disp.h>
+#include <linux/fb.h>
+
+/* LCD controller private state. */
+struct mmpfb_info {
+       struct device   *dev;
+       int     id;
+       const char      *name;
+
+       struct fb_info  *fb_info;
+       /* basicaly videomode is for output */
+       struct fb_videomode     mode;
+       int     pix_fmt;
+
+       void    *fb_start;
+       int     fb_size;
+       dma_addr_t      fb_start_dma;
+
+       struct mmp_overlay      *overlay;
+       struct mmp_path *path;
+
+       struct mutex    access_ok;
+
+       unsigned int            pseudo_palette[16];
+       int output_fmt;
+};
+
+#define MMPFB_DEFAULT_SIZE (PAGE_ALIGN(1920 * 1080 * 4 * 2))
+#endif /* _MMP_FB_H_ */
diff --git a/drivers/video/mmp/hw/Kconfig b/drivers/video/mmp/hw/Kconfig
new file mode 100644 (file)
index 0000000..02f109a
--- /dev/null
@@ -0,0 +1,20 @@
+if MMP_DISP
+
+config MMP_DISP_CONTROLLER
+       bool "mmp display controller hw support"
+       depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+       default n
+       help
+               Marvell MMP display hw controller support
+               this controller is used on Marvell PXA910,
+               MMP2, MMP3, PXA988 chips
+
+config MMP_DISP_SPI
+       bool "mmp display controller spi port"
+       depends on MMP_DISP_CONTROLLER && SPI_MASTER
+       default y
+       help
+               Marvell MMP display hw controller spi port support
+               will register as a spi master for panel usage
+
+endif
diff --git a/drivers/video/mmp/hw/Makefile b/drivers/video/mmp/hw/Makefile
new file mode 100644 (file)
index 0000000..0000a71
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MMP_DISP_CONTROLLER)  += mmp_ctrl.o
+obj-$(CONFIG_MMP_DISP_SPI)        += mmp_spi.o
diff --git a/drivers/video/mmp/hw/mmp_ctrl.c b/drivers/video/mmp/hw/mmp_ctrl.c
new file mode 100644 (file)
index 0000000..4bd31b2
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * linux/drivers/video/mmp/hw/mmp_ctrl.c
+ * Marvell MMP series Display Controller support
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors:  Guoqing Li <ligq@marvell.com>
+ *          Lisa Du <cldu@marvell.com>
+ *          Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+
+#include "mmp_ctrl.h"
+
+static irqreturn_t ctrl_handle_irq(int irq, void *dev_id)
+{
+       struct mmphw_ctrl *ctrl = (struct mmphw_ctrl *)dev_id;
+       u32 isr, imask, tmp;
+
+       isr = readl_relaxed(ctrl->reg_base + SPU_IRQ_ISR);
+       imask = readl_relaxed(ctrl->reg_base + SPU_IRQ_ENA);
+
+       do {
+               /* clear clock only */
+               tmp = readl_relaxed(ctrl->reg_base + SPU_IRQ_ISR);
+               if (tmp & isr)
+                       writel_relaxed(~isr, ctrl->reg_base + SPU_IRQ_ISR);
+       } while ((isr = readl(ctrl->reg_base + SPU_IRQ_ISR)) & imask);
+
+       return IRQ_HANDLED;
+}
+
+static u32 fmt_to_reg(struct mmp_overlay *overlay, int pix_fmt)
+{
+       u32 link_config = path_to_path_plat(overlay->path)->link_config;
+       u32 rbswap, uvswap = 0, yuvswap = 0,
+               csc_en = 0, val = 0,
+               vid = overlay_is_vid(overlay);
+
+       switch (pix_fmt) {
+       case PIXFMT_RGB565:
+       case PIXFMT_RGB1555:
+       case PIXFMT_RGB888PACK:
+       case PIXFMT_RGB888UNPACK:
+       case PIXFMT_RGBA888:
+               rbswap = !(link_config & 0x1);
+               break;
+       case PIXFMT_VYUY:
+       case PIXFMT_YVU422P:
+       case PIXFMT_YVU420P:
+               rbswap = link_config & 0x1;
+               uvswap = 1;
+               break;
+       case PIXFMT_YUYV:
+               rbswap = link_config & 0x1;
+               yuvswap = 1;
+               break;
+       default:
+               rbswap = link_config & 0x1;
+               break;
+       }
+
+       switch (pix_fmt) {
+       case PIXFMT_RGB565:
+       case PIXFMT_BGR565:
+               val = 0;
+               break;
+       case PIXFMT_RGB1555:
+       case PIXFMT_BGR1555:
+               val = 0x1;
+               break;
+       case PIXFMT_RGB888PACK:
+       case PIXFMT_BGR888PACK:
+               val = 0x2;
+               break;
+       case PIXFMT_RGB888UNPACK:
+       case PIXFMT_BGR888UNPACK:
+               val = 0x3;
+               break;
+       case PIXFMT_RGBA888:
+       case PIXFMT_BGRA888:
+               val = 0x4;
+               break;
+       case PIXFMT_UYVY:
+       case PIXFMT_VYUY:
+       case PIXFMT_YUYV:
+               val = 0x5;
+               csc_en = 1;
+               break;
+       case PIXFMT_YUV422P:
+       case PIXFMT_YVU422P:
+               val = 0x6;
+               csc_en = 1;
+               break;
+       case PIXFMT_YUV420P:
+       case PIXFMT_YVU420P:
+               val = 0x7;
+               csc_en = 1;
+               break;
+       default:
+               break;
+       }
+
+       return (dma_palette(0) | dma_fmt(vid, val) |
+               dma_swaprb(vid, rbswap) | dma_swapuv(vid, uvswap) |
+               dma_swapyuv(vid, yuvswap) | dma_csc(vid, csc_en));
+}
+
+static void dmafetch_set_fmt(struct mmp_overlay *overlay)
+{
+       u32 tmp;
+       struct mmp_path *path = overlay->path;
+       tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id));
+       tmp &= ~dma_mask(overlay_is_vid(overlay));
+       tmp |= fmt_to_reg(overlay, overlay->win.pix_fmt);
+       writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id));
+}
+
+static void overlay_set_win(struct mmp_overlay *overlay, struct mmp_win *win)
+{
+       struct lcd_regs *regs = path_regs(overlay->path);
+       u32 pitch;
+
+       /* assert win supported */
+       memcpy(&overlay->win, win, sizeof(struct mmp_win));
+
+       mutex_lock(&overlay->access_ok);
+       pitch = win->xsrc * pixfmt_to_stride(win->pix_fmt);
+       writel_relaxed(pitch, &regs->g_pitch);
+       writel_relaxed((win->ysrc << 16) | win->xsrc, &regs->g_size);
+       writel_relaxed((win->ydst << 16) | win->xdst, &regs->g_size_z);
+       writel_relaxed(0, &regs->g_start);
+
+       dmafetch_set_fmt(overlay);
+       mutex_unlock(&overlay->access_ok);
+}
+
+static void dmafetch_onoff(struct mmp_overlay *overlay, int on)
+{
+       u32 mask = overlay_is_vid(overlay) ? CFG_GRA_ENA_MASK :
+                  CFG_DMA_ENA_MASK;
+       u32 enable = overlay_is_vid(overlay) ? CFG_GRA_ENA(1) : CFG_DMA_ENA(1);
+       u32 tmp;
+       struct mmp_path *path = overlay->path;
+
+       mutex_lock(&overlay->access_ok);
+       tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id));
+       tmp &= ~mask;
+       tmp |= (on ? enable : 0);
+       writel(tmp, ctrl_regs(path) + dma_ctrl(0, path->id));
+       mutex_unlock(&overlay->access_ok);
+}
+
+static void path_enabledisable(struct mmp_path *path, int on)
+{
+       u32 tmp;
+       mutex_lock(&path->access_ok);
+       tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path));
+       if (on)
+               tmp &= ~SCLK_DISABLE;
+       else
+               tmp |= SCLK_DISABLE;
+       writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path));
+       mutex_unlock(&path->access_ok);
+}
+
+static void path_onoff(struct mmp_path *path, int on)
+{
+       if (path->status == on) {
+               dev_info(path->dev, "path %s is already %s\n",
+                               path->name, stat_name(path->status));
+               return;
+       }
+
+       if (on) {
+               path_enabledisable(path, 1);
+
+               if (path->panel && path->panel->set_onoff)
+                       path->panel->set_onoff(path->panel, 1);
+       } else {
+               if (path->panel && path->panel->set_onoff)
+                       path->panel->set_onoff(path->panel, 0);
+
+               path_enabledisable(path, 0);
+       }
+       path->status = on;
+}
+
+static void overlay_set_onoff(struct mmp_overlay *overlay, int on)
+{
+       if (overlay->status == on) {
+               dev_info(overlay_to_ctrl(overlay)->dev, "overlay %s is already %s\n",
+                       overlay->path->name, stat_name(overlay->status));
+               return;
+       }
+       overlay->status = on;
+       dmafetch_onoff(overlay, on);
+       if (overlay->path->ops.check_status(overlay->path)
+                       != overlay->path->status)
+               path_onoff(overlay->path, on);
+}
+
+static void overlay_set_fetch(struct mmp_overlay *overlay, int fetch_id)
+{
+       overlay->dmafetch_id = fetch_id;
+}
+
+static int overlay_set_addr(struct mmp_overlay *overlay, struct mmp_addr *addr)
+{
+       struct lcd_regs *regs = path_regs(overlay->path);
+
+       /* FIXME: assert addr supported */
+       memcpy(&overlay->addr, addr, sizeof(struct mmp_win));
+       writel(addr->phys[0], &regs->g_0);
+
+       return overlay->addr.phys[0];
+}
+
+static void path_set_mode(struct mmp_path *path, struct mmp_mode *mode)
+{
+       struct lcd_regs *regs = path_regs(path);
+       u32 total_x, total_y, vsync_ctrl, tmp, sclk_src, sclk_div,
+               link_config = path_to_path_plat(path)->link_config;
+
+       /* FIXME: assert videomode supported */
+       memcpy(&path->mode, mode, sizeof(struct mmp_mode));
+
+       mutex_lock(&path->access_ok);
+
+       /* polarity of timing signals */
+       tmp = readl_relaxed(ctrl_regs(path) + intf_ctrl(path->id)) & 0x1;
+       tmp |= mode->vsync_invert ? 0 : 0x8;
+       tmp |= mode->hsync_invert ? 0 : 0x4;
+       tmp |= link_config & CFG_DUMBMODE_MASK;
+       tmp |= CFG_DUMB_ENA(1);
+       writel_relaxed(tmp, ctrl_regs(path) + intf_ctrl(path->id));
+
+       writel_relaxed((mode->yres << 16) | mode->xres, &regs->screen_active);
+       writel_relaxed((mode->left_margin << 16) | mode->right_margin,
+               &regs->screen_h_porch);
+       writel_relaxed((mode->upper_margin << 16) | mode->lower_margin,
+               &regs->screen_v_porch);
+       total_x = mode->xres + mode->left_margin + mode->right_margin +
+               mode->hsync_len;
+       total_y = mode->yres + mode->upper_margin + mode->lower_margin +
+               mode->vsync_len;
+       writel_relaxed((total_y << 16) | total_x, &regs->screen_size);
+
+       /* vsync ctrl */
+       if (path->output_type == PATH_OUT_DSI)
+               vsync_ctrl = 0x01330133;
+       else
+               vsync_ctrl = ((mode->xres + mode->right_margin) << 16)
+                                       | (mode->xres + mode->right_margin);
+       writel_relaxed(vsync_ctrl, &regs->vsync_ctrl);
+
+       /* set pixclock div */
+       sclk_src = clk_get_rate(path_to_ctrl(path)->clk);
+       sclk_div = sclk_src / mode->pixclock_freq;
+       if (sclk_div * mode->pixclock_freq < sclk_src)
+               sclk_div++;
+
+       dev_info(path->dev, "%s sclk_src %d sclk_div 0x%x pclk %d\n",
+                       __func__, sclk_src, sclk_div, mode->pixclock_freq);
+
+       tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path));
+       tmp &= ~CLK_INT_DIV_MASK;
+       tmp |= sclk_div;
+       writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path));
+
+       mutex_unlock(&path->access_ok);
+}
+
+static struct mmp_overlay_ops mmphw_overlay_ops = {
+       .set_fetch = overlay_set_fetch,
+       .set_onoff = overlay_set_onoff,
+       .set_win = overlay_set_win,
+       .set_addr = overlay_set_addr,
+};
+
+static void ctrl_set_default(struct mmphw_ctrl *ctrl)
+{
+       u32 tmp, irq_mask;
+
+       /*
+        * LCD Global control(LCD_TOP_CTRL) should be configed before
+        * any other LCD registers read/write, or there maybe issues.
+        */
+       tmp = readl_relaxed(ctrl->reg_base + LCD_TOP_CTRL);
+       tmp |= 0xfff0;
+       writel_relaxed(tmp, ctrl->reg_base + LCD_TOP_CTRL);
+
+
+       /* disable all interrupts */
+       irq_mask = path_imasks(0) | err_imask(0) |
+                  path_imasks(1) | err_imask(1);
+       tmp = readl_relaxed(ctrl->reg_base + SPU_IRQ_ENA);
+       tmp &= ~irq_mask;
+       tmp |= irq_mask;
+       writel_relaxed(tmp, ctrl->reg_base + SPU_IRQ_ENA);
+}
+
+static void path_set_default(struct mmp_path *path)
+{
+       struct lcd_regs *regs = path_regs(path);
+       u32 dma_ctrl1, mask, tmp, path_config;
+
+       path_config = path_to_path_plat(path)->path_config;
+
+       /* Configure IOPAD: should be parallel only */
+       if (PATH_OUT_PARALLEL == path->output_type) {
+               mask = CFG_IOPADMODE_MASK | CFG_BURST_MASK | CFG_BOUNDARY_MASK;
+               tmp = readl_relaxed(ctrl_regs(path) + SPU_IOPAD_CONTROL);
+               tmp &= ~mask;
+               tmp |= path_config;
+               writel_relaxed(tmp, ctrl_regs(path) + SPU_IOPAD_CONTROL);
+       }
+
+       /* Select path clock source */
+       tmp = readl_relaxed(ctrl_regs(path) + LCD_SCLK(path));
+       tmp &= ~SCLK_SRC_SEL_MASK;
+       tmp |= path_config;
+       writel_relaxed(tmp, ctrl_regs(path) + LCD_SCLK(path));
+
+       /*
+        * Configure default bits: vsync triggers DMA,
+        * power save enable, configure alpha registers to
+        * display 100% graphics, and set pixel command.
+        */
+       dma_ctrl1 = 0x2032ff81;
+
+       dma_ctrl1 |= CFG_VSYNC_INV_MASK;
+       writel_relaxed(dma_ctrl1, ctrl_regs(path) + dma_ctrl(1, path->id));
+
+       /* Configure default register values */
+       writel_relaxed(0x00000000, &regs->blank_color);
+       writel_relaxed(0x00000000, &regs->g_1);
+       writel_relaxed(0x00000000, &regs->g_start);
+
+       /*
+        * 1.enable multiple burst request in DMA AXI
+        * bus arbiter for faster read if not tv path;
+        * 2.enable horizontal smooth filter;
+        */
+       if (PATH_PN == path->id) {
+               mask = CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK
+                       | CFG_ARBFAST_ENA(1);
+               tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id));
+               tmp |= mask;
+               writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id));
+       } else if (PATH_TV == path->id) {
+               mask = CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK
+                       | CFG_ARBFAST_ENA(1);
+               tmp = readl_relaxed(ctrl_regs(path) + dma_ctrl(0, path->id));
+               tmp &= ~mask;
+               tmp |= CFG_GRA_HSMOOTH_MASK | CFG_DMA_HSMOOTH_MASK;
+               writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id));
+       }
+}
+
+static int path_init(struct mmphw_path_plat *path_plat,
+               struct mmp_mach_path_config *config)
+{
+       struct mmphw_ctrl *ctrl = path_plat->ctrl;
+       struct mmp_path_info *path_info;
+       struct mmp_path *path = NULL;
+
+       dev_info(ctrl->dev, "%s: %s\n", __func__, config->name);
+
+       /* init driver data */
+       path_info = kzalloc(sizeof(struct mmp_path_info), GFP_KERNEL);
+       if (!path_info) {
+               dev_err(ctrl->dev, "%s: unable to alloc path_info for %s\n",
+                               __func__, config->name);
+               return 0;
+       }
+       path_info->name = config->name;
+       path_info->id = path_plat->id;
+       path_info->dev = ctrl->dev;
+       path_info->overlay_num = config->overlay_num;
+       path_info->overlay_ops = &mmphw_overlay_ops;
+       path_info->set_mode = path_set_mode;
+       path_info->plat_data = path_plat;
+
+       /* create/register platform device */
+       path = mmp_register_path(path_info);
+       if (!path) {
+               kfree(path_info);
+               return 0;
+       }
+       path_plat->path = path;
+       path_plat->path_config = config->path_config;
+       path_plat->link_config = config->link_config;
+       path_set_default(path);
+
+       kfree(path_info);
+       return 1;
+}
+
+static void path_deinit(struct mmphw_path_plat *path_plat)
+{
+       if (!path_plat)
+               return;
+
+       if (path_plat->path)
+               mmp_unregister_path(path_plat->path);
+}
+
+static int mmphw_probe(struct platform_device *pdev)
+{
+       struct mmp_mach_plat_info *mi;
+       struct resource *res;
+       int ret, i, size, irq;
+       struct mmphw_path_plat *path_plat;
+       struct mmphw_ctrl *ctrl = NULL;
+
+       /* get resources from platform data */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "%s: no IO memory defined\n", __func__);
+               ret = -ENOENT;
+               goto failed;
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "%s: no IRQ defined\n", __func__);
+               ret = -ENOENT;
+               goto failed;
+       }
+
+       /* get configs from platform data */
+       mi = pdev->dev.platform_data;
+       if (mi == NULL || !mi->path_num || !mi->paths) {
+               dev_err(&pdev->dev, "%s: no platform data defined\n", __func__);
+               ret = -EINVAL;
+               goto failed;
+       }
+
+       /* allocate */
+       size = sizeof(struct mmphw_ctrl) + sizeof(struct mmphw_path_plat) *
+              mi->path_num;
+       ctrl = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!ctrl) {
+               ret = -ENOMEM;
+               goto failed;
+       }
+
+       ctrl->name = mi->name;
+       ctrl->path_num = mi->path_num;
+       ctrl->dev = &pdev->dev;
+       ctrl->irq = irq;
+       platform_set_drvdata(pdev, ctrl);
+       mutex_init(&ctrl->access_ok);
+
+       /* map registers.*/
+       if (!devm_request_mem_region(ctrl->dev, res->start,
+                       resource_size(res), ctrl->name)) {
+               dev_err(ctrl->dev,
+                       "can't request region for resource %pR\n", res);
+               ret = -EINVAL;
+               goto failed;
+       }
+
+       ctrl->reg_base = devm_ioremap_nocache(ctrl->dev,
+                       res->start, resource_size(res));
+       if (ctrl->reg_base == NULL) {
+               dev_err(ctrl->dev, "%s: res %x - %x map failed\n", __func__,
+                       res->start, res->end);
+               ret = -ENOMEM;
+               goto failed;
+       }
+
+       /* request irq */
+       ret = devm_request_irq(ctrl->dev, ctrl->irq, ctrl_handle_irq,
+               IRQF_SHARED, "lcd_controller", ctrl);
+       if (ret < 0) {
+               dev_err(ctrl->dev, "%s unable to request IRQ %d\n",
+                               __func__, ctrl->irq);
+               ret = -ENXIO;
+               goto failed;
+       }
+
+       /* get clock */
+       ctrl->clk = devm_clk_get(ctrl->dev, mi->clk_name);
+       if (IS_ERR(ctrl->clk)) {
+               dev_err(ctrl->dev, "unable to get clk %s\n", mi->clk_name);
+               ret = -ENOENT;
+               goto failed_get_clk;
+       }
+       clk_prepare_enable(ctrl->clk);
+
+       /* init global regs */
+       ctrl_set_default(ctrl);
+
+       /* init pathes from machine info and register them */
+       for (i = 0; i < ctrl->path_num; i++) {
+               /* get from config and machine info */
+               path_plat = &ctrl->path_plats[i];
+               path_plat->id = i;
+               path_plat->ctrl = ctrl;
+
+               /* path init */
+               if (!path_init(path_plat, &mi->paths[i])) {
+                       ret = -EINVAL;
+                       goto failed_path_init;
+               }
+       }
+
+#ifdef CONFIG_MMP_DISP_SPI
+       ret = lcd_spi_register(ctrl);
+       if (ret < 0)
+               goto failed_path_init;
+#endif
+
+       dev_info(ctrl->dev, "device init done\n");
+
+       return 0;
+
+failed_path_init:
+       for (i = 0; i < ctrl->path_num; i++) {
+               path_plat = &ctrl->path_plats[i];
+               path_deinit(path_plat);
+       }
+
+       if (ctrl->clk) {
+               devm_clk_put(ctrl->dev, ctrl->clk);
+               clk_disable_unprepare(ctrl->clk);
+       }
+failed_get_clk:
+       devm_free_irq(ctrl->dev, ctrl->irq, ctrl);
+failed:
+       if (ctrl) {
+               if (ctrl->reg_base)
+                       devm_iounmap(ctrl->dev, ctrl->reg_base);
+               devm_release_mem_region(ctrl->dev, res->start,
+                               resource_size(res));
+               devm_kfree(ctrl->dev, ctrl);
+       }
+
+       platform_set_drvdata(pdev, NULL);
+       dev_err(&pdev->dev, "device init failed\n");
+
+       return ret;
+}
+
+static struct platform_driver mmphw_driver = {
+       .driver         = {
+               .name   = "mmp-disp",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = mmphw_probe,
+};
+
+static int mmphw_init(void)
+{
+       return platform_driver_register(&mmphw_driver);
+}
+module_init(mmphw_init);
+
+MODULE_AUTHOR("Li Guoqing<ligq@marvell.com>");
+MODULE_DESCRIPTION("Framebuffer driver for mmp");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mmp/hw/mmp_ctrl.h b/drivers/video/mmp/hw/mmp_ctrl.h
new file mode 100644 (file)
index 0000000..6408d8e
--- /dev/null
@@ -0,0 +1,1974 @@
+/*
+ * drivers/video/mmp/hw/mmp_ctrl.h
+ *
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors:  Guoqing Li <ligq@marvell.com>
+ *          Lisa Du <cldu@marvell.com>
+ *          Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _MMP_CTRL_H_
+#define _MMP_CTRL_H_
+
+#include <video/mmp_disp.h>
+
+/* ------------< LCD register >------------ */
+struct lcd_regs {
+/* TV patch register for MMP2 */
+/* 32 bit              TV Video Frame0 Y Starting Address */
+#define LCD_TVD_START_ADDR_Y0                  (0x0000)
+/* 32 bit              TV Video Frame0 U Starting Address */
+#define LCD_TVD_START_ADDR_U0                  (0x0004)
+/* 32 bit              TV Video Frame0 V Starting Address */
+#define LCD_TVD_START_ADDR_V0                  (0x0008)
+/* 32 bit              TV Video Frame0 Command Starting Address */
+#define LCD_TVD_START_ADDR_C0                  (0x000C)
+/* 32 bit              TV Video Frame1 Y Starting Address Register*/
+#define LCD_TVD_START_ADDR_Y1                  (0x0010)
+/* 32 bit              TV Video Frame1 U Starting Address Register*/
+#define LCD_TVD_START_ADDR_U1                  (0x0014)
+/* 32 bit              TV Video Frame1 V Starting Address Register*/
+#define LCD_TVD_START_ADDR_V1                  (0x0018)
+/* 32 bit              TV Video Frame1 Command Starting Address Register*/
+#define LCD_TVD_START_ADDR_C1                  (0x001C)
+/* 32 bit              TV Video Y andC Line Length(Pitch)Register*/
+#define LCD_TVD_PITCH_YC                       (0x0020)
+/* 32 bit              TV Video U andV Line Length(Pitch)Register*/
+#define LCD_TVD_PITCH_UV                       (0x0024)
+/* 32 bit        TV Video Starting Point on Screen Register*/
+#define LCD_TVD_OVSA_HPXL_VLN                  (0x0028)
+/* 32 bit              TV Video Source Size Register*/
+#define LCD_TVD_HPXL_VLN                       (0x002C)
+/* 32 bit        TV Video Destination Size (After Zooming)Register*/
+#define LCD_TVDZM_HPXL_VLN                     (0x0030)
+       u32 v_y0;
+       u32 v_u0;
+       u32 v_v0;
+       u32 v_c0;
+       u32 v_y1;
+       u32 v_u1;
+       u32 v_v1;
+       u32 v_c1;
+       u32 v_pitch_yc;         /* Video Y and C Line Length (Pitch) */
+       u32 v_pitch_uv;         /* Video U and V Line Length (Pitch) */
+       u32 v_start;            /* Video Starting Point on Screen */
+       u32 v_size;                     /* Video Source Size */
+       u32 v_size_z;           /* Video Destination Size (After Zooming) */
+
+/* 32 bit         TV Graphic Frame 0 Starting Address Register*/
+#define LCD_TVG_START_ADDR0                            (0x0034)
+/* 32 bit        TV Graphic Frame 1 Starting Address Register*/
+#define LCD_TVG_START_ADDR1                            (0x0038)
+/* 32 bit              TV Graphic Line Length(Pitch)Register*/
+#define LCD_TVG_PITCH                                  (0x003C)
+/* 32 bit              TV Graphic Starting Point on Screen Register*/
+#define LCD_TVG_OVSA_HPXL_VLN                          (0x0040)
+/* 32 bit              TV Graphic Source Size Register*/
+#define LCD_TVG_HPXL_VLN                               (0x0044)
+/* 32 bit              TV Graphic Destination size (after Zooming)Register*/
+#define LCD_TVGZM_HPXL_VLN                             (0x0048)
+       u32 g_0;                        /* Graphic Frame 0/1 Starting Address */
+       u32 g_1;
+       u32 g_pitch;            /* Graphic Line Length (Pitch) */
+       u32 g_start;            /* Graphic Starting Point on Screen */
+       u32 g_size;                     /* Graphic Source Size */
+       u32 g_size_z;           /* Graphic Destination Size (After Zooming) */
+
+/* 32 bit        TV Hardware Cursor Starting Point on screen Register*/
+#define LCD_TVC_OVSA_HPXL_VLN                          (0x004C)
+/* 32 bit              TV Hardware Cursor Size Register */
+#define LCD_TVC_HPXL_VLN                               (0x0050)
+       u32 hc_start;                   /* Hardware Cursor */
+       u32 hc_size;                    /* Hardware Cursor */
+
+/* 32 bit              TV Total Screen Size Register*/
+#define LCD_TV_V_H_TOTAL                               (0x0054)
+/* 32 bit              TV Screen Active Size Register*/
+#define LCD_TV_V_H_ACTIVE                              (0x0058)
+/* 32 bit              TV Screen Horizontal Porch Register*/
+#define LCD_TV_H_PORCH                                 (0x005C)
+/* 32 bit              TV Screen Vertical Porch Register*/
+#define LCD_TV_V_PORCH                                 (0x0060)
+       u32 screen_size;                /* Screen Total Size */
+       u32 screen_active;              /* Screen Active Size */
+       u32 screen_h_porch;             /* Screen Horizontal Porch */
+       u32 screen_v_porch;             /* Screen Vertical Porch */
+
+/* 32 bit              TV Screen Blank Color Register*/
+#define LCD_TV_BLANKCOLOR                              (0x0064)
+/* 32 bit              TV Hardware Cursor Color1 Register*/
+#define LCD_TV_ALPHA_COLOR1                            (0x0068)
+/* 32 bit              TV Hardware Cursor Color2 Register*/
+#define LCD_TV_ALPHA_COLOR2                            (0x006C)
+       u32 blank_color;                /* Screen Blank Color */
+       u32 hc_Alpha_color1;    /* Hardware Cursor Color1 */
+       u32 hc_Alpha_color2;    /* Hardware Cursor Color2 */
+
+/* 32 bit              TV Video Y Color Key Control*/
+#define LCD_TV_COLORKEY_Y                              (0x0070)
+/* 32 bit              TV Video U Color Key Control*/
+#define LCD_TV_COLORKEY_U                              (0x0074)
+/* 32 bit              TV Video V Color Key Control*/
+#define LCD_TV_COLORKEY_V                              (0x0078)
+       u32 v_colorkey_y;               /* Video Y Color Key Control */
+       u32 v_colorkey_u;               /* Video U Color Key Control */
+       u32 v_colorkey_v;               /* Video V Color Key Control */
+
+/* 32 bit              TV VSYNC PulsePixel Edge Control Register*/
+#define LCD_TV_SEPXLCNT                                        (0x007C)
+       u32 vsync_ctrl;                 /* VSYNC PulsePixel Edge Control */
+};
+
+#define intf_ctrl(id)          ((id) ? (((id) & 1) ? LCD_TVIF_CTRL : \
+                               LCD_DUMB2_CTRL) : LCD_SPU_DUMB_CTRL)
+#define dma_ctrl0(id)     ((id) ? (((id) & 1) ? LCD_TV_CTRL0 : \
+                               LCD_PN2_CTRL0) : LCD_SPU_DMA_CTRL0)
+#define dma_ctrl1(id)     ((id) ? (((id) & 1) ? LCD_TV_CTRL1 : \
+                               LCD_PN2_CTRL1) : LCD_SPU_DMA_CTRL1)
+#define dma_ctrl(ctrl1, id)     (ctrl1 ? dma_ctrl1(id) : dma_ctrl0(id))
+
+/* 32 bit              TV Path DMA Control 0*/
+#define LCD_TV_CTRL0                                   (0x0080)
+/* 32 bit              TV Path DMA Control 1*/
+#define LCD_TV_CTRL1                                   (0x0084)
+/* 32 bit              TV Path Video Contrast*/
+#define LCD_TV_CONTRAST                                        (0x0088)
+/* 32 bit              TV Path Video Saturation*/
+#define LCD_TV_SATURATION                              (0x008C)
+/* 32 bit              TV Path Video Hue Adjust*/
+#define LCD_TV_CBSH_HUE                                        (0x0090)
+/* 32 bit TV Path TVIF Control Register */
+#define LCD_TVIF_CTRL                                  (0x0094)
+#define TV_VBLNK_VALID_EN                              (1 << 12)
+
+/* 32 bit TV Path I/O Pad Control*/
+#define LCD_TVIOPAD_CTRL                               (0x0098)
+/* 32 bit TV Path Cloc Divider  */
+#define LCD_TCLK_DIV                                   (0x009C)
+
+#define LCD_SCLK(path) ((PATH_PN == path->id) ? LCD_CFG_SCLK_DIV :\
+       ((PATH_TV == path->id) ? LCD_TCLK_DIV : LCD_PN2_SCLK_DIV))
+
+/* dither configure */
+#ifdef CONFIG_CPU_PXA988
+#define LCD_DITHER_CTRL                                (0x01EC)
+#else
+#define LCD_DITHER_CTRL                                (0x00A0)
+#endif
+
+#define DITHER_TBL_INDEX_SEL(s)                ((s) << 16)
+#define DITHER_MODE2(m)                                ((m) << 12)
+#define DITHER_MODE2_SHIFT                     (12)
+#define DITHER_4X8_EN2                         (1 << 9)
+#define DITHER_4X8_EN2_SHIFT           (9)
+#define DITHER_EN2                                     (1 << 8)
+#define DITHER_MODE1(m)                                ((m) << 4)
+#define DITHER_MODE1_SHIFT                     (4)
+#define DITHER_4X8_EN1                         (1 << 1)
+#define DITHER_4X8_EN1_SHIFT           (1)
+#define DITHER_EN1                                     (1)
+
+/* dither table data was fixed by video bpp of input and output*/
+#ifdef CONFIG_CPU_PXA988
+#define DITHER_TB_4X4_INDEX0           (0x6e4ca280)
+#define DITHER_TB_4X4_INDEX1           (0x5d7f91b3)
+#define DITHER_TB_4X8_INDEX0           (0xb391a280)
+#define DITHER_TB_4X8_INDEX1           (0x7f5d6e4c)
+#define DITHER_TB_4X8_INDEX2           (0x80a291b3)
+#define DITHER_TB_4X8_INDEX3           (0x4c6e5d7f)
+#define LCD_DITHER_TBL_DATA            (0x01F0)
+#else
+#define DITHER_TB_4X4_INDEX0           (0x3b19f7d5)
+#define DITHER_TB_4X4_INDEX1           (0x082ac4e6)
+#define DITHER_TB_4X8_INDEX0           (0xf7d508e6)
+#define DITHER_TB_4X8_INDEX1           (0x3b194c2a)
+#define DITHER_TB_4X8_INDEX2           (0xc4e6d5f7)
+#define DITHER_TB_4X8_INDEX3           (0x082a193b)
+#define LCD_DITHER_TBL_DATA            (0x00A4)
+#endif
+
+/* Video Frame 0&1 start address registers */
+#define        LCD_SPU_DMA_START_ADDR_Y0       0x00C0
+#define        LCD_SPU_DMA_START_ADDR_U0       0x00C4
+#define        LCD_SPU_DMA_START_ADDR_V0       0x00C8
+#define LCD_CFG_DMA_START_ADDR_0       0x00CC /* Cmd address */
+#define        LCD_SPU_DMA_START_ADDR_Y1       0x00D0
+#define        LCD_SPU_DMA_START_ADDR_U1       0x00D4
+#define        LCD_SPU_DMA_START_ADDR_V1       0x00D8
+#define LCD_CFG_DMA_START_ADDR_1       0x00DC /* Cmd address */
+
+/* YC & UV Pitch */
+#define LCD_SPU_DMA_PITCH_YC           0x00E0
+#define         SPU_DMA_PITCH_C(c)             ((c)<<16)
+#define         SPU_DMA_PITCH_Y(y)             (y)
+#define LCD_SPU_DMA_PITCH_UV           0x00E4
+#define         SPU_DMA_PITCH_V(v)             ((v)<<16)
+#define         SPU_DMA_PITCH_U(u)             (u)
+
+/* Video Starting Point on Screen Register */
+#define LCD_SPUT_DMA_OVSA_HPXL_VLN             0x00E8
+#define         CFG_DMA_OVSA_VLN(y)                    ((y)<<16) /* 0~0xfff */
+#define         CFG_DMA_OVSA_HPXL(x)                   (x)      /* 0~0xfff */
+
+/* Video Size Register */
+#define LCD_SPU_DMA_HPXL_VLN                   0x00EC
+#define         CFG_DMA_VLN(y)                         ((y)<<16)
+#define         CFG_DMA_HPXL(x)                        (x)
+
+/* Video Size After zooming Register */
+#define LCD_SPU_DZM_HPXL_VLN                   0x00F0
+#define         CFG_DZM_VLN(y)                         ((y)<<16)
+#define         CFG_DZM_HPXL(x)                        (x)
+
+/* Graphic Frame 0&1 Starting Address Register */
+#define LCD_CFG_GRA_START_ADDR0                        0x00F4
+#define LCD_CFG_GRA_START_ADDR1                        0x00F8
+
+/* Graphic Frame Pitch */
+#define LCD_CFG_GRA_PITCH                      0x00FC
+
+/* Graphic Starting Point on Screen Register */
+#define LCD_SPU_GRA_OVSA_HPXL_VLN              0x0100
+#define         CFG_GRA_OVSA_VLN(y)                    ((y)<<16)
+#define         CFG_GRA_OVSA_HPXL(x)                   (x)
+
+/* Graphic Size Register */
+#define LCD_SPU_GRA_HPXL_VLN                   0x0104
+#define         CFG_GRA_VLN(y)                         ((y)<<16)
+#define         CFG_GRA_HPXL(x)                        (x)
+
+/* Graphic Size after Zooming Register */
+#define LCD_SPU_GZM_HPXL_VLN                   0x0108
+#define         CFG_GZM_VLN(y)                         ((y)<<16)
+#define         CFG_GZM_HPXL(x)                        (x)
+
+/* HW Cursor Starting Point on Screen Register */
+#define LCD_SPU_HWC_OVSA_HPXL_VLN              0x010C
+#define         CFG_HWC_OVSA_VLN(y)                    ((y)<<16)
+#define         CFG_HWC_OVSA_HPXL(x)                   (x)
+
+/* HW Cursor Size */
+#define LCD_SPU_HWC_HPXL_VLN                   0x0110
+#define         CFG_HWC_VLN(y)                         ((y)<<16)
+#define         CFG_HWC_HPXL(x)                        (x)
+
+/* Total Screen Size Register */
+#define LCD_SPUT_V_H_TOTAL                     0x0114
+#define         CFG_V_TOTAL(y)                         ((y)<<16)
+#define         CFG_H_TOTAL(x)                         (x)
+
+/* Total Screen Active Size Register */
+#define LCD_SPU_V_H_ACTIVE                     0x0118
+#define         CFG_V_ACTIVE(y)                        ((y)<<16)
+#define         CFG_H_ACTIVE(x)                        (x)
+
+/* Screen H&V Porch Register */
+#define LCD_SPU_H_PORCH                                0x011C
+#define         CFG_H_BACK_PORCH(b)                    ((b)<<16)
+#define         CFG_H_FRONT_PORCH(f)                   (f)
+#define LCD_SPU_V_PORCH                                0x0120
+#define         CFG_V_BACK_PORCH(b)                    ((b)<<16)
+#define         CFG_V_FRONT_PORCH(f)                   (f)
+
+/* Screen Blank Color Register */
+#define LCD_SPU_BLANKCOLOR                     0x0124
+#define  CFG_BLANKCOLOR_MASK                   0x00FFFFFF
+#define  CFG_BLANKCOLOR_R_MASK                 0x000000FF
+#define  CFG_BLANKCOLOR_G_MASK                 0x0000FF00
+#define  CFG_BLANKCOLOR_B_MASK                 0x00FF0000
+
+/* HW Cursor Color 1&2 Register */
+#define LCD_SPU_ALPHA_COLOR1                   0x0128
+#define         CFG_HWC_COLOR1                         0x00FFFFFF
+#define         CFG_HWC_COLOR1_R(red)                  ((red)<<16)
+#define         CFG_HWC_COLOR1_G(green)                ((green)<<8)
+#define         CFG_HWC_COLOR1_B(blue)                 (blue)
+#define         CFG_HWC_COLOR1_R_MASK                  0x000000FF
+#define         CFG_HWC_COLOR1_G_MASK                  0x0000FF00
+#define         CFG_HWC_COLOR1_B_MASK                  0x00FF0000
+#define LCD_SPU_ALPHA_COLOR2                   0x012C
+#define         CFG_HWC_COLOR2                         0x00FFFFFF
+#define         CFG_HWC_COLOR2_R_MASK                  0x000000FF
+#define         CFG_HWC_COLOR2_G_MASK                  0x0000FF00
+#define         CFG_HWC_COLOR2_B_MASK                  0x00FF0000
+
+/* Video YUV Color Key Control */
+#define LCD_SPU_COLORKEY_Y                     0x0130
+#define         CFG_CKEY_Y2(y2)                        ((y2)<<24)
+#define         CFG_CKEY_Y2_MASK                       0xFF000000
+#define         CFG_CKEY_Y1(y1)                        ((y1)<<16)
+#define         CFG_CKEY_Y1_MASK                       0x00FF0000
+#define         CFG_CKEY_Y(y)                          ((y)<<8)
+#define         CFG_CKEY_Y_MASK                        0x0000FF00
+#define         CFG_ALPHA_Y(y)                         (y)
+#define         CFG_ALPHA_Y_MASK                       0x000000FF
+#define LCD_SPU_COLORKEY_U                     0x0134
+#define         CFG_CKEY_U2(u2)                        ((u2)<<24)
+#define         CFG_CKEY_U2_MASK                       0xFF000000
+#define         CFG_CKEY_U1(u1)                        ((u1)<<16)
+#define         CFG_CKEY_U1_MASK                       0x00FF0000
+#define         CFG_CKEY_U(u)                          ((u)<<8)
+#define         CFG_CKEY_U_MASK                        0x0000FF00
+#define         CFG_ALPHA_U(u)                         (u)
+#define         CFG_ALPHA_U_MASK                       0x000000FF
+#define LCD_SPU_COLORKEY_V                     0x0138
+#define         CFG_CKEY_V2(v2)                        ((v2)<<24)
+#define         CFG_CKEY_V2_MASK                       0xFF000000
+#define         CFG_CKEY_V1(v1)                        ((v1)<<16)
+#define         CFG_CKEY_V1_MASK                       0x00FF0000
+#define         CFG_CKEY_V(v)                          ((v)<<8)
+#define         CFG_CKEY_V_MASK                        0x0000FF00
+#define         CFG_ALPHA_V(v)                         (v)
+#define         CFG_ALPHA_V_MASK                       0x000000FF
+
+/* Graphics/Video DMA color key enable bits in LCD_TV_CTRL1 */
+#define         CFG_CKEY_GRA                           0x2
+#define         CFG_CKEY_DMA                           0x1
+
+/* Interlace mode enable bits in LCD_TV_CTRL1 */
+#define     CFG_TV_INTERLACE_EN                 (1 << 22)
+#define     CFG_TV_NIB                          (1 << 0)
+
+#define LCD_PN_SEPXLCNT                                0x013c /* MMP2 */
+
+/* SPI Read Data Register */
+#define LCD_SPU_SPI_RXDATA                     0x0140
+
+/* Smart Panel Read Data Register */
+#define LCD_SPU_ISA_RSDATA                     0x0144
+#define         ISA_RXDATA_16BIT_1_DATA_MASK           0x000000FF
+#define         ISA_RXDATA_16BIT_2_DATA_MASK           0x0000FF00
+#define         ISA_RXDATA_16BIT_3_DATA_MASK           0x00FF0000
+#define         ISA_RXDATA_16BIT_4_DATA_MASK           0xFF000000
+#define         ISA_RXDATA_32BIT_1_DATA_MASK           0x00FFFFFF
+
+#define LCD_SPU_DBG_ISA                                (0x0148) /* TTC */
+#define LCD_SPU_DMAVLD_YC                      (0x014C)
+#define LCD_SPU_DMAVLD_UV                      (0x0150)
+#define LCD_SPU_DMAVLD_UVSPU_GRAVLD            (0x0154)
+
+#define LCD_READ_IOPAD                         (0x0148) /* MMP2*/
+#define LCD_DMAVLD_YC                          (0x014C)
+#define LCD_DMAVLD_UV                          (0x0150)
+#define LCD_TVGGRAVLD_HLEN                     (0x0154)
+
+/* HWC SRAM Read Data Register */
+#define LCD_SPU_HWC_RDDAT                      0x0158
+
+/* Gamma Table SRAM Read Data Register */
+#define LCD_SPU_GAMMA_RDDAT                    0x015c
+#define         CFG_GAMMA_RDDAT_MASK                   0x000000FF
+
+/* Palette Table SRAM Read Data Register */
+#define LCD_SPU_PALETTE_RDDAT                  0x0160
+#define         CFG_PALETTE_RDDAT_MASK                 0x00FFFFFF
+
+#define LCD_SPU_DBG_DMATOP                     (0x0164) /* TTC */
+#define LCD_SPU_DBG_GRATOP                     (0x0168)
+#define LCD_SPU_DBG_TXCTRL                     (0x016C)
+#define LCD_SPU_DBG_SLVTOP                     (0x0170)
+#define LCD_SPU_DBG_MUXTOP                     (0x0174)
+
+#define LCD_SLV_DBG                            (0x0164) /* MMP2 */
+#define LCD_TVDVLD_YC                          (0x0168)
+#define LCD_TVDVLD_UV                          (0x016C)
+#define LCD_TVC_RDDAT                          (0x0170)
+#define LCD_TV_GAMMA_RDDAT                     (0x0174)
+
+/* I/O Pads Input Read Only Register */
+#define LCD_SPU_IOPAD_IN                       0x0178
+#define         CFG_IOPAD_IN_MASK                      0x0FFFFFFF
+
+#define LCD_TV_PALETTE_RDDAT                   (0x0178) /* MMP2 */
+
+/* Reserved Read Only Registers */
+#define LCD_CFG_RDREG5F                                0x017C
+#define         IRE_FRAME_CNT_MASK                     0x000000C0
+#define         IPE_FRAME_CNT_MASK                     0x00000030
+#define         GRA_FRAME_CNT_MASK                     0x0000000C /* Graphic */
+#define         DMA_FRAME_CNT_MASK                     0x00000003 /* Video */
+
+#define LCD_FRAME_CNT                          (0x017C) /* MMP2 */
+
+/* SPI Control Register. */
+#define LCD_SPU_SPI_CTRL                       0x0180
+#define         CFG_SCLKCNT(div)                       ((div)<<24) /* 0xFF~0x2 */
+#define         CFG_SCLKCNT_MASK                       0xFF000000
+#define         CFG_RXBITS(rx)                         (((rx) - 1)<<16) /* 0x1F~0x1 */
+#define         CFG_RXBITS_MASK                        0x00FF0000
+#define         CFG_TXBITS(tx)                         (((tx) - 1)<<8) /* 0x1F~0x1 */
+#define         CFG_TXBITS_MASK                        0x0000FF00
+#define         CFG_CLKINV(clk)                        ((clk)<<7)
+#define         CFG_CLKINV_MASK                        0x00000080
+#define         CFG_KEEPXFER(transfer)                 ((transfer)<<6)
+#define         CFG_KEEPXFER_MASK                      0x00000040
+#define         CFG_RXBITSTO0(rx)                      ((rx)<<5)
+#define         CFG_RXBITSTO0_MASK                     0x00000020
+#define         CFG_TXBITSTO0(tx)                      ((tx)<<4)
+#define         CFG_TXBITSTO0_MASK                     0x00000010
+#define         CFG_SPI_ENA(spi)                       ((spi)<<3)
+#define         CFG_SPI_ENA_MASK                       0x00000008
+#define         CFG_SPI_SEL(spi)                       ((spi)<<2)
+#define         CFG_SPI_SEL_MASK                       0x00000004
+#define         CFG_SPI_3W4WB(wire)                    ((wire)<<1)
+#define         CFG_SPI_3W4WB_MASK                     0x00000002
+#define         CFG_SPI_START(start)                   (start)
+#define         CFG_SPI_START_MASK                     0x00000001
+
+/* SPI Tx Data Register */
+#define LCD_SPU_SPI_TXDATA                     0x0184
+
+/*
+   1. Smart Pannel 8-bit Bus Control Register.
+   2. AHB Slave Path Data Port Register
+*/
+#define LCD_SPU_SMPN_CTRL                      0x0188
+
+/* DMA Control 0 Register */
+#define LCD_SPU_DMA_CTRL0                      0x0190
+#define         CFG_NOBLENDING(nb)                     ((nb)<<31)
+#define         CFG_NOBLENDING_MASK                    0x80000000
+#define         CFG_GAMMA_ENA(gn)                      ((gn)<<30)
+#define         CFG_GAMMA_ENA_MASK                     0x40000000
+#define         CFG_CBSH_ENA(cn)                       ((cn)<<29)
+#define         CFG_CBSH_ENA_MASK                      0x20000000
+#define         CFG_PALETTE_ENA(pn)                    ((pn)<<28)
+#define         CFG_PALETTE_ENA_MASK                   0x10000000
+#define         CFG_ARBFAST_ENA(an)                    ((an)<<27)
+#define         CFG_ARBFAST_ENA_MASK                   0x08000000
+#define         CFG_HWC_1BITMOD(mode)                  ((mode)<<26)
+#define         CFG_HWC_1BITMOD_MASK                   0x04000000
+#define         CFG_HWC_1BITENA(mn)                    ((mn)<<25)
+#define         CFG_HWC_1BITENA_MASK                   0x02000000
+#define         CFG_HWC_ENA(cn)                        ((cn)<<24)
+#define         CFG_HWC_ENA_MASK                       0x01000000
+#define         CFG_DMAFORMAT(dmaformat)               ((dmaformat)<<20)
+#define         CFG_DMAFORMAT_MASK                     0x00F00000
+#define         CFG_GRAFORMAT(graformat)               ((graformat)<<16)
+#define         CFG_GRAFORMAT_MASK                     0x000F0000
+/* for graphic part */
+#define         CFG_GRA_FTOGGLE(toggle)                ((toggle)<<15)
+#define         CFG_GRA_FTOGGLE_MASK                   0x00008000
+#define         CFG_GRA_HSMOOTH(smooth)                ((smooth)<<14)
+#define         CFG_GRA_HSMOOTH_MASK                   0x00004000
+#define         CFG_GRA_TSTMODE(test)                  ((test)<<13)
+#define         CFG_GRA_TSTMODE_MASK                   0x00002000
+#define         CFG_GRA_SWAPRB(swap)                   ((swap)<<12)
+#define         CFG_GRA_SWAPRB_MASK                    0x00001000
+#define         CFG_GRA_SWAPUV(swap)                   ((swap)<<11)
+#define         CFG_GRA_SWAPUV_MASK                    0x00000800
+#define         CFG_GRA_SWAPYU(swap)                   ((swap)<<10)
+#define         CFG_GRA_SWAPYU_MASK                    0x00000400
+#define         CFG_GRA_SWAP_MASK                      0x00001C00
+#define         CFG_YUV2RGB_GRA(cvrt)                  ((cvrt)<<9)
+#define         CFG_YUV2RGB_GRA_MASK                   0x00000200
+#define         CFG_GRA_ENA(gra)                       ((gra)<<8)
+#define         CFG_GRA_ENA_MASK                       0x00000100
+#define dma0_gfx_masks (CFG_GRAFORMAT_MASK | CFG_GRA_FTOGGLE_MASK | \
+       CFG_GRA_HSMOOTH_MASK | CFG_GRA_TSTMODE_MASK | CFG_GRA_SWAP_MASK | \
+       CFG_YUV2RGB_GRA_MASK | CFG_GRA_ENA_MASK)
+/* for video part */
+#define         CFG_DMA_FTOGGLE(toggle)                ((toggle)<<7)
+#define         CFG_DMA_FTOGGLE_MASK                   0x00000080
+#define         CFG_DMA_HSMOOTH(smooth)                ((smooth)<<6)
+#define         CFG_DMA_HSMOOTH_MASK                   0x00000040
+#define         CFG_DMA_TSTMODE(test)                  ((test)<<5)
+#define         CFG_DMA_TSTMODE_MASK                   0x00000020
+#define         CFG_DMA_SWAPRB(swap)                   ((swap)<<4)
+#define         CFG_DMA_SWAPRB_MASK                    0x00000010
+#define         CFG_DMA_SWAPUV(swap)                   ((swap)<<3)
+#define         CFG_DMA_SWAPUV_MASK                    0x00000008
+#define         CFG_DMA_SWAPYU(swap)                   ((swap)<<2)
+#define         CFG_DMA_SWAPYU_MASK                    0x00000004
+#define         CFG_DMA_SWAP_MASK                      0x0000001C
+#define         CFG_YUV2RGB_DMA(cvrt)                  ((cvrt)<<1)
+#define         CFG_YUV2RGB_DMA_MASK                   0x00000002
+#define         CFG_DMA_ENA(video)                     (video)
+#define         CFG_DMA_ENA_MASK                       0x00000001
+#define dma0_vid_masks (CFG_DMAFORMAT_MASK | CFG_DMA_FTOGGLE_MASK | \
+       CFG_DMA_HSMOOTH_MASK | CFG_DMA_TSTMODE_MASK | CFG_DMA_SWAP_MASK | \
+       CFG_YUV2RGB_DMA_MASK | CFG_DMA_ENA_MASK)
+#define dma_palette(val)               ((val ? 1 : 0) << 28)
+#define dma_fmt(vid, val)              ((val & 0xf) << ((vid) ? 20 : 16))
+#define dma_swaprb(vid, val)           ((val ? 1 : 0) << ((vid) ? 4 : 12))
+#define dma_swapuv(vid, val)           ((val ? 1 : 0) << ((vid) ? 3 : 11))
+#define dma_swapyuv(vid, val)          ((val ? 1 : 0) << ((vid) ? 2 : 10))
+#define dma_csc(vid, val)              ((val ? 1 : 0) << ((vid) ? 1 : 9))
+#define dma_hsmooth(vid, val)          ((val ? 1 : 0) << ((vid) ? 6 : 14))
+#define dma_mask(vid)  (dma_palette(1) | dma_fmt(vid, 0xf) | dma_csc(vid, 1) \
+       | dma_swaprb(vid, 1) | dma_swapuv(vid, 1) | dma_swapyuv(vid, 1))
+
+/* DMA Control 1 Register */
+#define LCD_SPU_DMA_CTRL1                      0x0194
+#define         CFG_FRAME_TRIG(trig)                   ((trig)<<31)
+#define         CFG_FRAME_TRIG_MASK                    0x80000000
+#define         CFG_VSYNC_TRIG(trig)                   ((trig)<<28)
+#define         CFG_VSYNC_TRIG_MASK                    0x70000000
+#define         CFG_VSYNC_INV(inv)                     ((inv)<<27)
+#define         CFG_VSYNC_INV_MASK                     0x08000000
+#define         CFG_COLOR_KEY_MODE(cmode)              ((cmode)<<24)
+#define         CFG_COLOR_KEY_MASK                     0x07000000
+#define         CFG_CARRY(carry)                       ((carry)<<23)
+#define         CFG_CARRY_MASK                         0x00800000
+#define         CFG_LNBUF_ENA(lnbuf)                   ((lnbuf)<<22)
+#define         CFG_LNBUF_ENA_MASK                     0x00400000
+#define         CFG_GATED_ENA(gated)                   ((gated)<<21)
+#define         CFG_GATED_ENA_MASK                     0x00200000
+#define         CFG_PWRDN_ENA(power)                   ((power)<<20)
+#define         CFG_PWRDN_ENA_MASK                     0x00100000
+#define         CFG_DSCALE(dscale)                     ((dscale)<<18)
+#define         CFG_DSCALE_MASK                        0x000C0000
+#define         CFG_ALPHA_MODE(amode)                  ((amode)<<16)
+#define         CFG_ALPHA_MODE_MASK                    0x00030000
+#define         CFG_ALPHA(alpha)                       ((alpha)<<8)
+#define         CFG_ALPHA_MASK                         0x0000FF00
+#define         CFG_PXLCMD(pxlcmd)                     (pxlcmd)
+#define         CFG_PXLCMD_MASK                        0x000000FF
+
+/* SRAM Control Register */
+#define LCD_SPU_SRAM_CTRL                      0x0198
+#define         CFG_SRAM_INIT_WR_RD(mode)              ((mode)<<14)
+#define         CFG_SRAM_INIT_WR_RD_MASK               0x0000C000
+#define         CFG_SRAM_ADDR_LCDID(id)                ((id)<<8)
+#define         CFG_SRAM_ADDR_LCDID_MASK               0x00000F00
+#define         CFG_SRAM_ADDR(addr)                    (addr)
+#define         CFG_SRAM_ADDR_MASK                     0x000000FF
+
+/* SRAM Write Data Register */
+#define LCD_SPU_SRAM_WRDAT                     0x019C
+
+/* SRAM RTC/WTC Control Register */
+#define LCD_SPU_SRAM_PARA0                     0x01A0
+
+/* SRAM Power Down Control Register */
+#define LCD_SPU_SRAM_PARA1                     0x01A4
+#define         CFG_CSB_256x32(hwc)                    ((hwc)<<15)     /* HWC */
+#define         CFG_CSB_256x32_MASK                    0x00008000
+#define         CFG_CSB_256x24(palette)                ((palette)<<14) /* Palette */
+#define         CFG_CSB_256x24_MASK                    0x00004000
+#define         CFG_CSB_256x8(gamma)                   ((gamma)<<13)   /* Gamma */
+#define         CFG_CSB_256x8_MASK                     0x00002000
+#define         CFG_PDWN256x32(pdwn)                   ((pdwn)<<7)     /* HWC */
+#define         CFG_PDWN256x32_MASK                    0x00000080
+#define         CFG_PDWN256x24(pdwn)                   ((pdwn)<<6)     /* Palette */
+#define         CFG_PDWN256x24_MASK                    0x00000040
+#define         CFG_PDWN256x8(pdwn)                    ((pdwn)<<5)     /* Gamma */
+#define         CFG_PDWN256x8_MASK                     0x00000020
+#define         CFG_PDWN32x32(pdwn)                    ((pdwn)<<3)
+#define         CFG_PDWN32x32_MASK                     0x00000008
+#define         CFG_PDWN16x66(pdwn)                    ((pdwn)<<2)
+#define         CFG_PDWN16x66_MASK                     0x00000004
+#define         CFG_PDWN32x66(pdwn)                    ((pdwn)<<1)
+#define         CFG_PDWN32x66_MASK                     0x00000002
+#define         CFG_PDWN64x66(pdwn)                    (pdwn)
+#define         CFG_PDWN64x66_MASK                     0x00000001
+
+/* Smart or Dumb Panel Clock Divider */
+#define LCD_CFG_SCLK_DIV                       0x01A8
+#define         SCLK_SRC_SEL(src)              ((src)<<31)
+#define         SCLK_SRC_SEL_MASK              0x80000000
+#define  SCLK_DISABLE                          (1<<28)
+#define         CLK_FRACDIV(frac)                      ((frac)<<16)
+#define         CLK_FRACDIV_MASK                       0x0FFF0000
+#define         DSI1_BITCLK_DIV(div)                   (div<<8)
+#define         DSI1_BITCLK_DIV_MASK                   0x00000F00
+#define         CLK_INT_DIV(div)                       (div)
+#define         CLK_INT_DIV_MASK                       0x000000FF
+
+/* Video Contrast Register */
+#define LCD_SPU_CONTRAST                       0x01AC
+#define         CFG_BRIGHTNESS(bright)                 ((bright)<<16)
+#define         CFG_BRIGHTNESS_MASK                    0xFFFF0000
+#define         CFG_CONTRAST(contrast)                 (contrast)
+#define         CFG_CONTRAST_MASK                      0x0000FFFF
+
+/* Video Saturation Register */
+#define LCD_SPU_SATURATION                     0x01B0
+#define         CFG_C_MULTS(mult)                      ((mult)<<16)
+#define         CFG_C_MULTS_MASK                       0xFFFF0000
+#define         CFG_SATURATION(sat)                    (sat)
+#define         CFG_SATURATION_MASK                    0x0000FFFF
+
+/* Video Hue Adjust Register */
+#define LCD_SPU_CBSH_HUE                       0x01B4
+#define         CFG_SIN0(sin0)                         ((sin0)<<16)
+#define         CFG_SIN0_MASK                          0xFFFF0000
+#define         CFG_COS0(con0)                         (con0)
+#define         CFG_COS0_MASK                          0x0000FFFF
+
+/* Dump LCD Panel Control Register */
+#define LCD_SPU_DUMB_CTRL                      0x01B8
+#define         CFG_DUMBMODE(mode)                     ((mode)<<28)
+#define         CFG_DUMBMODE_MASK                      0xF0000000
+#define         CFG_LCDGPIO_O(data)                    ((data)<<20)
+#define         CFG_LCDGPIO_O_MASK                     0x0FF00000
+#define         CFG_LCDGPIO_ENA(gpio)                  ((gpio)<<12)
+#define         CFG_LCDGPIO_ENA_MASK                   0x000FF000
+#define         CFG_BIAS_OUT(bias)                     ((bias)<<8)
+#define         CFG_BIAS_OUT_MASK                      0x00000100
+#define         CFG_REVERSE_RGB(RGB)                   ((RGB)<<7)
+#define         CFG_REVERSE_RGB_MASK                   0x00000080
+#define         CFG_INV_COMPBLANK(blank)               ((blank)<<6)
+#define         CFG_INV_COMPBLANK_MASK                 0x00000040
+#define         CFG_INV_COMPSYNC(sync)                 ((sync)<<5)
+#define         CFG_INV_COMPSYNC_MASK                  0x00000020
+#define         CFG_INV_HENA(hena)                     ((hena)<<4)
+#define         CFG_INV_HENA_MASK                      0x00000010
+#define         CFG_INV_VSYNC(vsync)                   ((vsync)<<3)
+#define         CFG_INV_VSYNC_MASK                     0x00000008
+#define         CFG_INV_HSYNC(hsync)                   ((hsync)<<2)
+#define         CFG_INV_HSYNC_MASK                     0x00000004
+#define         CFG_INV_PCLK(pclk)                     ((pclk)<<1)
+#define         CFG_INV_PCLK_MASK                      0x00000002
+#define         CFG_DUMB_ENA(dumb)                     (dumb)
+#define         CFG_DUMB_ENA_MASK                      0x00000001
+
+/* LCD I/O Pads Control Register */
+#define SPU_IOPAD_CONTROL                      0x01BC
+#define         CFG_GRA_VM_ENA(vm)                     ((vm)<<15)
+#define         CFG_GRA_VM_ENA_MASK                    0x00008000
+#define         CFG_DMA_VM_ENA(vm)                     ((vm)<<13)
+#define         CFG_DMA_VM_ENA_MASK                    0x00002000
+#define         CFG_CMD_VM_ENA(vm)                     ((vm)<<12)
+#define         CFG_CMD_VM_ENA_MASK                    0x00001000
+#define         CFG_CSC(csc)                           ((csc)<<8)
+#define         CFG_CSC_MASK                           0x00000300
+#define         CFG_BOUNDARY(size)                     ((size)<<5)
+#define         CFG_BOUNDARY_MASK                      0x00000020
+#define         CFG_BURST(len)                         ((len)<<4)
+#define         CFG_BURST_MASK                         0x00000010
+#define         CFG_IOPADMODE(iopad)                   (iopad)
+#define         CFG_IOPADMODE_MASK                     0x0000000F
+
+/* LCD Interrupt Control Register */
+#define SPU_IRQ_ENA                            0x01C0
+#define         DMA_FRAME_IRQ0_ENA(irq)                ((irq)<<31)
+#define         DMA_FRAME_IRQ0_ENA_MASK                0x80000000
+#define         DMA_FRAME_IRQ1_ENA(irq)                ((irq)<<30)
+#define         DMA_FRAME_IRQ1_ENA_MASK                0x40000000
+#define         DMA_FF_UNDERFLOW_ENA(ff)               ((ff)<<29)
+#define         DMA_FF_UNDERFLOW_ENA_MASK              0x20000000
+#define         AXI_BUS_ERROR_IRQ_ENA(irq)             ((irq)<<28)
+#define         AXI_BUS_ERROR_IRQ_ENA_MASK             0x10000000
+#define         GRA_FRAME_IRQ0_ENA(irq)                ((irq)<<27)
+#define         GRA_FRAME_IRQ0_ENA_MASK                0x08000000
+#define         GRA_FRAME_IRQ1_ENA(irq)                ((irq)<<26)
+#define         GRA_FRAME_IRQ1_ENA_MASK                0x04000000
+#define         GRA_FF_UNDERFLOW_ENA(ff)               ((ff)<<25)
+#define         GRA_FF_UNDERFLOW_ENA_MASK              0x02000000
+#define         VSYNC_IRQ_ENA(vsync_irq)               ((vsync_irq)<<23)
+#define         VSYNC_IRQ_ENA_MASK                     0x00800000
+#define         DUMB_FRAMEDONE_ENA(fdone)              ((fdone)<<22)
+#define         DUMB_FRAMEDONE_ENA_MASK                0x00400000
+#define         TWC_FRAMEDONE_ENA(fdone)               ((fdone)<<21)
+#define         TWC_FRAMEDONE_ENA_MASK                 0x00200000
+#define         HWC_FRAMEDONE_ENA(fdone)               ((fdone)<<20)
+#define         HWC_FRAMEDONE_ENA_MASK                 0x00100000
+#define         SLV_IRQ_ENA(irq)                       ((irq)<<19)
+#define         SLV_IRQ_ENA_MASK                       0x00080000
+#define         SPI_IRQ_ENA(irq)                       ((irq)<<18)
+#define         SPI_IRQ_ENA_MASK                       0x00040000
+#define         PWRDN_IRQ_ENA(irq)                     ((irq)<<17)
+#define         PWRDN_IRQ_ENA_MASK                     0x00020000
+#define         AXI_LATENCY_TOO_LONG_IRQ_ENA(irq)      ((irq)<<16)
+#define  AXI_LATENCY_TOO_LONG_IRQ_ENA_MASK     0x00010000
+#define         CLEAN_SPU_IRQ_ISR(irq)                 (irq)
+#define         CLEAN_SPU_IRQ_ISR_MASK                 0x0000FFFF
+#define         TV_DMA_FRAME_IRQ0_ENA(irq)             ((irq)<<15)
+#define         TV_DMA_FRAME_IRQ0_ENA_MASK             0x00008000
+#define         TV_DMA_FRAME_IRQ1_ENA(irq)             ((irq)<<14)
+#define         TV_DMA_FRAME_IRQ1_ENA_MASK             0x00004000
+#define         TV_DMA_FF_UNDERFLOW_ENA(unerrun)       ((unerrun)<<13)
+#define         TV_DMA_FF_UNDERFLOW_ENA_MASK           0x00002000
+#define         TVSYNC_IRQ_ENA(irq)                    ((irq)<<12)
+#define         TVSYNC_IRQ_ENA_MASK                    0x00001000
+#define         TV_FRAME_IRQ0_ENA(irq)                 ((irq)<<11)
+#define         TV_FRAME_IRQ0_ENA_MASK                 0x00000800
+#define         TV_FRAME_IRQ1_ENA(irq)                 ((irq)<<10)
+#define         TV_FRAME_IRQ1_ENA_MASK                 0x00000400
+#define         TV_GRA_FF_UNDERFLOW_ENA(unerrun)       ((unerrun)<<9)
+#define         TV_GRA_FF_UNDERFLOW_ENA_MASK           0x00000200
+#define         TV_FRAMEDONE_ENA(irq)                  ((irq)<<8)
+#define         TV_FRAMEDONE_ENA_MASK                  0x00000100
+
+/* FIXME - JUST GUESS */
+#define         PN2_DMA_FRAME_IRQ0_ENA(irq)            ((irq)<<7)
+#define         PN2_DMA_FRAME_IRQ0_ENA_MASK            0x00000080
+#define         PN2_DMA_FRAME_IRQ1_ENA(irq)            ((irq)<<6)
+#define         PN2_DMA_FRAME_IRQ1_ENA_MASK            0x00000040
+#define         PN2_DMA_FF_UNDERFLOW_ENA(ff)           ((ff)<<5)
+#define         PN2_DMA_FF_UNDERFLOW_ENA_MASK          0x00000020
+#define         PN2_GRA_FRAME_IRQ0_ENA(irq)            ((irq)<<3)
+#define         PN2_GRA_FRAME_IRQ0_ENA_MASK            0x00000008
+#define         PN2_GRA_FRAME_IRQ1_ENA(irq)            ((irq)<<2)
+#define         PN2_GRA_FRAME_IRQ1_ENA_MASK            0x04000004
+#define         PN2_GRA_FF_UNDERFLOW_ENA(ff)           ((ff)<<1)
+#define         PN2_GRA_FF_UNDERFLOW_ENA_MASK          0x00000002
+#define         PN2_VSYNC_IRQ_ENA(irq)                 ((irq)<<0)
+#define         PN2_SYNC_IRQ_ENA_MASK                  0x00000001
+
+#define gf0_imask(id)  ((id) ? (((id) & 1) ? TV_FRAME_IRQ0_ENA_MASK \
+               : PN2_GRA_FRAME_IRQ0_ENA_MASK) : GRA_FRAME_IRQ0_ENA_MASK)
+#define gf1_imask(id)  ((id) ? (((id) & 1) ? TV_FRAME_IRQ1_ENA_MASK \
+               : PN2_GRA_FRAME_IRQ1_ENA_MASK) : GRA_FRAME_IRQ1_ENA_MASK)
+#define vsync_imask(id)        ((id) ? (((id) & 1) ? TVSYNC_IRQ_ENA_MASK \
+               : PN2_SYNC_IRQ_ENA_MASK) : VSYNC_IRQ_ENA_MASK)
+#define vsync_imasks   (vsync_imask(0) | vsync_imask(1))
+
+#define display_done_imask(id) ((id) ? (((id) & 1) ? TV_FRAMEDONE_ENA_MASK\
+       : (PN2_DMA_FRAME_IRQ0_ENA_MASK | PN2_DMA_FRAME_IRQ1_ENA_MASK))\
+       : DUMB_FRAMEDONE_ENA_MASK)
+
+#define display_done_imasks    (display_done_imask(0) | display_done_imask(1))
+
+#define vf0_imask(id)  ((id) ? (((id) & 1) ? TV_DMA_FRAME_IRQ0_ENA_MASK \
+               : PN2_DMA_FRAME_IRQ0_ENA_MASK) : DMA_FRAME_IRQ0_ENA_MASK)
+#define vf1_imask(id)  ((id) ? (((id) & 1) ? TV_DMA_FRAME_IRQ1_ENA_MASK \
+               : PN2_DMA_FRAME_IRQ1_ENA_MASK) : DMA_FRAME_IRQ1_ENA_MASK)
+
+#define gfx_imasks     (gf0_imask(0) | gf1_imask(0) | gf0_imask(1) | \
+               gf1_imask(1))
+#define vid_imasks     (vf0_imask(0) | vf1_imask(0) | vf0_imask(1) | \
+               vf1_imask(1))
+#define vid_imask(id)  (display_done_imask(id))
+
+#define pn1_imasks     (gf0_imask(0) | gf1_imask(0) | vsync_imask(0) | \
+               display_done_imask(0) | vf0_imask(0) | vf1_imask(0))
+#define tv_imasks      (gf0_imask(1) | gf1_imask(1) | vsync_imask(1) | \
+               display_done_imask(1) | vf0_imask(1) | vf1_imask(1))
+#define path_imasks(id)        ((id) ? (tv_imasks) : (pn1_imasks))
+
+/* error indications */
+#define vid_udflow_imask(id)   ((id) ? (((id) & 1) ? \
+       (TV_DMA_FF_UNDERFLOW_ENA_MASK) : (PN2_DMA_FF_UNDERFLOW_ENA_MASK)) : \
+       (DMA_FF_UNDERFLOW_ENA_MASK))
+#define gfx_udflow_imask(id)   ((id) ? (((id) & 1) ? \
+       (TV_GRA_FF_UNDERFLOW_ENA_MASK) : (PN2_GRA_FF_UNDERFLOW_ENA_MASK)) : \
+       (GRA_FF_UNDERFLOW_ENA_MASK))
+
+#define err_imask(id) (vid_udflow_imask(id) | gfx_udflow_imask(id) | \
+       AXI_BUS_ERROR_IRQ_ENA_MASK | AXI_LATENCY_TOO_LONG_IRQ_ENA_MASK)
+#define err_imasks (err_imask(0) | err_imask(1) | err_imask(2))
+/* LCD Interrupt Status Register */
+#define SPU_IRQ_ISR                    0x01C4
+#define         DMA_FRAME_IRQ0(irq)            ((irq)<<31)
+#define         DMA_FRAME_IRQ0_MASK            0x80000000
+#define         DMA_FRAME_IRQ1(irq)            ((irq)<<30)
+#define         DMA_FRAME_IRQ1_MASK            0x40000000
+#define         DMA_FF_UNDERFLOW(ff)           ((ff)<<29)
+#define         DMA_FF_UNDERFLOW_MASK          0x20000000
+#define         AXI_BUS_ERROR_IRQ(irq)         ((irq)<<28)
+#define         AXI_BUS_ERROR_IRQ_MASK         0x10000000
+#define         GRA_FRAME_IRQ0(irq)            ((irq)<<27)
+#define         GRA_FRAME_IRQ0_MASK            0x08000000
+#define         GRA_FRAME_IRQ1(irq)            ((irq)<<26)
+#define         GRA_FRAME_IRQ1_MASK            0x04000000
+#define         GRA_FF_UNDERFLOW(ff)           ((ff)<<25)
+#define         GRA_FF_UNDERFLOW_MASK          0x02000000
+#define         VSYNC_IRQ(vsync_irq)           ((vsync_irq)<<23)
+#define         VSYNC_IRQ_MASK                 0x00800000
+#define         DUMB_FRAMEDONE(fdone)          ((fdone)<<22)
+#define         DUMB_FRAMEDONE_MASK            0x00400000
+#define         TWC_FRAMEDONE(fdone)           ((fdone)<<21)
+#define         TWC_FRAMEDONE_MASK             0x00200000
+#define         HWC_FRAMEDONE(fdone)           ((fdone)<<20)
+#define         HWC_FRAMEDONE_MASK             0x00100000
+#define         SLV_IRQ(irq)                   ((irq)<<19)
+#define         SLV_IRQ_MASK                   0x00080000
+#define         SPI_IRQ(irq)                   ((irq)<<18)
+#define         SPI_IRQ_MASK                   0x00040000
+#define         PWRDN_IRQ(irq)                 ((irq)<<17)
+#define         PWRDN_IRQ_MASK                 0x00020000
+#define         AXI_LATENCY_TOO_LONGR_IRQ(irq) ((irq)<<16)
+#define         AXI_LATENCY_TOO_LONGR_IRQ_MASK 0x00010000
+#define         TV_DMA_FRAME_IRQ0(irq)         ((irq)<<15)
+#define         TV_DMA_FRAME_IRQ0_MASK         0x00008000
+#define         TV_DMA_FRAME_IRQ1(irq)         ((irq)<<14)
+#define         TV_DMA_FRAME_IRQ1_MASK         0x00004000
+#define         TV_DMA_FF_UNDERFLOW(unerrun)   ((unerrun)<<13)
+#define         TV_DMA_FF_UNDERFLOW_MASK       0x00002000
+#define         TVSYNC_IRQ(irq)                ((irq)<<12)
+#define         TVSYNC_IRQ_MASK                0x00001000
+#define         TV_FRAME_IRQ0(irq)             ((irq)<<11)
+#define         TV_FRAME_IRQ0_MASK             0x00000800
+#define         TV_FRAME_IRQ1(irq)             ((irq)<<10)
+#define         TV_FRAME_IRQ1_MASK             0x00000400
+#define         TV_GRA_FF_UNDERFLOW(unerrun)   ((unerrun)<<9)
+#define         TV_GRA_FF_UNDERFLOW_MASK       0x00000200
+#define         PN2_DMA_FRAME_IRQ0(irq)        ((irq)<<7)
+#define         PN2_DMA_FRAME_IRQ0_MASK        0x00000080
+#define         PN2_DMA_FRAME_IRQ1(irq)        ((irq)<<6)
+#define         PN2_DMA_FRAME_IRQ1_MASK        0x00000040
+#define         PN2_DMA_FF_UNDERFLOW(ff)       ((ff)<<5)
+#define         PN2_DMA_FF_UNDERFLOW_MASK      0x00000020
+#define         PN2_GRA_FRAME_IRQ0(irq)        ((irq)<<3)
+#define         PN2_GRA_FRAME_IRQ0_MASK        0x00000008
+#define         PN2_GRA_FRAME_IRQ1(irq)        ((irq)<<2)
+#define         PN2_GRA_FRAME_IRQ1_MASK        0x04000004
+#define         PN2_GRA_FF_UNDERFLOW(ff)       ((ff)<<1)
+#define         PN2_GRA_FF_UNDERFLOW_MASK      0x00000002
+#define         PN2_VSYNC_IRQ(irq)             ((irq)<<0)
+#define         PN2_SYNC_IRQ_MASK              0x00000001
+
+/* LCD FIFO Depth register */
+#define LCD_FIFO_DEPTH                 0x01c8
+#define         VIDEO_FIFO(fi)                 ((fi) << 0)
+#define         VIDEO_FIFO_MASK                0x00000003
+#define         GRAPHIC_FIFO(fi)               ((fi) << 2)
+#define         GRAPHIC_FIFO_MASK              0x0000000c
+
+/* read-only */
+#define         DMA_FRAME_IRQ0_LEVEL_MASK              0x00008000
+#define         DMA_FRAME_IRQ1_LEVEL_MASK              0x00004000
+#define         DMA_FRAME_CNT_ISR_MASK                 0x00003000
+#define         GRA_FRAME_IRQ0_LEVEL_MASK              0x00000800
+#define         GRA_FRAME_IRQ1_LEVEL_MASK              0x00000400
+#define         GRA_FRAME_CNT_ISR_MASK                 0x00000300
+#define         VSYNC_IRQ_LEVEL_MASK                   0x00000080
+#define         DUMB_FRAMEDONE_LEVEL_MASK              0x00000040
+#define         TWC_FRAMEDONE_LEVEL_MASK               0x00000020
+#define         HWC_FRAMEDONE_LEVEL_MASK               0x00000010
+#define         SLV_FF_EMPTY_MASK                      0x00000008
+#define         DMA_FF_ALLEMPTY_MASK                   0x00000004
+#define         GRA_FF_ALLEMPTY_MASK                   0x00000002
+#define         PWRDN_IRQ_LEVEL_MASK                   0x00000001
+
+/* 32 bit LCD Interrupt Reset Status*/
+#define SPU_IRQ_RSR                            (0x01C8)
+/* 32 bit Panel Path Graphic Partial Display Horizontal Control Register*/
+#define LCD_GRA_CUTHPXL                                (0x01CC)
+/* 32 bit Panel Path Graphic Partial Display Vertical Control Register*/
+#define LCD_GRA_CUTVLN                         (0x01D0)
+/* 32 bit TV Path Graphic Partial Display        Horizontal Control Register*/
+#define LCD_TVG_CUTHPXL                                (0x01D4)
+/* 32 bit TV Path Graphic Partial Display Vertical Control Register*/
+#define LCD_TVG_CUTVLN                         (0x01D8)
+/* 32 bit LCD Global Control Register*/
+#define LCD_TOP_CTRL                           (0x01DC)
+/* 32 bit LCD SQU Line Buffer Control Register 1*/
+#define LCD_SQULN1_CTRL                                (0x01E0)
+/* 32 bit LCD SQU Line Buffer Control Register 2*/
+#define LCD_SQULN2_CTRL                                (0x01E4)
+#define squln_ctrl(id) ((id) ? (((id) & 1) ? LCD_SQULN2_CTRL : \
+                       LCD_PN2_SQULN1_CTRL) : LCD_SQULN1_CTRL)
+
+/* 32 bit LCD Mixed Overlay Control Register */
+#define LCD_AFA_ALL2ONE                                (0x01E8)
+
+#define LCD_PN2_SCLK_DIV                       (0x01EC)
+#define LCD_PN2_TCLK_DIV                       (0x01F0)
+#define LCD_LVDS_SCLK_DIV_WR                   (0x01F4)
+#define LCD_LVDS_SCLK_DIV_RD                   (0x01FC)
+#define PN2_LCD_DMA_START_ADDR_Y0              (0x0200)
+#define PN2_LCD_DMA_START_ADDR_U0              (0x0204)
+#define PN2_LCD_DMA_START_ADDR_V0              (0x0208)
+#define PN2_LCD_DMA_START_ADDR_C0              (0x020C)
+#define PN2_LCD_DMA_START_ADDR_Y1              (0x0210)
+#define PN2_LCD_DMA_START_ADDR_U1              (0x0214)
+#define PN2_LCD_DMA_START_ADDR_V1              (0x0218)
+#define PN2_LCD_DMA_START_ADDR_C1              (0x021C)
+#define PN2_LCD_DMA_PITCH_YC                   (0x0220)
+#define PN2_LCD_DMA_PITCH_UV                   (0x0224)
+#define PN2_LCD_DMA_OVSA_HPXL_VLN              (0x0228)
+#define PN2_LCD_DMA_HPXL_VLN                   (0x022C)
+#define PN2_LCD_DMAZM_HPXL_VLN                 (0x0230)
+#define PN2_LCD_GRA_START_ADDR0                        (0x0234)
+#define PN2_LCD_GRA_START_ADDR1                        (0x0238)
+#define PN2_LCD_GRA_PITCH                      (0x023C)
+#define PN2_LCD_GRA_OVSA_HPXL_VLN              (0x0240)
+#define PN2_LCD_GRA_HPXL_VLN                   (0x0244)
+#define PN2_LCD_GRAZM_HPXL_VLN                 (0x0248)
+#define PN2_LCD_HWC_OVSA_HPXL_VLN              (0x024C)
+#define PN2_LCD_HWC_HPXL_VLN                   (0x0250)
+#define LCD_PN2_V_H_TOTAL                      (0x0254)
+#define LCD_PN2_V_H_ACTIVE                     (0x0258)
+#define LCD_PN2_H_PORCH                                (0x025C)
+#define LCD_PN2_V_PORCH                                (0x0260)
+#define LCD_PN2_BLANKCOLOR                     (0x0264)
+#define LCD_PN2_ALPHA_COLOR1                   (0x0268)
+#define LCD_PN2_ALPHA_COLOR2                   (0x026C)
+#define LCD_PN2_COLORKEY_Y                     (0x0270)
+#define LCD_PN2_COLORKEY_U                     (0x0274)
+#define LCD_PN2_COLORKEY_V                     (0x0278)
+#define LCD_PN2_SEPXLCNT                       (0x027C)
+#define LCD_TV_V_H_TOTAL_FLD                   (0x0280)
+#define LCD_TV_V_PORCH_FLD                     (0x0284)
+#define LCD_TV_SEPXLCNT_FLD                    (0x0288)
+
+#define LCD_2ND_ALPHA                          (0x0294)
+#define LCD_PN2_CONTRAST                       (0x0298)
+#define LCD_PN2_SATURATION                     (0x029c)
+#define LCD_PN2_CBSH_HUE                       (0x02a0)
+#define LCD_TIMING_EXT                         (0x02C0)
+#define LCD_PN2_LAYER_ALPHA_SEL1               (0x02c4)
+#define LCD_PN2_CTRL0                          (0x02C8)
+#define TV_LAYER_ALPHA_SEL1                    (0x02cc)
+#define LCD_SMPN2_CTRL                         (0x02D0)
+#define LCD_IO_OVERL_MAP_CTRL                  (0x02D4)
+#define LCD_DUMB2_CTRL                         (0x02d8)
+#define LCD_PN2_CTRL1                          (0x02DC)
+#define PN2_IOPAD_CONTROL                      (0x02E0)
+#define LCD_PN2_SQULN1_CTRL                    (0x02E4)
+#define PN2_LCD_GRA_CUTHPXL                    (0x02e8)
+#define PN2_LCD_GRA_CUTVLN                     (0x02ec)
+#define LCD_PN2_SQULN2_CTRL                    (0x02F0)
+#define ALL_LAYER_ALPHA_SEL                    (0x02F4)
+
+/* pxa988 has different MASTER_CTRL from MMP3/MMP2 */
+#ifdef CONFIG_CPU_PXA988
+#define TIMING_MASTER_CONTROL                  (0x01F4)
+#define MASTER_ENH(id)                         (1 << ((id) + 5))
+#define MASTER_ENV(id)                         (1 << ((id) + 6))
+#else
+#define TIMING_MASTER_CONTROL                  (0x02F8)
+#define MASTER_ENH(id)                         (1 << (id))
+#define MASTER_ENV(id)                         (1 << ((id) + 4))
+#endif
+
+#define DSI_START_SEL_SHIFT(id)                (((id) << 1) + 8)
+#define timing_master_config(path, dsi_id, lcd_id) \
+       (MASTER_ENH(path) | MASTER_ENV(path) | \
+       (((lcd_id) + ((dsi_id) << 1)) << DSI_START_SEL_SHIFT(path)))
+
+#define LCD_2ND_BLD_CTL                                (0x02Fc)
+#define LVDS_SRC_MASK                          (3 << 30)
+#define LVDS_SRC_SHIFT                         (30)
+#define LVDS_FMT_MASK                          (1 << 28)
+#define LVDS_FMT_SHIFT                         (28)
+
+#define CLK_SCLK       (1 << 0)
+#define CLK_LVDS_RD    (1 << 1)
+#define CLK_LVDS_WR    (1 << 2)
+
+#define gra_partdisp_ctrl_hor(id)      ((id) ? (((id) & 1) ? \
+       LCD_TVG_CUTHPXL : PN2_LCD_GRA_CUTHPXL) : LCD_GRA_CUTHPXL)
+#define gra_partdisp_ctrl_ver(id)      ((id) ? (((id) & 1) ? \
+       LCD_TVG_CUTVLN : PN2_LCD_GRA_CUTVLN) : LCD_GRA_CUTVLN)
+
+/*
+ * defined Video Memory Color format for DMA control 0 register
+ * DMA0 bit[23:20]
+ */
+#define VMODE_RGB565           0x0
+#define VMODE_RGB1555          0x1
+#define VMODE_RGB888PACKED     0x2
+#define VMODE_RGB888UNPACKED   0x3
+#define VMODE_RGBA888          0x4
+#define VMODE_YUV422PACKED     0x5
+#define VMODE_YUV422PLANAR     0x6
+#define VMODE_YUV420PLANAR     0x7
+#define VMODE_SMPNCMD          0x8
+#define VMODE_PALETTE4BIT      0x9
+#define VMODE_PALETTE8BIT      0xa
+#define VMODE_RESERVED         0xb
+
+/*
+ * defined Graphic Memory Color format for DMA control 0 register
+ * DMA0 bit[19:16]
+ */
+#define GMODE_RGB565           0x0
+#define GMODE_RGB1555          0x1
+#define GMODE_RGB888PACKED     0x2
+#define GMODE_RGB888UNPACKED   0x3
+#define GMODE_RGBA888          0x4
+#define GMODE_YUV422PACKED     0x5
+#define GMODE_YUV422PLANAR     0x6
+#define GMODE_YUV420PLANAR     0x7
+#define GMODE_SMPNCMD          0x8
+#define GMODE_PALETTE4BIT      0x9
+#define GMODE_PALETTE8BIT      0xa
+#define GMODE_RESERVED         0xb
+
+/*
+ * define for DMA control 1 register
+ */
+#define DMA1_FRAME_TRIG                31 /* bit location */
+#define DMA1_VSYNC_MODE                28
+#define DMA1_VSYNC_INV         27
+#define DMA1_CKEY              24
+#define DMA1_CARRY             23
+#define DMA1_LNBUF_ENA         22
+#define DMA1_GATED_ENA         21
+#define DMA1_PWRDN_ENA         20
+#define DMA1_DSCALE            18
+#define DMA1_ALPHA_MODE                16
+#define DMA1_ALPHA             08
+#define DMA1_PXLCMD            00
+
+/*
+ * defined for Configure Dumb Mode
+ * DUMB LCD Panel bit[31:28]
+ */
+#define DUMB16_RGB565_0                0x0
+#define DUMB16_RGB565_1                0x1
+#define DUMB18_RGB666_0                0x2
+#define DUMB18_RGB666_1                0x3
+#define DUMB12_RGB444_0                0x4
+#define DUMB12_RGB444_1                0x5
+#define DUMB24_RGB888_0                0x6
+#define DUMB_BLANK             0x7
+
+/*
+ * defined for Configure I/O Pin Allocation Mode
+ * LCD LCD I/O Pads control register bit[3:0]
+ */
+#define IOPAD_DUMB24           0x0
+#define IOPAD_DUMB18SPI                0x1
+#define IOPAD_DUMB18GPIO       0x2
+#define IOPAD_DUMB16SPI                0x3
+#define IOPAD_DUMB16GPIO       0x4
+#define IOPAD_DUMB12           0x5
+#define IOPAD_SMART18SPI       0x6
+#define IOPAD_SMART16SPI       0x7
+#define IOPAD_SMART8BOTH       0x8
+#define IOPAD_DUMB18_SMART8    0x9
+#define IOPAD_DUMB16_SMART8SPI 0xa
+#define IOPAD_DUMB16_SMART8GPIO        0xb
+#define IOPAD_DUMB16_DUMB16    0xc
+#define IOPAD_SMART8_SMART8    0xc
+
+/*
+ *defined for indicating boundary and cycle burst length
+ */
+#define  CFG_BOUNDARY_1KB                      (1<<5)
+#define  CFG_BOUNDARY_4KB                      (0<<5)
+#define         CFG_CYC_BURST_LEN16                    (1<<4)
+#define         CFG_CYC_BURST_LEN8                     (0<<4)
+
+/*
+ * defined Dumb Panel Clock Divider register
+ * SCLK_Source bit[31]
+ */
+ /* 0: PLL clock select*/
+#define AXI_BUS_SEL                    0x80000000
+#define CCD_CLK_SEL                    0x40000000
+#define DCON_CLK_SEL                   0x20000000
+#define ENA_CLK_INT_DIV                        CONFIG_FB_DOVE_CLCD_SCLK_DIV
+#define IDLE_CLK_INT_DIV               0x1       /* idle Integer Divider */
+#define DIS_CLK_INT_DIV                        0x0       /* Disable Integer Divider */
+
+/* SRAM ID */
+#define SRAMID_GAMMA_YR                        0x0
+#define SRAMID_GAMMA_UG                        0x1
+#define SRAMID_GAMMA_VB                        0x2
+#define SRAMID_PALATTE                 0x3
+#define SRAMID_HWC                     0xf
+
+/* SRAM INIT Read/Write */
+#define SRAMID_INIT_READ               0x0
+#define SRAMID_INIT_WRITE              0x2
+#define SRAMID_INIT_DEFAULT            0x3
+
+/*
+ * defined VSYNC selection mode for DMA control 1 register
+ * DMA1 bit[30:28]
+ */
+#define VMODE_SMPN                     0x0
+#define VMODE_SMPNIRQ                  0x1
+#define VMODE_DUMB                     0x2
+#define VMODE_IPE                      0x3
+#define VMODE_IRE                      0x4
+
+/*
+ * defined Configure Alpha and Alpha mode for DMA control 1 register
+ * DMA1 bit[15:08](alpha) / bit[17:16](alpha mode)
+ */
+/* ALPHA mode */
+#define MODE_ALPHA_DMA                 0x0
+#define MODE_ALPHA_GRA                 0x1
+#define MODE_ALPHA_CFG                 0x2
+
+/* alpha value */
+#define ALPHA_NOGRAPHIC                        0xFF      /* all video, no graphic */
+#define ALPHA_NOVIDEO                  0x00      /* all graphic, no video */
+#define ALPHA_GRAPHNVIDEO              0x0F      /* Selects graphic & video */
+
+/*
+ * defined Pixel Command for DMA control 1 register
+ * DMA1 bit[07:00]
+ */
+#define PIXEL_CMD                      0x81
+
+/* DSI */
+/* DSI1 - 4 Lane Controller base */
+#define DSI1_REGS_PHYSICAL_BASE                0xD420B800
+/* DSI2 - 3 Lane Controller base */
+#define DSI2_REGS_PHYSICAL_BASE                0xD420BA00
+
+/*        DSI Controller Registers        */
+struct dsi_lcd_regs {
+#define DSI_LCD1_CTRL_0  0x100   /* DSI Active Panel 1 Control register 0 */
+#define DSI_LCD1_CTRL_1  0x104   /* DSI Active Panel 1 Control register 1 */
+       u32 ctrl0;
+       u32 ctrl1;
+       u32 reserved1[2];
+
+#define DSI_LCD1_TIMING_0              0x110   /* Timing register 0 */
+#define DSI_LCD1_TIMING_1              0x114   /* Timing register 1 */
+#define DSI_LCD1_TIMING_2              0x118   /* Timing register 2 */
+#define DSI_LCD1_TIMING_3              0x11C   /* Timing register 3 */
+#define DSI_LCD1_WC_0                  0x120   /* Word Count register 0 */
+#define DSI_LCD1_WC_1                  0x124   /* Word Count register 1 */
+#define DSI_LCD1_WC_2                  0x128    /* Word Count register 2 */
+       u32 timing0;
+       u32 timing1;
+       u32 timing2;
+       u32 timing3;
+       u32 wc0;
+       u32 wc1;
+       u32 wc2;
+       u32 reserved2[1];
+       u32 slot_cnt0;
+       u32 slot_cnt1;
+       u32 reserved3[2];
+       u32 status_0;
+       u32 status_1;
+       u32 status_2;
+       u32 status_3;
+       u32 status_4;
+};
+
+struct dsi_regs {
+#define DSI_CTRL_0       0x000   /* DSI control register 0 */
+#define DSI_CTRL_1       0x004   /* DSI control register 1 */
+       u32 ctrl0;
+       u32 ctrl1;
+       u32 reserved1[2];
+       u32 irq_status;
+       u32 irq_mask;
+       u32 reserved2[2];
+
+#define DSI_CPU_CMD_0   0x020   /* DSI CPU packet command register 0 */
+#define DSI_CPU_CMD_1   0x024   /* DSU CPU Packet Command Register 1 */
+#define DSI_CPU_CMD_3  0x02C   /* DSU CPU Packet Command Register 3 */
+#define DSI_CPU_WDAT_0 0x030   /* DSI CUP */
+       u32 cmd0;
+       u32 cmd1;
+       u32 cmd2;
+       u32 cmd3;
+       u32 dat0;
+       u32 status0;
+       u32 status1;
+       u32 status2;
+       u32 status3;
+       u32 status4;
+       u32 reserved3[2];
+
+       u32 smt_cmd;
+       u32 smt_ctrl0;
+       u32 smt_ctrl1;
+       u32 reserved4[1];
+
+       u32 rx0_status;
+
+/* Rx Packet Header - data from slave device */
+#define DSI_RX_PKT_HDR_0 0x064
+       u32 rx0_header;
+       u32 rx1_status;
+       u32 rx1_header;
+       u32 rx_ctrl;
+       u32 rx_ctrl1;
+       u32 rx2_status;
+       u32 rx2_header;
+       u32 reserved5[1];
+
+       u32 phy_ctrl1;
+#define DSI_PHY_CTRL_2         0x088   /* DSI DPHI Control Register 2 */
+#define DSI_PHY_CTRL_3         0x08C   /* DPHY Control Register 3 */
+       u32 phy_ctrl2;
+       u32 phy_ctrl3;
+       u32 phy_status0;
+       u32 phy_status1;
+       u32 reserved6[5];
+       u32 phy_status2;
+
+#define DSI_PHY_RCOMP_0                0x0B0   /* DPHY Rcomp Control Register */
+       u32 phy_rcomp0;
+       u32 reserved7[3];
+#define DSI_PHY_TIME_0         0x0C0   /* DPHY Timing Control Register 0 */
+#define DSI_PHY_TIME_1         0x0C4   /* DPHY Timing Control Register 1 */
+#define DSI_PHY_TIME_2         0x0C8   /* DPHY Timing Control Register 2 */
+#define DSI_PHY_TIME_3         0x0CC   /* DPHY Timing Control Register 3 */
+#define DSI_PHY_TIME_4         0x0D0   /* DPHY Timing Control Register 4 */
+#define DSI_PHY_TIME_5         0x0D4   /* DPHY Timing Control Register 5 */
+       u32 phy_timing0;
+       u32 phy_timing1;
+       u32 phy_timing2;
+       u32 phy_timing3;
+       u32 phy_code_0;
+       u32 phy_code_1;
+       u32 reserved8[2];
+       u32 mem_ctrl;
+       u32 tx_timer;
+       u32 rx_timer;
+       u32 turn_timer;
+       u32 reserved9[4];
+
+#define DSI_LCD1_CTRL_0  0x100   /* DSI Active Panel 1 Control register 0 */
+#define DSI_LCD1_CTRL_1  0x104   /* DSI Active Panel 1 Control register 1 */
+#define DSI_LCD1_TIMING_0              0x110   /* Timing register 0 */
+#define DSI_LCD1_TIMING_1              0x114   /* Timing register 1 */
+#define DSI_LCD1_TIMING_2              0x118   /* Timing register 2 */
+#define DSI_LCD1_TIMING_3              0x11C   /* Timing register 3 */
+#define DSI_LCD1_WC_0                  0x120   /* Word Count register 0 */
+#define DSI_LCD1_WC_1                  0x124   /* Word Count register 1 */
+#define DSI_LCD1_WC_2                  0x128   /* Word Count register 2 */
+       struct dsi_lcd_regs lcd1;
+       u32 reserved10[11];
+       struct dsi_lcd_regs lcd2;
+};
+
+#define DSI_LCD2_CTRL_0  0x180   /* DSI Active Panel 2 Control register 0 */
+#define DSI_LCD2_CTRL_1  0x184   /* DSI Active Panel 2 Control register 1 */
+#define DSI_LCD2_TIMING_0              0x190   /* Timing register 0 */
+#define DSI_LCD2_TIMING_1              0x194   /* Timing register 1 */
+#define DSI_LCD2_TIMING_2              0x198   /* Timing register 2 */
+#define DSI_LCD2_TIMING_3              0x19C   /* Timing register 3 */
+#define DSI_LCD2_WC_0                  0x1A0   /* Word Count register 0 */
+#define DSI_LCD2_WC_1                  0x1A4   /* Word Count register 1 */
+#define DSI_LCD2_WC_2                  0x1A8    /* Word Count register 2 */
+
+/*     DSI_CTRL_0              0x0000  DSI Control Register 0 */
+#define DSI_CTRL_0_CFG_SOFT_RST                        (1<<31)
+#define DSI_CTRL_0_CFG_SOFT_RST_REG            (1<<30)
+#define DSI_CTRL_0_CFG_LCD1_TX_EN              (1<<8)
+#define DSI_CTRL_0_CFG_LCD1_SLV                        (1<<4)
+#define DSI_CTRL_0_CFG_LCD1_EN                 (1<<0)
+
+/*     DSI_CTRL_1              0x0004  DSI Control Register 1 */
+#define DSI_CTRL_1_CFG_EOTP                    (1<<8)
+#define DSI_CTRL_1_CFG_RSVD                    (2<<4)
+#define DSI_CTRL_1_CFG_LCD2_VCH_NO_MASK                (3<<2)
+#define DSI_CTRL_1_CFG_LCD2_VCH_NO_SHIFT       2
+#define DSI_CTRL_1_CFG_LCD1_VCH_NO_MASK                (3<<0)
+#define DSI_CTRL_1_CFG_LCD1_VCH_NO_SHIFT       0
+
+/*     DSI_LCD1_CTRL_1 0x0104  DSI Active Panel 1 Control Register 1 */
+/* LCD 1 Vsync Reset Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_VSYNC_RST_EN     (1<<31)
+/* LCD 1 2K Pixel Buffer Mode Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_M2K_EN           (1<<30)
+/*             Bit(s) DSI_LCD1_CTRL_1_RSRV_29_23 reserved */
+/* Long Blanking Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HLP_PKT_EN       (1<<22)
+/* Extra Long Blanking Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HEX_PKT_EN       (1<<21)
+/* Front Porch Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HFP_PKT_EN       (1<<20)
+/* hact Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HACT_PKT_EN      (1<<19)
+/* Back Porch Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HBP_PKT_EN       (1<<18)
+/* hse Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HSE_PKT_EN       (1<<17)
+/* hsa Packet Enable */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HSA_PKT_EN       (1<<16)
+/* All Item Enable after Pixel Data */
+#define        DSI_LCD1_CTRL_1_CFG_L1_ALL_SLOT_EN      (1<<15)
+/* Extra Long Packet Enable after Pixel Data */
+#define        DSI_LCD1_CTRL_1_CFG_L1_HEX_SLOT_EN      (1<<14)
+/*             Bit(s) DSI_LCD1_CTRL_1_RSRV_13_11 reserved */
+/* Turn Around Bus at Last h Line */
+#define        DSI_LCD1_CTRL_1_CFG_L1_LAST_LINE_TURN   (1<<10)
+/* Go to Low Power Every Frame */
+#define        DSI_LCD1_CTRL_1_CFG_L1_LPM_FRAME_EN     (1<<9)
+/* Go to Low Power Every Line */
+#define        DSI_LCD1_CTRL_1_CFG_L1_LPM_LINE_EN      (1<<8)
+/*             Bit(s) DSI_LCD1_CTRL_1_RSRV_7_4 reserved */
+/* DSI Transmission Mode for LCD 1 */
+#define DSI_LCD1_CTRL_1_CFG_L1_BURST_MODE_SHIFT        2
+#define DSI_LCD1_CTRL_1_CFG_L1_BURST_MODE_MASK (3<<2)
+/* LCD 1 Input Data RGB Mode for LCD 1 */
+#define DSI_LCD2_CTRL_1_CFG_L1_RGB_TYPE_SHIFT  0
+#define DSI_LCD2_CTRL_1_CFG_L1_RGB_TYPE_MASK   (3<<2)
+
+/*     DSI_PHY_CTRL_2          0x0088  DPHY Control Register 2 */
+/*             Bit(s) DSI_PHY_CTRL_2_RSRV_31_12 reserved */
+/* DPHY LP Receiver Enable */
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_RESC_EN_MASK        (0xf<<8)
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_RESC_EN_SHIFT       8
+/* DPHY Data Lane Enable */
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_MASK             (0xf<<4)
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_SHIFT            4
+/* DPHY Bus Turn Around */
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_TURN_MASK           (0xf)
+#define        DSI_PHY_CTRL_2_CFG_CSR_LANE_TURN_SHIFT          0
+
+/*     DSI_CPU_CMD_1           0x0024  DSI CPU Packet Command Register 1 */
+/*             Bit(s) DSI_CPU_CMD_1_RSRV_31_24 reserved */
+/* LPDT TX Enable */
+#define        DSI_CPU_CMD_1_CFG_TXLP_LPDT_MASK                (0xf<<20)
+#define        DSI_CPU_CMD_1_CFG_TXLP_LPDT_SHIFT               20
+/* ULPS TX Enable */
+#define        DSI_CPU_CMD_1_CFG_TXLP_ULPS_MASK                (0xf<<16)
+#define        DSI_CPU_CMD_1_CFG_TXLP_ULPS_SHIFT               16
+/* Low Power TX Trigger Code */
+#define        DSI_CPU_CMD_1_CFG_TXLP_TRIGGER_CODE_MASK        (0xffff)
+#define        DSI_CPU_CMD_1_CFG_TXLP_TRIGGER_CODE_SHIFT       0
+
+/*     DSI_PHY_TIME_0  0x00c0  DPHY Timing Control Register 0 */
+/* Length of HS Exit Period in tx_clk_esc Cycles */
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_EXIT_MASK        (0xff<<24)
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_EXIT_SHIFT       24
+/* DPHY HS Trail Period Length */
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_TRAIL_MASK       (0xff<<16)
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_TRAIL_SHIFT      16
+/* DPHY HS Zero State Length */
+#define        DSI_PHY_TIME_0_CDG_CSR_TIME_HS_ZERO_MASK        (0xff<<8)
+#define        DSI_PHY_TIME_0_CDG_CSR_TIME_HS_ZERO_SHIFT       8
+/* DPHY HS Prepare State Length */
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_PREP_MASK        (0xff)
+#define        DSI_PHY_TIME_0_CFG_CSR_TIME_HS_PREP_SHIFT       0
+
+/*     DSI_PHY_TIME_1          0x00c4  DPHY Timing Control Register 1 */
+/* Time to Drive LP-00 by New Transmitter */
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GET_MASK         (0xff<<24)
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GET_SHIFT        24
+/* Time to Drive LP-00 after Turn Request */
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GO_MASK          (0xff<<16)
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GO_SHIFT         16
+/* DPHY HS Wakeup Period Length */
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_WAKEUP_MASK         (0xffff)
+#define        DSI_PHY_TIME_1_CFG_CSR_TIME_WAKEUP_SHIFT        0
+
+/*     DSI_PHY_TIME_2          0x00c8  DPHY Timing Control Register 2 */
+/* DPHY CLK Exit Period Length */
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_EXIT_MASK        (0xff<<24)
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_EXIT_SHIFT       24
+/* DPHY CLK Trail Period Length */
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_TRAIL_MASK       (0xff<<16)
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_TRAIL_SHIFT      16
+/* DPHY CLK Zero State Length */
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_ZERO_MASK        (0xff<<8)
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_ZERO_SHIFT       8
+/* DPHY CLK LP Length */
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_LPX_MASK         (0xff)
+#define        DSI_PHY_TIME_2_CFG_CSR_TIME_CK_LPX_SHIFT        0
+
+/*     DSI_PHY_TIME_3          0x00cc  DPHY Timing Control Register 3 */
+/*             Bit(s) DSI_PHY_TIME_3_RSRV_31_16 reserved */
+/* DPHY LP Length */
+#define        DSI_PHY_TIME_3_CFG_CSR_TIME_LPX_MASK            (0xff<<8)
+#define        DSI_PHY_TIME_3_CFG_CSR_TIME_LPX_SHIFT           8
+/* DPHY HS req to rdy Length */
+#define        DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_MASK         (0xff)
+#define        DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_SHIFT        0
+
+/*
+ * DSI timings
+ * PXA988 has diffrent ESC CLK with MMP2/MMP3
+ * it will be used in dsi_set_dphy() in pxa688_phy.c
+ * as low power mode clock.
+ */
+#ifdef CONFIG_CPU_PXA988
+#define DSI_ESC_CLK                            52  /* Unit: Mhz */
+#define DSI_ESC_CLK_T                          19  /* Unit: ns */
+#else
+#define DSI_ESC_CLK                            66  /* Unit: Mhz */
+#define DSI_ESC_CLK_T                          15  /* Unit: ns */
+#endif
+
+/* LVDS */
+/* LVDS_PHY_CTRL */
+#define LVDS_PHY_CTL                           0x2A4
+#define LVDS_PLL_LOCK                          (1 << 31)
+#define LVDS_PHY_EXT_MASK                      (7 << 28)
+#define LVDS_PHY_EXT_SHIFT                     (28)
+#define LVDS_CLK_PHASE_MASK                    (0x7f << 16)
+#define LVDS_CLK_PHASE_SHIFT                   (16)
+#define LVDS_SSC_RESET_EXT                     (1 << 13)
+#define LVDS_SSC_MODE_DOWN_SPREAD              (1 << 12)
+#define LVDS_SSC_EN                            (1 << 11)
+#define LVDS_PU_PLL                            (1 << 10)
+#define LVDS_PU_TX                             (1 << 9)
+#define LVDS_PU_IVREF                          (1 << 8)
+#define LVDS_CLK_SEL                           (1 << 7)
+#define LVDS_CLK_SEL_LVDS_PCLK                 (1 << 7)
+#define LVDS_PD_CH_MASK                                (0x3f << 1)
+#define LVDS_PD_CH(ch)                         ((ch) << 1)
+#define LVDS_RST                               (1 << 0)
+
+#define LVDS_PHY_CTL_EXT       0x2A8
+
+/* LVDS_PHY_CTRL_EXT1 */
+#define LVDS_SSC_RNGE_MASK                     (0x7ff << 16)
+#define LVDS_SSC_RNGE_SHIFT                    (16)
+#define LVDS_RESERVE_IN_MASK                   (0xf << 12)
+#define LVDS_RESERVE_IN_SHIFT                  (12)
+#define LVDS_TEST_MON_MASK                     (0x7 << 8)
+#define LVDS_TEST_MON_SHIFT                    (8)
+#define LVDS_POL_SWAP_MASK                     (0x3f << 0)
+#define LVDS_POL_SWAP_SHIFT                    (0)
+
+/* LVDS_PHY_CTRL_EXT2 */
+#define LVDS_TX_DIF_AMP_MASK                   (0xf << 24)
+#define LVDS_TX_DIF_AMP_SHIFT                  (24)
+#define LVDS_TX_DIF_CM_MASK                    (0x3 << 22)
+#define LVDS_TX_DIF_CM_SHIFT                   (22)
+#define LVDS_SELLV_TXCLK_MASK                  (0x1f << 16)
+#define LVDS_SELLV_TXCLK_SHIFT                 (16)
+#define LVDS_TX_CMFB_EN                                (0x1 << 15)
+#define LVDS_TX_TERM_EN                                (0x1 << 14)
+#define LVDS_SELLV_TXDATA_MASK                 (0x1f << 8)
+#define LVDS_SELLV_TXDATA_SHIFT                        (8)
+#define LVDS_SELLV_OP7_MASK                    (0x3 << 6)
+#define LVDS_SELLV_OP7_SHIFT                   (6)
+#define LVDS_SELLV_OP6_MASK                    (0x3 << 4)
+#define LVDS_SELLV_OP6_SHIFT                   (4)
+#define LVDS_SELLV_OP9_MASK                    (0x3 << 2)
+#define LVDS_SELLV_OP9_SHIFT                   (2)
+#define LVDS_STRESSTST_EN                      (0x1 << 0)
+
+/* LVDS_PHY_CTRL_EXT3 */
+#define LVDS_KVCO_MASK                         (0xf << 28)
+#define LVDS_KVCO_SHIFT                                (28)
+#define LVDS_CTUNE_MASK                                (0x3 << 26)
+#define LVDS_CTUNE_SHIFT                       (26)
+#define LVDS_VREG_IVREF_MASK                   (0x3 << 24)
+#define LVDS_VREG_IVREF_SHIFT                  (24)
+#define LVDS_VDDL_MASK                         (0xf << 20)
+#define LVDS_VDDL_SHIFT                                (20)
+#define LVDS_VDDM_MASK                         (0x3 << 18)
+#define LVDS_VDDM_SHIFT                                (18)
+#define LVDS_FBDIV_MASK                                (0xf << 8)
+#define LVDS_FBDIV_SHIFT                       (8)
+#define LVDS_REFDIV_MASK                       (0x7f << 0)
+#define LVDS_REFDIV_SHIFT                      (0)
+
+/* LVDS_PHY_CTRL_EXT4 */
+#define LVDS_SSC_FREQ_DIV_MASK                 (0xffff << 16)
+#define LVDS_SSC_FREQ_DIV_SHIFT                        (16)
+#define LVDS_INTPI_MASK                                (0xf << 12)
+#define LVDS_INTPI_SHIFT                       (12)
+#define LVDS_VCODIV_SEL_SE_MASK                        (0xf << 8)
+#define LVDS_VCODIV_SEL_SE_SHIFT               (8)
+#define LVDS_RESET_INTP_EXT                    (0x1 << 7)
+#define LVDS_VCO_VRNG_MASK                     (0x7 << 4)
+#define LVDS_VCO_VRNG_SHIFT                    (4)
+#define LVDS_PI_EN                             (0x1 << 3)
+#define LVDS_ICP_MASK                          (0x7 << 0)
+#define LVDS_ICP_SHIFT                         (0)
+
+/* LVDS_PHY_CTRL_EXT5 */
+#define LVDS_FREQ_OFFSET_MASK                  (0x1ffff << 15)
+#define LVDS_FREQ_OFFSET_SHIFT                 (15)
+#define LVDS_FREQ_OFFSET_VALID                 (0x1 << 2)
+#define LVDS_FREQ_OFFSET_MODE_CK_DIV4_OUT      (0x1 << 1)
+#define LVDS_FREQ_OFFSET_MODE_EN               (0x1 << 0)
+
+/* VDMA */
+struct vdma_ch_regs {
+#define VDMA_DC_SADDR_1                0x320
+#define VDMA_DC_SADDR_2                0x3A0
+#define VDMA_DC_SZ_1           0x324
+#define VDMA_DC_SZ_2           0x3A4
+#define VDMA_CTRL_1            0x328
+#define VDMA_CTRL_2            0x3A8
+#define VDMA_SRC_SZ_1          0x32C
+#define VDMA_SRC_SZ_2          0x3AC
+#define VDMA_SA_1              0x330
+#define VDMA_SA_2              0x3B0
+#define VDMA_DA_1              0x334
+#define VDMA_DA_2              0x3B4
+#define VDMA_SZ_1              0x338
+#define VDMA_SZ_2              0x3B8
+       u32     dc_saddr;
+       u32     dc_size;
+       u32     ctrl;
+       u32     src_size;
+       u32     src_addr;
+       u32     dst_addr;
+       u32     dst_size;
+#define VDMA_PITCH_1           0x33C
+#define VDMA_PITCH_2           0x3BC
+#define VDMA_ROT_CTRL_1                0x340
+#define VDMA_ROT_CTRL_2                0x3C0
+#define VDMA_RAM_CTRL0_1       0x344
+#define VDMA_RAM_CTRL0_2       0x3C4
+#define VDMA_RAM_CTRL1_1       0x348
+#define VDMA_RAM_CTRL1_2       0x3C8
+       u32     pitch;
+       u32     rot_ctrl;
+       u32     ram_ctrl0;
+       u32     ram_ctrl1;
+
+};
+struct vdma_regs {
+#define VDMA_ARBR_CTRL         0x300
+#define VDMA_IRQR              0x304
+#define VDMA_IRQM              0x308
+#define VDMA_IRQS              0x30C
+#define VDMA_MDMA_ARBR_CTRL    0x310
+       u32     arbr_ctr;
+       u32     irq_raw;
+       u32     irq_mask;
+       u32     irq_status;
+       u32     mdma_arbr_ctrl;
+       u32     reserved[3];
+
+       struct vdma_ch_regs     ch1;
+       u32     reserved2[21];
+       struct vdma_ch_regs     ch2;
+};
+
+/* CMU */
+#define CMU_PIP_DE_H_CFG       0x0008
+#define CMU_PRI1_H_CFG         0x000C
+#define CMU_PRI2_H_CFG         0x0010
+#define CMU_ACE_MAIN_DE1_H_CFG 0x0014
+#define CMU_ACE_MAIN_DE2_H_CFG 0x0018
+#define CMU_ACE_PIP_DE1_H_CFG  0x001C
+#define CMU_ACE_PIP_DE2_H_CFG  0x0020
+#define CMU_PIP_DE_V_CFG       0x0024
+#define CMU_PRI_V_CFG          0x0028
+#define CMU_ACE_MAIN_DE_V_CFG  0x002C
+#define CMU_ACE_PIP_DE_V_CFG   0x0030
+#define CMU_BAR_0_CFG          0x0034
+#define CMU_BAR_1_CFG          0x0038
+#define CMU_BAR_2_CFG          0x003C
+#define CMU_BAR_3_CFG          0x0040
+#define CMU_BAR_4_CFG          0x0044
+#define CMU_BAR_5_CFG          0x0048
+#define CMU_BAR_6_CFG          0x004C
+#define CMU_BAR_7_CFG          0x0050
+#define CMU_BAR_8_CFG          0x0054
+#define CMU_BAR_9_CFG          0x0058
+#define CMU_BAR_10_CFG         0x005C
+#define CMU_BAR_11_CFG         0x0060
+#define CMU_BAR_12_CFG         0x0064
+#define CMU_BAR_13_CFG         0x0068
+#define CMU_BAR_14_CFG         0x006C
+#define CMU_BAR_15_CFG         0x0070
+#define CMU_BAR_CTRL           0x0074
+#define PATTERN_TOTAL          0x0078
+#define PATTERN_ACTIVE         0x007C
+#define PATTERN_FRONT_PORCH    0x0080
+#define PATTERN_BACK_PORCH     0x0084
+#define CMU_CLK_CTRL           0x0088
+
+#define CMU_ICSC_M_C0_L                0x0900
+#define CMU_ICSC_M_C0_H                0x0901
+#define CMU_ICSC_M_C1_L                0x0902
+#define CMU_ICSC_M_C1_H                0x0903
+#define CMU_ICSC_M_C2_L                0x0904
+#define CMU_ICSC_M_C2_H                0x0905
+#define CMU_ICSC_M_C3_L                0x0906
+#define CMU_ICSC_M_C3_H                0x0907
+#define CMU_ICSC_M_C4_L                0x0908
+#define CMU_ICSC_M_C4_H                0x0909
+#define CMU_ICSC_M_C5_L                0x090A
+#define CMU_ICSC_M_C5_H                0x090B
+#define CMU_ICSC_M_C6_L                0x090C
+#define CMU_ICSC_M_C6_H                0x090D
+#define CMU_ICSC_M_C7_L                0x090E
+#define CMU_ICSC_M_C7_H                0x090F
+#define CMU_ICSC_M_C8_L                0x0910
+#define CMU_ICSC_M_C8_H                0x0911
+#define CMU_ICSC_M_O1_0                0x0914
+#define CMU_ICSC_M_O1_1                0x0915
+#define CMU_ICSC_M_O1_2                0x0916
+#define CMU_ICSC_M_O2_0                0x0918
+#define CMU_ICSC_M_O2_1                0x0919
+#define CMU_ICSC_M_O2_2                0x091A
+#define CMU_ICSC_M_O3_0                0x091C
+#define CMU_ICSC_M_O3_1                0x091D
+#define CMU_ICSC_M_O3_2                0x091E
+#define CMU_ICSC_P_C0_L                0x0920
+#define CMU_ICSC_P_C0_H                0x0921
+#define CMU_ICSC_P_C1_L                0x0922
+#define CMU_ICSC_P_C1_H                0x0923
+#define CMU_ICSC_P_C2_L                0x0924
+#define CMU_ICSC_P_C2_H                0x0925
+#define CMU_ICSC_P_C3_L                0x0926
+#define CMU_ICSC_P_C3_H                0x0927
+#define CMU_ICSC_P_C4_L                0x0928
+#define CMU_ICSC_P_C4_H                0x0929
+#define CMU_ICSC_P_C5_L                0x092A
+#define CMU_ICSC_P_C5_H                0x092B
+#define CMU_ICSC_P_C6_L                0x092C
+#define CMU_ICSC_P_C6_H                0x092D
+#define CMU_ICSC_P_C7_L                0x092E
+#define CMU_ICSC_P_C7_H                0x092F
+#define CMU_ICSC_P_C8_L                0x0930
+#define CMU_ICSC_P_C8_H                0x0931
+#define CMU_ICSC_P_O1_0                0x0934
+#define CMU_ICSC_P_O1_1                0x0935
+#define CMU_ICSC_P_O1_2                0x0936
+#define CMU_ICSC_P_O2_0                0x0938
+#define CMU_ICSC_P_O2_1                0x0939
+#define CMU_ICSC_P_O2_2                0x093A
+#define CMU_ICSC_P_O3_0                0x093C
+#define CMU_ICSC_P_O3_1                0x093D
+#define CMU_ICSC_P_O3_2                0x093E
+#define CMU_BR_M_EN            0x0940
+#define CMU_BR_M_TH1_L         0x0942
+#define CMU_BR_M_TH1_H         0x0943
+#define CMU_BR_M_TH2_L         0x0944
+#define CMU_BR_M_TH2_H         0x0945
+#define CMU_ACE_M_EN           0x0950
+#define CMU_ACE_M_WFG1         0x0951
+#define CMU_ACE_M_WFG2         0x0952
+#define CMU_ACE_M_WFG3         0x0953
+#define CMU_ACE_M_TH0          0x0954
+#define CMU_ACE_M_TH1          0x0955
+#define CMU_ACE_M_TH2          0x0956
+#define CMU_ACE_M_TH3          0x0957
+#define CMU_ACE_M_TH4          0x0958
+#define CMU_ACE_M_TH5          0x0959
+#define CMU_ACE_M_OP0_L                0x095A
+#define CMU_ACE_M_OP0_H                0x095B
+#define CMU_ACE_M_OP5_L                0x095C
+#define CMU_ACE_M_OP5_H                0x095D
+#define CMU_ACE_M_GB2          0x095E
+#define CMU_ACE_M_GB3          0x095F
+#define CMU_ACE_M_MS1          0x0960
+#define CMU_ACE_M_MS2          0x0961
+#define CMU_ACE_M_MS3          0x0962
+#define CMU_BR_P_EN            0x0970
+#define CMU_BR_P_TH1_L         0x0972
+#define CMU_BR_P_TH1_H         0x0973
+#define CMU_BR_P_TH2_L         0x0974
+#define CMU_BR_P_TH2_H         0x0975
+#define CMU_ACE_P_EN           0x0980
+#define CMU_ACE_P_WFG1         0x0981
+#define CMU_ACE_P_WFG2         0x0982
+#define CMU_ACE_P_WFG3         0x0983
+#define CMU_ACE_P_TH0          0x0984
+#define CMU_ACE_P_TH1          0x0985
+#define CMU_ACE_P_TH2          0x0986
+#define CMU_ACE_P_TH3          0x0987
+#define CMU_ACE_P_TH4          0x0988
+#define CMU_ACE_P_TH5          0x0989
+#define CMU_ACE_P_OP0_L                0x098A
+#define CMU_ACE_P_OP0_H                0x098B
+#define CMU_ACE_P_OP5_L                0x098C
+#define CMU_ACE_P_OP5_H                0x098D
+#define CMU_ACE_P_GB2          0x098E
+#define CMU_ACE_P_GB3          0x098F
+#define CMU_ACE_P_MS1          0x0990
+#define CMU_ACE_P_MS2          0x0991
+#define CMU_ACE_P_MS3          0x0992
+#define CMU_FTDC_M_EN          0x09A0
+#define CMU_FTDC_P_EN          0x09A1
+#define CMU_FTDC_INLOW_L       0x09A2
+#define CMU_FTDC_INLOW_H       0x09A3
+#define CMU_FTDC_INHIGH_L      0x09A4
+#define CMU_FTDC_INHIGH_H      0x09A5
+#define CMU_FTDC_OUTLOW_L      0x09A6
+#define CMU_FTDC_OUTLOW_H      0x09A7
+#define CMU_FTDC_OUTHIGH_L     0x09A8
+#define CMU_FTDC_OUTHIGH_H     0x09A9
+#define CMU_FTDC_YLOW          0x09AA
+#define CMU_FTDC_YHIGH         0x09AB
+#define CMU_FTDC_CH1           0x09AC
+#define CMU_FTDC_CH2_L         0x09AE
+#define CMU_FTDC_CH2_H         0x09AF
+#define CMU_FTDC_CH3_L         0x09B0
+#define CMU_FTDC_CH3_H         0x09B1
+#define CMU_FTDC_1_C00_6       0x09B2
+#define CMU_FTDC_1_C01_6       0x09B8
+#define CMU_FTDC_1_C11_6       0x09BE
+#define CMU_FTDC_1_C10_6       0x09C4
+#define CMU_FTDC_1_OFF00_6     0x09CA
+#define CMU_FTDC_1_OFF10_6     0x09D0
+#define CMU_HS_M_EN            0x0A00
+#define CMU_HS_M_AX1_L         0x0A02
+#define CMU_HS_M_AX1_H         0x0A03
+#define CMU_HS_M_AX2_L         0x0A04
+#define CMU_HS_M_AX2_H         0x0A05
+#define CMU_HS_M_AX3_L         0x0A06
+#define CMU_HS_M_AX3_H         0x0A07
+#define CMU_HS_M_AX4_L         0x0A08
+#define CMU_HS_M_AX4_H         0x0A09
+#define CMU_HS_M_AX5_L         0x0A0A
+#define CMU_HS_M_AX5_H         0x0A0B
+#define CMU_HS_M_AX6_L         0x0A0C
+#define CMU_HS_M_AX6_H         0x0A0D
+#define CMU_HS_M_AX7_L         0x0A0E
+#define CMU_HS_M_AX7_H         0x0A0F
+#define CMU_HS_M_AX8_L         0x0A10
+#define CMU_HS_M_AX8_H         0x0A11
+#define CMU_HS_M_AX9_L         0x0A12
+#define CMU_HS_M_AX9_H         0x0A13
+#define CMU_HS_M_AX10_L                0x0A14
+#define CMU_HS_M_AX10_H                0x0A15
+#define CMU_HS_M_AX11_L                0x0A16
+#define CMU_HS_M_AX11_H                0x0A17
+#define CMU_HS_M_AX12_L                0x0A18
+#define CMU_HS_M_AX12_H                0x0A19
+#define CMU_HS_M_AX13_L                0x0A1A
+#define CMU_HS_M_AX13_H                0x0A1B
+#define CMU_HS_M_AX14_L                0x0A1C
+#define CMU_HS_M_AX14_H                0x0A1D
+#define CMU_HS_M_H1_H14                0x0A1E
+#define CMU_HS_M_S1_S14                0x0A2C
+#define CMU_HS_M_GL            0x0A3A
+#define CMU_HS_M_MAXSAT_RGB_Y_L        0x0A3C
+#define CMU_HS_M_MAXSAT_RGB_Y_H        0x0A3D
+#define CMU_HS_M_MAXSAT_RCR_L  0x0A3E
+#define CMU_HS_M_MAXSAT_RCR_H  0x0A3F
+#define CMU_HS_M_MAXSAT_RCB_L  0x0A40
+#define CMU_HS_M_MAXSAT_RCB_H  0x0A41
+#define CMU_HS_M_MAXSAT_GCR_L  0x0A42
+#define CMU_HS_M_MAXSAT_GCR_H  0x0A43
+#define CMU_HS_M_MAXSAT_GCB_L  0x0A44
+#define CMU_HS_M_MAXSAT_GCB_H  0x0A45
+#define CMU_HS_M_MAXSAT_BCR_L  0x0A46
+#define CMU_HS_M_MAXSAT_BCR_H  0x0A47
+#define CMU_HS_M_MAXSAT_BCB_L  0x0A48
+#define CMU_HS_M_MAXSAT_BCB_H  0x0A49
+#define CMU_HS_M_ROFF_L                0x0A4A
+#define CMU_HS_M_ROFF_H                0x0A4B
+#define CMU_HS_M_GOFF_L                0x0A4C
+#define CMU_HS_M_GOFF_H                0x0A4D
+#define CMU_HS_M_BOFF_L                0x0A4E
+#define CMU_HS_M_BOFF_H                0x0A4F
+#define CMU_HS_P_EN            0x0A50
+#define CMU_HS_P_AX1_L         0x0A52
+#define CMU_HS_P_AX1_H         0x0A53
+#define CMU_HS_P_AX2_L         0x0A54
+#define CMU_HS_P_AX2_H         0x0A55
+#define CMU_HS_P_AX3_L         0x0A56
+#define CMU_HS_P_AX3_H         0x0A57
+#define CMU_HS_P_AX4_L         0x0A58
+#define CMU_HS_P_AX4_H         0x0A59
+#define CMU_HS_P_AX5_L         0x0A5A
+#define CMU_HS_P_AX5_H         0x0A5B
+#define CMU_HS_P_AX6_L         0x0A5C
+#define CMU_HS_P_AX6_H         0x0A5D
+#define CMU_HS_P_AX7_L         0x0A5E
+#define CMU_HS_P_AX7_H         0x0A5F
+#define CMU_HS_P_AX8_L         0x0A60
+#define CMU_HS_P_AX8_H         0x0A61
+#define CMU_HS_P_AX9_L         0x0A62
+#define CMU_HS_P_AX9_H         0x0A63
+#define CMU_HS_P_AX10_L                0x0A64
+#define CMU_HS_P_AX10_H                0x0A65
+#define CMU_HS_P_AX11_L                0x0A66
+#define CMU_HS_P_AX11_H                0x0A67
+#define CMU_HS_P_AX12_L                0x0A68
+#define CMU_HS_P_AX12_H                0x0A69
+#define CMU_HS_P_AX13_L                0x0A6A
+#define CMU_HS_P_AX13_H                0x0A6B
+#define CMU_HS_P_AX14_L                0x0A6C
+#define CMU_HS_P_AX14_H                0x0A6D
+#define CMU_HS_P_H1_H14                0x0A6E
+#define CMU_HS_P_S1_S14                0x0A7C
+#define CMU_HS_P_GL            0x0A8A
+#define CMU_HS_P_MAXSAT_RGB_Y_L        0x0A8C
+#define CMU_HS_P_MAXSAT_RGB_Y_H        0x0A8D
+#define CMU_HS_P_MAXSAT_RCR_L  0x0A8E
+#define CMU_HS_P_MAXSAT_RCR_H  0x0A8F
+#define CMU_HS_P_MAXSAT_RCB_L  0x0A90
+#define CMU_HS_P_MAXSAT_RCB_H  0x0A91
+#define CMU_HS_P_MAXSAT_GCR_L  0x0A92
+#define CMU_HS_P_MAXSAT_GCR_H  0x0A93
+#define CMU_HS_P_MAXSAT_GCB_L  0x0A94
+#define CMU_HS_P_MAXSAT_GCB_H  0x0A95
+#define CMU_HS_P_MAXSAT_BCR_L  0x0A96
+#define CMU_HS_P_MAXSAT_BCR_H  0x0A97
+#define CMU_HS_P_MAXSAT_BCB_L  0x0A98
+#define CMU_HS_P_MAXSAT_BCB_H  0x0A99
+#define CMU_HS_P_ROFF_L                0x0A9A
+#define CMU_HS_P_ROFF_H                0x0A9B
+#define CMU_HS_P_GOFF_L                0x0A9C
+#define CMU_HS_P_GOFF_H                0x0A9D
+#define CMU_HS_P_BOFF_L                0x0A9E
+#define CMU_HS_P_BOFF_H                0x0A9F
+#define CMU_GLCSC_M_C0_L       0x0AA0
+#define CMU_GLCSC_M_C0_H       0x0AA1
+#define CMU_GLCSC_M_C1_L       0x0AA2
+#define CMU_GLCSC_M_C1_H       0x0AA3
+#define CMU_GLCSC_M_C2_L       0x0AA4
+#define CMU_GLCSC_M_C2_H       0x0AA5
+#define CMU_GLCSC_M_C3_L       0x0AA6
+#define CMU_GLCSC_M_C3_H       0x0AA7
+#define CMU_GLCSC_M_C4_L       0x0AA8
+#define CMU_GLCSC_M_C4_H       0x0AA9
+#define CMU_GLCSC_M_C5_L       0x0AAA
+#define CMU_GLCSC_M_C5_H       0x0AAB
+#define CMU_GLCSC_M_C6_L       0x0AAC
+#define CMU_GLCSC_M_C6_H       0x0AAD
+#define CMU_GLCSC_M_C7_L       0x0AAE
+#define CMU_GLCSC_M_C7_H       0x0AAF
+#define CMU_GLCSC_M_C8_L       0x0AB0
+#define CMU_GLCSC_M_C8_H       0x0AB1
+#define CMU_GLCSC_M_O1_1       0x0AB4
+#define CMU_GLCSC_M_O1_2       0x0AB5
+#define CMU_GLCSC_M_O1_3       0x0AB6
+#define CMU_GLCSC_M_O2_1       0x0AB8
+#define CMU_GLCSC_M_O2_2       0x0AB9
+#define CMU_GLCSC_M_O2_3       0x0ABA
+#define CMU_GLCSC_M_O3_1       0x0ABC
+#define CMU_GLCSC_M_O3_2       0x0ABD
+#define CMU_GLCSC_M_O3_3       0x0ABE
+#define CMU_GLCSC_P_C0_L       0x0AC0
+#define CMU_GLCSC_P_C0_H       0x0AC1
+#define CMU_GLCSC_P_C1_L       0x0AC2
+#define CMU_GLCSC_P_C1_H       0x0AC3
+#define CMU_GLCSC_P_C2_L       0x0AC4
+#define CMU_GLCSC_P_C2_H       0x0AC5
+#define CMU_GLCSC_P_C3_L       0x0AC6
+#define CMU_GLCSC_P_C3_H       0x0AC7
+#define CMU_GLCSC_P_C4_L       0x0AC8
+#define CMU_GLCSC_P_C4_H       0x0AC9
+#define CMU_GLCSC_P_C5_L       0x0ACA
+#define CMU_GLCSC_P_C5_H       0x0ACB
+#define CMU_GLCSC_P_C6_L       0x0ACC
+#define CMU_GLCSC_P_C6_H       0x0ACD
+#define CMU_GLCSC_P_C7_L       0x0ACE
+#define CMU_GLCSC_P_C7_H       0x0ACF
+#define CMU_GLCSC_P_C8_L       0x0AD0
+#define CMU_GLCSC_P_C8_H       0x0AD1
+#define CMU_GLCSC_P_O1_1       0x0AD4
+#define CMU_GLCSC_P_O1_2       0x0AD5
+#define CMU_GLCSC_P_O1_3       0x0AD6
+#define CMU_GLCSC_P_O2_1       0x0AD8
+#define CMU_GLCSC_P_O2_2       0x0AD9
+#define CMU_GLCSC_P_O2_3       0x0ADA
+#define CMU_GLCSC_P_O3_1       0x0ADC
+#define CMU_GLCSC_P_O3_2       0x0ADD
+#define CMU_GLCSC_P_O3_3       0x0ADE
+#define CMU_PIXVAL_M_EN                0x0AE0
+#define CMU_PIXVAL_P_EN                0x0AE1
+
+#define CMU_CLK_CTRL_TCLK      0x0
+#define CMU_CLK_CTRL_SCLK      0x2
+#define CMU_CLK_CTRL_MSK       0x2
+#define CMU_CLK_CTRL_ENABLE    0x1
+
+#define LCD_TOP_CTRL_TV                0x2
+#define LCD_TOP_CTRL_PN                0x0
+#define LCD_TOP_CTRL_SEL_MSK   0x2
+#define LCD_IO_CMU_IN_SEL_MSK  (0x3 << 20)
+#define LCD_IO_CMU_IN_SEL_TV   0
+#define LCD_IO_CMU_IN_SEL_PN   1
+#define LCD_IO_CMU_IN_SEL_PN2  2
+#define LCD_IO_TV_OUT_SEL_MSK  (0x3 << 26)
+#define LCD_IO_PN_OUT_SEL_MSK  (0x3 << 24)
+#define LCD_IO_PN2_OUT_SEL_MSK (0x3 << 28)
+#define LCD_IO_TV_OUT_SEL_NON  3
+#define LCD_IO_PN_OUT_SEL_NON  3
+#define LCD_IO_PN2_OUT_SEL_NON 3
+#define LCD_TOP_CTRL_CMU_ENABLE 0x1
+#define LCD_IO_OVERL_MSK       0xC00000
+#define LCD_IO_OVERL_TV                0x0
+#define LCD_IO_OVERL_LCD1      0x400000
+#define LCD_IO_OVERL_LCD2      0xC00000
+#define HINVERT_MSK            0x4
+#define VINVERT_MSK            0x8
+#define HINVERT_LEN            0x2
+#define VINVERT_LEN            0x3
+
+#define CMU_CTRL               0x88
+#define CMU_CTRL_A0_MSK                0x6
+#define CMU_CTRL_A0_TV         0x0
+#define CMU_CTRL_A0_LCD1       0x1
+#define CMU_CTRL_A0_LCD2       0x2
+#define CMU_CTRL_A0_HDMI       0x3
+
+#define ICR_DRV_ROUTE_OFF      0x0
+#define ICR_DRV_ROUTE_TV       0x1
+#define ICR_DRV_ROUTE_LCD1     0x2
+#define ICR_DRV_ROUTE_LCD2     0x3
+
+enum {
+       PATH_PN = 0,
+       PATH_TV,
+       PATH_P2,
+};
+
+/*
+ * mmp path describes part of mmp path related info:
+ * which is hiden in display driver and not exported to buffer driver
+ */
+struct mmphw_ctrl;
+struct mmphw_path_plat {
+       int id;
+       struct mmphw_ctrl *ctrl;
+       struct mmp_path *path;
+       u32 path_config;
+       u32 link_config;
+};
+
+/* mmp ctrl describes mmp controller related info */
+struct mmphw_ctrl {
+       /* platform related, get from config */
+       const char *name;
+       int irq;
+       void *reg_base;
+       struct clk *clk;
+
+       /* sys info */
+       struct device *dev;
+
+       /* state */
+       int open_count;
+       int status;
+       struct mutex access_ok;
+
+       /*pathes*/
+       int path_num;
+       struct mmphw_path_plat path_plats[0];
+};
+
+static inline int overlay_is_vid(struct mmp_overlay *overlay)
+{
+       return overlay->dmafetch_id & 1;
+}
+
+static inline struct mmphw_path_plat *path_to_path_plat(struct mmp_path *path)
+{
+       return (struct mmphw_path_plat *)path->plat_data;
+}
+
+static inline struct mmphw_ctrl *path_to_ctrl(struct mmp_path *path)
+{
+       return path_to_path_plat(path)->ctrl;
+}
+
+static inline struct mmphw_ctrl *overlay_to_ctrl(struct mmp_overlay *overlay)
+{
+       return path_to_ctrl(overlay->path);
+}
+
+static inline void *ctrl_regs(struct mmp_path *path)
+{
+       return path_to_ctrl(path)->reg_base;
+}
+
+/* path regs, for regs symmetrical for both pathes */
+static inline struct lcd_regs *path_regs(struct mmp_path *path)
+{
+       if (path->id == PATH_PN)
+               return (struct lcd_regs *)(ctrl_regs(path) + 0xc0);
+       else if (path->id == PATH_TV)
+               return (struct lcd_regs *)ctrl_regs(path);
+       else if (path->id == PATH_P2)
+               return (struct lcd_regs *)(ctrl_regs(path) + 0x200);
+       else {
+               dev_err(path->dev, "path id %d invalid\n", path->id);
+               BUG_ON(1);
+               return NULL;
+       }
+}
+
+#ifdef CONFIG_MMP_DISP_SPI
+extern int lcd_spi_register(struct mmphw_ctrl *ctrl);
+#endif
+#endif /* _MMP_CTRL_H_ */
diff --git a/drivers/video/mmp/hw/mmp_spi.c b/drivers/video/mmp/hw/mmp_spi.c
new file mode 100644 (file)
index 0000000..e62ca7b
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * linux/drivers/video/mmp/hw/mmp_spi.c
+ * using the spi in LCD controler for commands send
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors:  Guoqing Li <ligq@marvell.com>
+ *          Lisa Du <cldu@marvell.com>
+ *          Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include "mmp_ctrl.h"
+
+/**
+ * spi_write - write command to the SPI port
+ * @data: can be 8/16/32-bit, MSB justified data to write.
+ * @len:  data length.
+ *
+ * Wait bus transfer complete IRQ.
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ *   %-ETIMEDOUT       timeout occurred
+ *   0                 success
+ */
+static inline int lcd_spi_write(struct spi_device *spi, u32 data)
+{
+       int timeout = 100000, isr, ret = 0;
+       u32 tmp;
+       void *reg_base =
+               *(void **)spi_master_get_devdata(spi->master);
+
+       /* clear ISR */
+       writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
+
+       switch (spi->bits_per_word) {
+       case 8:
+               writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA);
+               break;
+       case 16:
+               writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA);
+               break;
+       case 32:
+               writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA);
+               break;
+       default:
+               dev_err(&spi->dev, "Wrong spi bit length\n");
+       }
+
+       /* SPI start to send command */
+       tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
+       tmp &= ~CFG_SPI_START_MASK;
+       tmp |= CFG_SPI_START(1);
+       writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
+
+       isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
+       while (!(isr & SPI_IRQ_ENA_MASK)) {
+               udelay(100);
+               isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
+               if (!--timeout) {
+                       ret = -ETIMEDOUT;
+                       dev_err(&spi->dev, "spi cmd send time out\n");
+                       break;
+               }
+       }
+
+       tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
+       tmp &= ~CFG_SPI_START_MASK;
+       tmp |= CFG_SPI_START(0);
+       writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL);
+
+       writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
+
+       return ret;
+}
+
+static int lcd_spi_setup(struct spi_device *spi)
+{
+       void *reg_base =
+               *(void **)spi_master_get_devdata(spi->master);
+       u32 tmp;
+
+       tmp = CFG_SCLKCNT(16) |
+               CFG_TXBITS(spi->bits_per_word) |
+               CFG_SPI_SEL(1) | CFG_SPI_ENA(1) |
+               CFG_SPI_3W4WB(1);
+       writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
+
+       /*
+        * After set mode it need a time to pull up the spi singals,
+        * or it would cause the wrong waveform when send spi command,
+        * especially on pxa910h
+        */
+       tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL);
+       if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI)
+               writel_relaxed(IOPAD_DUMB18SPI |
+                       (tmp & ~CFG_IOPADMODE_MASK),
+                       reg_base + SPU_IOPAD_CONTROL);
+       udelay(20);
+       return 0;
+}
+
+static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m)
+{
+       struct spi_transfer *t;
+       int i;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               switch (spi->bits_per_word) {
+               case 8:
+                       for (i = 0; i < t->len; i++)
+                               lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]);
+                       break;
+               case 16:
+                       for (i = 0; i < t->len/2; i++)
+                               lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]);
+                       break;
+               case 32:
+                       for (i = 0; i < t->len/4; i++)
+                               lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]);
+                       break;
+               default:
+                       dev_err(&spi->dev, "Wrong spi bit length\n");
+               }
+       }
+
+       m->status = 0;
+       if (m->complete)
+               m->complete(m->context);
+       return 0;
+}
+
+int lcd_spi_register(struct mmphw_ctrl *ctrl)
+{
+       struct spi_master *master;
+       void **p_regbase;
+       int err;
+
+       master = spi_alloc_master(ctrl->dev, sizeof(void *));
+       if (!master) {
+               dev_err(ctrl->dev, "unable to allocate SPI master\n");
+               return -ENOMEM;
+       }
+       p_regbase = spi_master_get_devdata(master);
+       *p_regbase = ctrl->reg_base;
+
+       /* set bus num to 5 to avoid conflict with other spi hosts */
+       master->bus_num = 5;
+       master->num_chipselect = 1;
+       master->setup = lcd_spi_setup;
+       master->transfer = lcd_spi_one_transfer;
+
+       err = spi_register_master(master);
+       if (err < 0) {
+               dev_err(ctrl->dev, "unable to register SPI master\n");
+               spi_master_put(master);
+               return err;
+       }
+
+       dev_info(&master->dev, "registered\n");
+
+       return 0;
+}
diff --git a/drivers/video/mmp/panel/Kconfig b/drivers/video/mmp/panel/Kconfig
new file mode 100644 (file)
index 0000000..4b2c4f4
--- /dev/null
@@ -0,0 +1,6 @@
+config MMP_PANEL_TPOHVGA
+       bool "tpohvga panel TJ032MD01BW support"
+       depends on SPI_MASTER
+       default n
+       help
+               tpohvga panel support
diff --git a/drivers/video/mmp/panel/Makefile b/drivers/video/mmp/panel/Makefile
new file mode 100644 (file)
index 0000000..2f91611
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_MMP_PANEL_TPOHVGA)    += tpo_tj032md01bw.o
diff --git a/drivers/video/mmp/panel/tpo_tj032md01bw.c b/drivers/video/mmp/panel/tpo_tj032md01bw.c
new file mode 100644 (file)
index 0000000..998978b
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * linux/drivers/video/mmp/panel/tpo_tj032md01bw.c
+ * active panel using spi interface to do init
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors:  Guoqing Li <ligq@marvell.com>
+ *          Lisa Du <cldu@marvell.com>
+ *          Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spi/spi.h>
+#include <video/mmp_disp.h>
+
+static u16 init[] = {
+       0x0801,
+       0x0800,
+       0x0200,
+       0x0304,
+       0x040e,
+       0x0903,
+       0x0b18,
+       0x0c53,
+       0x0d01,
+       0x0ee0,
+       0x0f01,
+       0x1058,
+       0x201e,
+       0x210a,
+       0x220a,
+       0x231e,
+       0x2400,
+       0x2532,
+       0x2600,
+       0x27ac,
+       0x2904,
+       0x2aa2,
+       0x2b45,
+       0x2c45,
+       0x2d15,
+       0x2e5a,
+       0x2fff,
+       0x306b,
+       0x310d,
+       0x3248,
+       0x3382,
+       0x34bd,
+       0x35e7,
+       0x3618,
+       0x3794,
+       0x3801,
+       0x395d,
+       0x3aae,
+       0x3bff,
+       0x07c9,
+};
+
+static u16 poweroff[] = {
+       0x07d9,
+};
+
+struct tpohvga_plat_data {
+       void (*plat_onoff)(int status);
+       struct spi_device *spi;
+};
+
+static void tpohvga_onoff(struct mmp_panel *panel, int status)
+{
+       struct tpohvga_plat_data *plat = panel->plat_data;
+       int ret;
+
+       if (status) {
+               plat->plat_onoff(1);
+
+               ret = spi_write(plat->spi, init, sizeof(init));
+               if (ret < 0)
+                       dev_warn(panel->dev, "init cmd failed(%d)\n", ret);
+       } else {
+               ret = spi_write(plat->spi, poweroff, sizeof(poweroff));
+               if (ret < 0)
+                       dev_warn(panel->dev, "poweroff cmd failed(%d)\n", ret);
+
+               plat->plat_onoff(0);
+       }
+}
+
+static struct mmp_mode mmp_modes_tpohvga[] = {
+       [0] = {
+               .pixclock_freq = 10394400,
+               .refresh = 60,
+               .xres = 320,
+               .yres = 480,
+               .hsync_len = 10,
+               .left_margin = 15,
+               .right_margin = 10,
+               .vsync_len = 2,
+               .upper_margin = 4,
+               .lower_margin = 2,
+               .invert_pixclock = 1,
+               .pix_fmt_out = PIXFMT_RGB565,
+       },
+};
+
+static int tpohvga_get_modelist(struct mmp_panel *panel,
+               struct mmp_mode **modelist)
+{
+       *modelist = mmp_modes_tpohvga;
+       return 1;
+}
+
+static struct mmp_panel panel_tpohvga = {
+       .name = "tpohvga",
+       .panel_type = PANELTYPE_ACTIVE,
+       .get_modelist = tpohvga_get_modelist,
+       .set_onoff = tpohvga_onoff,
+};
+
+static int tpohvga_probe(struct spi_device *spi)
+{
+       struct mmp_mach_panel_info *mi;
+       int ret;
+       struct tpohvga_plat_data *plat_data;
+
+       /* get configs from platform data */
+       mi = spi->dev.platform_data;
+       if (mi == NULL) {
+               dev_err(&spi->dev, "%s: no platform data defined\n", __func__);
+               return -EINVAL;
+       }
+
+       /* setup spi related info */
+       spi->bits_per_word = 16;
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&spi->dev, "spi setup failed %d", ret);
+               return ret;
+       }
+
+       plat_data = kzalloc(sizeof(*plat_data), GFP_KERNEL);
+       if (plat_data == NULL)
+               return -ENOMEM;
+
+       plat_data->spi = spi;
+       plat_data->plat_onoff = mi->plat_set_onoff;
+       panel_tpohvga.plat_data = plat_data;
+       panel_tpohvga.plat_path_name = mi->plat_path_name;
+       panel_tpohvga.dev = &spi->dev;
+
+       mmp_register_panel(&panel_tpohvga);
+
+       return 0;
+}
+
+static struct spi_driver panel_tpohvga_driver = {
+       .driver         = {
+               .name   = "tpo-hvga",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = tpohvga_probe,
+};
+module_spi_driver(panel_tpohvga_driver);
+
+MODULE_AUTHOR("Lisa Du<cldu@marvell.com>");
+MODULE_DESCRIPTION("Panel driver for tpohvga");
+MODULE_LICENSE("GPL");
index 7368872..cfdb380 100644 (file)
@@ -1306,7 +1306,7 @@ static int mx3fb_unmap_video_memory(struct fb_info *fbi)
        dma_free_writecombine(fbi->device, fbi->fix.smem_len,
                              fbi->screen_base, fbi->fix.smem_start);
 
-       fbi->screen_base = 0;
+       fbi->screen_base = NULL;
        mutex_lock(&fbi->mm_lock);
        fbi->fix.smem_start = 0;
        fbi->fix.smem_len = 0;
index 7a33997..c921ac9 100644 (file)
@@ -616,6 +616,7 @@ v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        lock_page(page);
        if (page->mapping != inode->i_mapping)
                goto out_unlock;
+       wait_for_stable_page(page);
 
        return VM_FAULT_LOCKED;
 out_unlock:
index 49d0b43..ff9dbc6 100644 (file)
@@ -1249,7 +1249,7 @@ static int writenote(struct memelfnote *men, struct file *file,
 #undef DUMP_WRITE
 
 static void fill_elf_header(struct elfhdr *elf, int segs,
-                           u16 machine, u32 flags, u8 osabi)
+                           u16 machine, u32 flags)
 {
        memset(elf, 0, sizeof(*elf));
 
@@ -1634,7 +1634,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
         * Initialize the ELF file header.
         */
        fill_elf_header(elf, phdrs,
-                       view->e_machine, view->e_flags, view->ei_osabi);
+                       view->e_machine, view->e_flags);
 
        /*
         * Allocate a structure for each thread.
@@ -1874,7 +1874,7 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
        elf_core_copy_regs(&info->prstatus->pr_reg, regs);
 
        /* Set up header */
-       fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS, ELF_OSABI);
+       fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
 
        /*
         * Set up the notes in similar form to SVR4 core dumps made
index 172f849..78333a3 100644 (file)
@@ -994,6 +994,7 @@ int revalidate_disk(struct gendisk *disk)
 
        mutex_lock(&bdev->bd_mutex);
        check_disk_size_change(disk, bdev);
+       bdev->bd_invalidated = 0;
        mutex_unlock(&bdev->bd_mutex);
        bdput(bdev);
        return ret;
index 7a75c3e..2ea9cd4 100644 (file)
@@ -2359,7 +2359,7 @@ int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
        if (unlikely(ret < 0))
                goto out_unlock;
        set_page_dirty(page);
-       wait_on_page_writeback(page);
+       wait_for_stable_page(page);
        return 0;
 out_unlock:
        unlock_page(page);
index 712b10f..e9dcfa3 100644 (file)
@@ -1037,10 +1037,11 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
 static int configfs_depend_prep(struct dentry *origin,
                                struct config_item *target)
 {
-       struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
+       struct configfs_dirent *child_sd, *sd;
        int ret = 0;
 
-       BUG_ON(!origin || !sd);
+       BUG_ON(!origin || !origin->d_fsdata);
+       sd = origin->d_fsdata;
 
        if (sd->s_element == target)  /* Boo-yah */
                goto out;
index 6e50223..4ba2683 100644 (file)
@@ -2065,6 +2065,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal":
                test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
                "writeback");
+       sb->s_flags |= MS_SNAP_STABLE;
 
        return 0;
 
index cbfe13b..cd818d8 100644 (file)
@@ -4968,7 +4968,7 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                                            0, len, NULL,
                                            ext4_bh_unmapped)) {
                        /* Wait so that we don't change page under IO */
-                       wait_on_page_writeback(page);
+                       wait_for_stable_page(page);
                        ret = VM_FAULT_LOCKED;
                        goto out;
                }
index 06b7092..2687f50 100644 (file)
@@ -483,7 +483,7 @@ out:
        gfs2_holder_uninit(&gh);
        if (ret == 0) {
                set_page_dirty(page);
-               wait_on_page_writeback(page);
+               wait_for_stable_page(page);
        }
        sb_end_pagefault(inode->i_sb);
        return block_page_mkwrite_return(ret);
index 6194688..bec4af6 100644 (file)
@@ -126,7 +126,7 @@ static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        nilfs_transaction_commit(inode->i_sb);
 
  mapped:
-       wait_on_page_writeback(page);
+       wait_for_stable_page(page);
  out:
        sb_end_pagefault(inode->i_sb);
        return block_page_mkwrite_return(ret);
index 228a2c2..07f7a92 100644 (file)
@@ -576,8 +576,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
 
        /* don't allow invalid bits: we don't want flags set */
        mask = inotify_arg_to_mask(arg);
-       if (unlikely(!(mask & IN_ALL_EVENTS)))
-               return -EINVAL;
 
        fsn_mark = fsnotify_find_inode_mark(group, inode);
        if (!fsn_mark)
@@ -629,8 +627,6 @@ static int inotify_new_watch(struct fsnotify_group *group,
 
        /* don't allow invalid bits: we don't want flags set */
        mask = inotify_arg_to_mask(arg);
-       if (unlikely(!(mask & IN_ALL_EVENTS)))
-               return -EINVAL;
 
        tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
        if (unlikely(!tmp_i_mark))
index 31b9463..b8a9d87 100644 (file)
@@ -6751,8 +6751,7 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
                mlog_errno(ret);
 
 out:
-       if (pages)
-               kfree(pages);
+       kfree(pages);
 
        return ret;
 }
index 6577432..9796330 100644 (file)
@@ -1194,6 +1194,7 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
                                goto out;
                        }
                }
+               wait_for_stable_page(wc->w_pages[i]);
 
                if (index == target_index)
                        wc->w_target_page = wc->w_pages[i];
index f7c648d..42252bf 100644 (file)
@@ -1471,8 +1471,7 @@ static void o2hb_region_release(struct config_item *item)
 
        mlog(ML_HEARTBEAT, "hb region release (%s)\n", reg->hr_dev_name);
 
-       if (reg->hr_tmp_block)
-               kfree(reg->hr_tmp_block);
+       kfree(reg->hr_tmp_block);
 
        if (reg->hr_slot_data) {
                for (i = 0; i < reg->hr_num_pages; i++) {
@@ -1486,8 +1485,7 @@ static void o2hb_region_release(struct config_item *item)
        if (reg->hr_bdev)
                blkdev_put(reg->hr_bdev, FMODE_READ|FMODE_WRITE);
 
-       if (reg->hr_slots)
-               kfree(reg->hr_slots);
+       kfree(reg->hr_slots);
 
        kfree(reg->hr_db_regnum);
        kfree(reg->hr_db_livenodes);
index 1bfe880..f0edbd8 100644 (file)
@@ -1165,10 +1165,8 @@ out:
        o2net_debug_del_nst(&nst); /* must be before dropping sc and node */
        if (sc)
                sc_put(sc);
-       if (vec)
-               kfree(vec);
-       if (msg)
-               kfree(msg);
+       kfree(vec);
+       kfree(msg);
        o2net_complete_nsw(nn, &nsw, 0, 0, 0);
        return ret;
 }
index 9e89d70..dbb17c0 100644 (file)
@@ -319,9 +319,7 @@ static void dlm_free_ctxt_mem(struct dlm_ctxt *dlm)
        if (dlm->master_hash)
                dlm_free_pagevec((void **)dlm->master_hash, DLM_HASH_PAGES);
 
-       if (dlm->name)
-               kfree(dlm->name);
-
+       kfree(dlm->name);
        kfree(dlm);
 }
 
index 4f7795f..88577eb 100644 (file)
@@ -2545,6 +2545,7 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
         * everything is up to the caller :) */
        status = ocfs2_should_refresh_lock_res(lockres);
        if (status < 0) {
+               ocfs2_cluster_unlock(osb, lockres, level);
                mlog_errno(status);
                goto bail;
        }
@@ -2553,8 +2554,10 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
 
                ocfs2_complete_lock_res_refresh(lockres, status);
 
-               if (status < 0)
+               if (status < 0) {
+                       ocfs2_cluster_unlock(osb, lockres, level);
                        mlog_errno(status);
+               }
                ocfs2_track_lock_refresh(lockres);
        }
 bail:
index f487aa3..1c39efb 100644 (file)
@@ -282,8 +282,7 @@ search:
        spin_unlock(&oi->ip_lock);
 
 out:
-       if (new_emi)
-               kfree(new_emi);
+       kfree(new_emi);
 }
 
 static int ocfs2_last_eb_is_empty(struct inode *inode,
index 2dd36af..8eccfab 100644 (file)
@@ -1234,11 +1234,8 @@ static void ocfs2_queue_recovery_completion(struct ocfs2_journal *journal,
                /* Though we wish to avoid it, we are in fact safe in
                 * skipping local alloc cleanup as fsck.ocfs2 is more
                 * than capable of reclaiming unused space. */
-               if (la_dinode)
-                       kfree(la_dinode);
-
-               if (tl_dinode)
-                       kfree(tl_dinode);
+               kfree(la_dinode);
+               kfree(tl_dinode);
 
                if (qrec)
                        ocfs2_free_quota_recovery(qrec);
@@ -1408,8 +1405,7 @@ bail:
 
        mutex_unlock(&osb->recovery_lock);
 
-       if (rm_quota)
-               kfree(rm_quota);
+       kfree(rm_quota);
 
        /* no one is callint kthread_stop() for us so the kthread() api
         * requires that we call do_exit().  And it isn't exported, but
index a9f78c7..aebeacd 100644 (file)
@@ -476,8 +476,7 @@ out:
        if (local_alloc_inode)
                iput(local_alloc_inode);
 
-       if (alloc_copy)
-               kfree(alloc_copy);
+       kfree(alloc_copy);
 }
 
 /*
@@ -534,7 +533,7 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,
                mlog_errno(status);
 
 bail:
-       if ((status < 0) && (*alloc_copy)) {
+       if (status < 0) {
                kfree(*alloc_copy);
                *alloc_copy = NULL;
        }
@@ -1290,8 +1289,7 @@ bail:
        if (main_bm_inode)
                iput(main_bm_inode);
 
-       if (alloc_copy)
-               kfree(alloc_copy);
+       kfree(alloc_copy);
 
        if (ac)
                ocfs2_free_alloc_context(ac);
index 9436801..bf1f893 100644 (file)
@@ -376,7 +376,7 @@ static int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn)
        dlm_register_eviction_cb(dlm, &priv->op_eviction_cb);
 
 out_free:
-       if (rc && conn->cc_private)
+       if (rc)
                kfree(conn->cc_private);
 
 out:
index 0e91ec2..9b6910d 100644 (file)
@@ -2525,8 +2525,7 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
                mlog_errno(status);
 
 finally:
-       if (local_alloc)
-               kfree(local_alloc);
+       kfree(local_alloc);
 
        if (status)
                mlog_errno(status);
@@ -2553,8 +2552,7 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb)
         * we free it here.
         */
        kfree(osb->journal);
-       if (osb->local_alloc_copy)
-               kfree(osb->local_alloc_copy);
+       kfree(osb->local_alloc_copy);
        kfree(osb->uuid_str);
        ocfs2_put_dlm_debug(osb->osb_dlm_debug);
        memset(osb, 0, sizeof(struct ocfs2_super));
index 3d635f4..f053688 100644 (file)
@@ -91,8 +91,7 @@ static struct inode **get_local_system_inode(struct ocfs2_super *osb,
                } else
                        osb->local_system_inodes = local_system_inodes;
                spin_unlock(&osb->osb_lock);
-               if (unlikely(free))
-                       kfree(free);
+               kfree(free);
        }
 
        index = (slot * NUM_LOCAL_SYSTEM_INODES) +
index 5bc7781..4f6493c 100644 (file)
@@ -1522,6 +1522,7 @@ static int ubifs_vm_page_mkwrite(struct vm_area_struct *vma,
                        ubifs_release_dirty_inode_budget(c, ui);
        }
 
+       wait_for_stable_page(page);
        unlock_page(page);
        return 0;
 
index 12731a1..3504599 100644 (file)
@@ -254,6 +254,7 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
 #define BDI_CAP_EXEC_MAP       0x00000040
 #define BDI_CAP_NO_ACCT_WB     0x00000080
 #define BDI_CAP_SWAP_BACKED    0x00000100
+#define BDI_CAP_STABLE_WRITES  0x00000200
 
 #define BDI_CAP_VMFLAGS \
        (BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
@@ -308,6 +309,11 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout);
 int pdflush_proc_obsolete(struct ctl_table *table, int write,
                void __user *buffer, size_t *lenp, loff_t *ppos);
 
+static inline bool bdi_cap_stable_pages_required(struct backing_dev_info *bdi)
+{
+       return bdi->capabilities & BDI_CAP_STABLE_WRITES;
+}
+
 static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
 {
        return !(bdi->capabilities & BDI_CAP_NO_WRITEBACK);
index b1cf40d..7f48186 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_BUG_H
 
 #include <asm/bug.h>
+#include <linux/compiler.h>
 
 enum bug_trap_type {
        BUG_TRAP_TYPE_NONE = 0,
@@ -12,11 +13,12 @@ enum bug_trap_type {
 struct pt_regs;
 
 #ifdef __CHECKER__
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
+#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0)
 #define BUILD_BUG_ON_ZERO(e) (0)
 #define BUILD_BUG_ON_NULL(e) ((void*)0)
 #define BUILD_BUG_ON_INVALID(e) (0)
-#define BUILD_BUG_ON(condition)
+#define BUILD_BUG_ON_MSG(cond, msg) (0)
+#define BUILD_BUG_ON(condition) (0)
 #define BUILD_BUG() (0)
 #else /* __CHECKER__ */
 
@@ -39,29 +41,37 @@ struct pt_regs;
 #define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e))))
 
 /**
+ * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied
+ *                   error message.
+ * @condition: the condition which the compiler should know is false.
+ *
+ * See BUILD_BUG_ON for description.
+ */
+#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
+
+/**
  * BUILD_BUG_ON - break compile if a condition is true.
  * @condition: the condition which the compiler should know is false.
  *
  * If you have some code which relies on certain constants being equal, or
- * other compile-time-evaluated condition, you should use BUILD_BUG_ON to
+ * some other compile-time-evaluated condition, you should use BUILD_BUG_ON to
  * detect if someone changes it.
  *
- * The implementation uses gcc's reluctance to create a negative array, but
- * gcc (as of 4.4) only emits that error for obvious cases (eg. not arguments
- * to inline functions).  So as a fallback we use the optimizer; if it can't
- * prove the condition is false, it will cause a link error on the undefined
- * "__build_bug_on_failed".  This error message can be harder to track down
- * though, hence the two different methods.
+ * The implementation uses gcc's reluctance to create a negative array, but gcc
+ * (as of 4.4) only emits that error for obvious cases (e.g. not arguments to
+ * inline functions).  Luckily, in 4.3 they added the "error" function
+ * attribute just for this type of case.  Thus, we use a negative sized array
+ * (should always create an error on gcc versions older than 4.4) and then call
+ * an undefined function with the error attribute (should always create an
+ * error on gcc 4.3 and later).  If for some reason, neither creates a
+ * compile-time error, we'll still have a link-time error, which is harder to
+ * track down.
  */
 #ifndef __OPTIMIZE__
 #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
 #else
-extern int __build_bug_on_failed;
-#define BUILD_BUG_ON(condition)                                        \
-       do {                                                    \
-               ((void)sizeof(char[1 - 2*!!(condition)]));      \
-               if (condition) __build_bug_on_failed = 1;       \
-       } while(0)
+#define BUILD_BUG_ON(condition) \
+       BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
 #endif
 
 /**
@@ -71,12 +81,7 @@ extern int __build_bug_on_failed;
  * build time, you should use BUILD_BUG to detect if it is
  * unexpectedly used.
  */
-#define BUILD_BUG()                                            \
-       do {                                                    \
-               extern void __build_bug_failed(void)            \
-                       __linktime_error("BUILD_BUG failed");   \
-               __build_bug_failed();                           \
-       } while (0)
+#define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed")
 
 #endif /* __CHECKER__ */
 
index 6a6d7ae..24545cd 100644 (file)
@@ -5,6 +5,9 @@
 /*
  * Common definitions for all gcc versions go here.
  */
+#define GCC_VERSION (__GNUC__ * 10000 \
+                  + __GNUC_MINOR__ * 100 \
+                  + __GNUC_PATCHLEVEL__)
 
 
 /* Optimization barrier */
index 37d4124..7d89feb 100644 (file)
@@ -2,22 +2,22 @@
 #error "Please don't include <linux/compiler-gcc3.h> directly, include <linux/compiler.h> instead."
 #endif
 
-#if __GNUC_MINOR__ < 2
+#if GCC_VERSION < 30200
 # error Sorry, your compiler is too old - please upgrade it.
 #endif
 
-#if __GNUC_MINOR__ >= 3
+#if GCC_VERSION >= 30300
 # define __used                        __attribute__((__used__))
 #else
 # define __used                        __attribute__((__unused__))
 #endif
 
-#if __GNUC_MINOR__ >= 4
+#if GCC_VERSION >= 30400
 #define __must_check           __attribute__((warn_unused_result))
 #endif
 
 #ifdef CONFIG_GCOV_KERNEL
-# if __GNUC_MINOR__ < 4
+# if GCC_VERSION < 30400
 #   error "GCOV profiling support for gcc versions below 3.4 not included"
 # endif /* __GNUC_MINOR__ */
 #endif /* CONFIG_GCOV_KERNEL */
index 662fd1b..68b162d 100644 (file)
@@ -4,7 +4,7 @@
 
 /* GCC 4.1.[01] miscompiles __weak */
 #ifdef __KERNEL__
-# if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1
+# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
 #  error Your version of gcc miscompiles the __weak directive
 # endif
 #endif
 #define __must_check           __attribute__((warn_unused_result))
 #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
 
-#if __GNUC_MINOR__ >= 3
+#if GCC_VERSION >= 40100
+# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
+#endif
+
+#if GCC_VERSION >= 40300
 /* Mark functions as cold. gcc will assume any path leading to a call
    to them will be unlikely.  This means a lot of manual unlikely()s
    are unnecessary now for any paths leading to the usual suspects
    the kernel context */
 #define __cold                 __attribute__((__cold__))
 
-#define __linktime_error(message) __attribute__((__error__(message)))
-
 #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
 
-#if __GNUC_MINOR__ >= 5
+#ifndef __CHECKER__
+# define __compiletime_warning(message) __attribute__((warning(message)))
+# define __compiletime_error(message) __attribute__((error(message)))
+#endif /* __CHECKER__ */
+#endif /* GCC_VERSION >= 40300 */
+
+#if GCC_VERSION >= 40500
 /*
  * Mark a position in code as unreachable.  This can be used to
  * suppress control flow warnings after asm blocks that transfer
 /* Mark a function definition as prohibited from being cloned. */
 #define __noclone      __attribute__((__noclone__))
 
-#endif
-#endif
+#endif /* GCC_VERSION >= 40500 */
 
-#if __GNUC_MINOR__ >= 6
+#if GCC_VERSION >= 40600
 /*
  * Tell the optimizer that something else uses this function or variable.
  */
 #define __visible __attribute__((externally_visible))
 #endif
 
-#if __GNUC_MINOR__ > 0
-#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
-#endif
-#if __GNUC_MINOR__ >= 3 && !defined(__CHECKER__)
-#define __compiletime_warning(message) __attribute__((warning(message)))
-#define __compiletime_error(message) __attribute__((error(message)))
-#endif
 
 #ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
-#if __GNUC_MINOR__ >= 4
+#if GCC_VERSION >= 40400
 #define __HAVE_BUILTIN_BSWAP32__
 #define __HAVE_BUILTIN_BSWAP64__
 #endif
-#if __GNUC_MINOR__ >= 8 || (defined(__powerpc__) && __GNUC_MINOR__ >= 6)
+#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600)
 #define __HAVE_BUILTIN_BSWAP16__
 #endif
-#endif
+#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
index dd852b7..10b8f23 100644 (file)
@@ -307,10 +307,36 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
 #endif
 #ifndef __compiletime_error
 # define __compiletime_error(message)
+# define __compiletime_error_fallback(condition) \
+       do { ((void)sizeof(char[1 - 2 * condition])); } while (0)
+#else
+# define __compiletime_error_fallback(condition) do { } while (0)
 #endif
-#ifndef __linktime_error
-# define __linktime_error(message)
-#endif
+
+#define __compiletime_assert(condition, msg, prefix, suffix)           \
+       do {                                                            \
+               bool __cond = !(condition);                             \
+               extern void prefix ## suffix(void) __compiletime_error(msg); \
+               if (__cond)                                             \
+                       prefix ## suffix();                             \
+               __compiletime_error_fallback(__cond);                   \
+       } while (0)
+
+#define _compiletime_assert(condition, msg, prefix, suffix) \
+       __compiletime_assert(condition, msg, prefix, suffix)
+
+/**
+ * compiletime_assert - break build and emit msg if condition is false
+ * @condition: a compile-time constant condition to check
+ * @msg:       a message to emit if condition is false
+ *
+ * In tradition of POSIX assert, this macro will break the build if the
+ * supplied condition is *false*, emitting the supplied error message if the
+ * compiler has support to do so.
+ */
+#define compiletime_assert(condition, msg) \
+       _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
+
 /*
  * Prevent the compiler from merging or refetching accesses.  The compiler
  * is also forbidden from reordering successive instances of ACCESS_ONCE(),
index 2bca44b..bfe88c4 100644 (file)
@@ -359,7 +359,9 @@ extern void lockdep_trace_alloc(gfp_t mask);
 
 #define lockdep_depth(tsk)     (debug_locks ? (tsk)->lockdep_depth : 0)
 
-#define lockdep_assert_held(l) WARN_ON(debug_locks && !lockdep_is_held(l))
+#define lockdep_assert_held(l) do {                            \
+               WARN_ON(debug_locks && !lockdep_is_held(l));    \
+       } while (0)
 
 #define lockdep_recursing(tsk) ((tsk)->lockdep_recursion)
 
index 6da609d..0e38e13 100644 (file)
@@ -414,6 +414,7 @@ static inline void wait_on_page_writeback(struct page *page)
 }
 
 extern void end_page_writeback(struct page *page);
+void wait_for_stable_page(struct page *page);
 
 /*
  * Add an arbitrary waiter to a page's wait queue
index e81f62d..20ee8b2 100644 (file)
 #define LP8556_FAST_CONFIG     BIT(7) /* use it if EPROMs should be maintained
                                          when exiting the low power mode */
 
+/* CONFIG register - LP8557 */
+#define LP8557_PWM_STANDBY     BIT(7)
+#define LP8557_PWM_FILTER      BIT(6)
+#define LP8557_RELOAD_EPROM    BIT(3)  /* use it if EPROMs should be reset
+                                          when the backlight turns on */
+#define LP8557_OFF_OPENLEDS    BIT(2)
+#define LP8557_PWM_CONFIG      LP8557_PWM_ONLY
+#define LP8557_I2C_CONFIG      LP8557_I2C_ONLY
+#define LP8557_COMB1_CONFIG    LP8557_COMBINED1
+#define LP8557_COMB2_CONFIG    LP8557_COMBINED2
+
 enum lp855x_chip_id {
        LP8550,
        LP8551,
        LP8552,
        LP8553,
        LP8556,
+       LP8557,
 };
 
 enum lp855x_brightness_ctrl_mode {
@@ -89,6 +101,13 @@ enum lp8556_brightness_source {
        LP8556_COMBINED2,       /* pwm + i2c after the shaper block */
 };
 
+enum lp8557_brightness_source {
+       LP8557_PWM_ONLY,
+       LP8557_I2C_ONLY,
+       LP8557_COMBINED1,       /* pwm + i2c after the shaper block */
+       LP8557_COMBINED2,       /* pwm + i2c before the shaper block */
+};
+
 struct lp855x_rom_data {
        u8 addr;
        u8 val;
index 5bef304..1249a54 100644 (file)
@@ -252,6 +252,15 @@ extern void dump_stack(void) __cold;
        printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_cont_once(fmt, ...)                                 \
        printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__)
+
+#if defined(DEBUG)
+#define pr_devel_once(fmt, ...)                                        \
+       printk_once(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_devel_once(fmt, ...)                                        \
+       no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#endif
+
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(DEBUG)
 #define pr_debug_once(fmt, ...)                                        \
@@ -295,6 +304,15 @@ extern void dump_stack(void) __cold;
 #define pr_info_ratelimited(fmt, ...)                                  \
        printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
 /* no pr_cont_ratelimited, don't do that... */
+
+#if defined(DEBUG)
+#define pr_devel_ratelimited(fmt, ...)                                 \
+       printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_devel_ratelimited(fmt, ...)                                 \
+       no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
+#endif
+
 /* If you are writing a driver, please use dev_dbg instead */
 #if defined(DEBUG)
 #define pr_debug_ratelimited(fmt, ...)                                 \
index dd6f06b..3e07a7d 100644 (file)
@@ -89,7 +89,8 @@ void kick_all_cpus_sync(void);
 #ifdef CONFIG_USE_GENERIC_SMP_HELPERS
 void __init call_function_init(void);
 void generic_smp_call_function_single_interrupt(void);
-void generic_smp_call_function_interrupt(void);
+#define generic_smp_call_function_interrupt \
+       generic_smp_call_function_single_interrupt
 #else
 static inline void call_function_init(void) { }
 #endif
index 126a817..900b948 100644 (file)
@@ -49,14 +49,14 @@ typedef __s64       Elf64_Sxword;
  *
  * Specifications are available in:
  *
- * - Sun microsystems: Linker and Libraries.
- *   Part No: 817-1984-17, September 2008.
- *   URL: http://docs.sun.com/app/docs/doc/817-1984
+ * - Oracle: Linker and Libraries.
+ *   Part No: 817–1984–19, August 2011.
+ *   http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf
  *
  * - System V ABI AMD64 Architecture Processor Supplement
- *   Draft Version 0.99.,
- *   May 11, 2009.
- *   URL: http://www.x86-64.org/
+ *   Draft Version 0.99.4,
+ *   January 13, 2010.
+ *   http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf
  */
 #define PN_XNUM 0xffff
 
index 780d4c6..c7fc1e6 100644 (file)
@@ -86,6 +86,9 @@ struct inodes_stat_t {
 #define MS_KERNMOUNT   (1<<22) /* this is a kern_mount call */
 #define MS_I_VERSION   (1<<23) /* Update inode I_version field */
 #define MS_STRICTATIME (1<<24) /* Always perform atime updates */
+
+/* These sb flags are internal to the kernel */
+#define MS_SNAP_STABLE (1<<27) /* Snapshot pages during writeback, if needed */
 #define MS_NOSEC       (1<<28)
 #define MS_BORN                (1<<29)
 #define MS_ACTIVE      (1<<30)
index 83ce5e6..89dc88a 100644 (file)
@@ -220,7 +220,6 @@ struct mipi_dsim_config {
 struct mipi_dsim_device {
        struct device                   *dev;
        int                             id;
-       struct resource                 *res;
        struct clk                      *clock;
        unsigned int                    irq;
        void __iomem                    *reg_base;
diff --git a/include/video/mmp_disp.h b/include/video/mmp_disp.h
new file mode 100644 (file)
index 0000000..b9dd1fb
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * linux/include/video/mmp_disp.h
+ * Header file for Marvell MMP Display Controller
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Authors: Zhou Zhu <zzhu3@marvell.com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _MMP_DISP_H_
+#define _MMP_DISP_H_
+#include <linux/kthread.h>
+
+enum {
+       PIXFMT_UYVY = 0,
+       PIXFMT_VYUY,
+       PIXFMT_YUYV,
+       PIXFMT_YUV422P,
+       PIXFMT_YVU422P,
+       PIXFMT_YUV420P,
+       PIXFMT_YVU420P,
+       PIXFMT_RGB565 = 0x100,
+       PIXFMT_BGR565,
+       PIXFMT_RGB1555,
+       PIXFMT_BGR1555,
+       PIXFMT_RGB888PACK,
+       PIXFMT_BGR888PACK,
+       PIXFMT_RGB888UNPACK,
+       PIXFMT_BGR888UNPACK,
+       PIXFMT_RGBA888,
+       PIXFMT_BGRA888,
+       PIXFMT_RGB666, /* for output usage */
+       PIXFMT_PSEUDOCOLOR = 0x200,
+};
+
+static inline int pixfmt_to_stride(int pix_fmt)
+{
+       switch (pix_fmt) {
+       case PIXFMT_RGB565:
+       case PIXFMT_BGR565:
+       case PIXFMT_RGB1555:
+       case PIXFMT_BGR1555:
+       case PIXFMT_UYVY:
+       case PIXFMT_VYUY:
+       case PIXFMT_YUYV:
+               return 2;
+       case PIXFMT_RGB888UNPACK:
+       case PIXFMT_BGR888UNPACK:
+       case PIXFMT_RGBA888:
+       case PIXFMT_BGRA888:
+               return 4;
+       case PIXFMT_RGB888PACK:
+       case PIXFMT_BGR888PACK:
+               return 3;
+       case PIXFMT_YUV422P:
+       case PIXFMT_YVU422P:
+       case PIXFMT_YUV420P:
+       case PIXFMT_YVU420P:
+       case PIXFMT_PSEUDOCOLOR:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+/* parameters used by path/overlay */
+/* overlay related para: win/addr */
+struct mmp_win {
+       /* position/size of window */
+       u16     xsrc;
+       u16     ysrc;
+       u16     xdst;
+       u16     ydst;
+       u16     xpos;
+       u16     ypos;
+       u16     left_crop;
+       u16     right_crop;
+       u16     up_crop;
+       u16     bottom_crop;
+       int     pix_fmt;
+};
+
+struct mmp_addr {
+       /* phys address */
+       u32     phys[6];
+};
+
+/* path related para: mode */
+struct mmp_mode {
+       const char *name;
+       u32 refresh;
+       u32 xres;
+       u32 yres;
+       u32 left_margin;
+       u32 right_margin;
+       u32 upper_margin;
+       u32 lower_margin;
+       u32 hsync_len;
+       u32 vsync_len;
+       u32 hsync_invert;
+       u32 vsync_invert;
+       u32 invert_pixclock;
+       u32 pixclock_freq;
+       int pix_fmt_out;
+};
+
+/* main structures */
+struct mmp_path;
+struct mmp_overlay;
+struct mmp_panel;
+
+/* status types */
+enum {
+       MMP_OFF = 0,
+       MMP_ON,
+};
+
+static inline const char *stat_name(int stat)
+{
+       switch (stat) {
+       case MMP_OFF:
+               return "OFF";
+       case MMP_ON:
+               return "ON";
+       default:
+               return "UNKNOWNSTAT";
+       }
+}
+
+struct mmp_overlay_ops {
+       /* should be provided by driver */
+       void (*set_fetch)(struct mmp_overlay *overlay, int fetch_id);
+       void (*set_onoff)(struct mmp_overlay *overlay, int status);
+       void (*set_win)(struct mmp_overlay *overlay, struct mmp_win *win);
+       int (*set_addr)(struct mmp_overlay *overlay, struct mmp_addr *addr);
+};
+
+/* overlay describes a z-order indexed slot in each path. */
+struct mmp_overlay {
+       int id;
+       const char *name;
+       struct mmp_path *path;
+
+       /* overlay info: private data */
+       int dmafetch_id;
+       struct mmp_addr addr;
+       struct mmp_win win;
+
+       /* state */
+       int open_count;
+       int status;
+       struct mutex access_ok;
+
+       struct mmp_overlay_ops *ops;
+};
+
+/* panel type */
+enum {
+       PANELTYPE_ACTIVE = 0,
+       PANELTYPE_SMART,
+       PANELTYPE_TV,
+       PANELTYPE_DSI_CMD,
+       PANELTYPE_DSI_VIDEO,
+};
+
+struct mmp_panel {
+       /* use node to register to list */
+       struct list_head node;
+       const char *name;
+       /* path name used to connect to proper path configed */
+       const char *plat_path_name;
+       struct device *dev;
+       int panel_type;
+       void *plat_data;
+       int (*get_modelist)(struct mmp_panel *panel,
+                       struct mmp_mode **modelist);
+       void (*set_mode)(struct mmp_panel *panel,
+                       struct mmp_mode *mode);
+       void (*set_onoff)(struct mmp_panel *panel,
+                       int status);
+};
+
+struct mmp_path_ops {
+       int (*check_status)(struct mmp_path *path);
+       struct mmp_overlay *(*get_overlay)(struct mmp_path *path,
+                       int overlay_id);
+       int (*get_modelist)(struct mmp_path *path,
+                       struct mmp_mode **modelist);
+
+       /* follow ops should be provided by driver */
+       void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode);
+       void (*set_onoff)(struct mmp_path *path, int status);
+       /* todo: add query */
+};
+
+/* path output types */
+enum {
+       PATH_OUT_PARALLEL,
+       PATH_OUT_DSI,
+       PATH_OUT_HDMI,
+};
+
+/* path is main part of mmp-disp */
+struct mmp_path {
+       /* use node to register to list */
+       struct list_head node;
+
+       /* init data */
+       struct device *dev;
+
+       int id;
+       const char *name;
+       int output_type;
+       struct mmp_panel *panel;
+       void *plat_data;
+
+       /* dynamic use */
+       struct mmp_mode mode;
+
+       /* state */
+       int open_count;
+       int status;
+       struct mutex access_ok;
+
+       struct mmp_path_ops ops;
+
+       /* layers */
+       int overlay_num;
+       struct mmp_overlay overlays[0];
+};
+
+extern struct mmp_path *mmp_get_path(const char *name);
+static inline void mmp_path_set_mode(struct mmp_path *path,
+               struct mmp_mode *mode)
+{
+       if (path)
+               path->ops.set_mode(path, mode);
+}
+static inline void mmp_path_set_onoff(struct mmp_path *path, int status)
+{
+       if (path)
+               path->ops.set_onoff(path, status);
+}
+static inline int mmp_path_get_modelist(struct mmp_path *path,
+               struct mmp_mode **modelist)
+{
+       if (path)
+               return path->ops.get_modelist(path, modelist);
+       return 0;
+}
+static inline struct mmp_overlay *mmp_path_get_overlay(
+               struct mmp_path *path, int overlay_id)
+{
+       if (path)
+               return path->ops.get_overlay(path, overlay_id);
+       return NULL;
+}
+static inline void mmp_overlay_set_fetch(struct mmp_overlay *overlay,
+               int fetch_id)
+{
+       if (overlay)
+               overlay->ops->set_fetch(overlay, fetch_id);
+}
+static inline void mmp_overlay_set_onoff(struct mmp_overlay *overlay,
+               int status)
+{
+       if (overlay)
+               overlay->ops->set_onoff(overlay, status);
+}
+static inline void mmp_overlay_set_win(struct mmp_overlay *overlay,
+               struct mmp_win *win)
+{
+       if (overlay)
+               overlay->ops->set_win(overlay, win);
+}
+static inline int mmp_overlay_set_addr(struct mmp_overlay *overlay,
+               struct mmp_addr *addr)
+{
+       if (overlay)
+               return overlay->ops->set_addr(overlay, addr);
+       return 0;
+}
+
+/*
+ * driver data is set from each detailed ctrl driver for path usage
+ * it defined a common interface that plat driver need to implement
+ */
+struct mmp_path_info {
+       /* driver data, set when registed*/
+       const char *name;
+       struct device *dev;
+       int id;
+       int output_type;
+       int overlay_num;
+       void (*set_mode)(struct mmp_path *path, struct mmp_mode *mode);
+       void (*set_onoff)(struct mmp_path *path, int status);
+       struct mmp_overlay_ops *overlay_ops;
+       void *plat_data;
+};
+
+extern struct mmp_path *mmp_register_path(
+               struct mmp_path_info *info);
+extern void mmp_unregister_path(struct mmp_path *path);
+extern void mmp_register_panel(struct mmp_panel *panel);
+extern void mmp_unregister_panel(struct mmp_panel *panel);
+
+/* defintions for platform data */
+/* interface for buffer driver */
+struct mmp_buffer_driver_mach_info {
+       const char      *name;
+       const char      *path_name;
+       int     overlay_id;
+       int     dmafetch_id;
+       int     default_pixfmt;
+};
+
+/* interface for controllers driver */
+struct mmp_mach_path_config {
+       const char *name;
+       int overlay_num;
+       int output_type;
+       u32 path_config;
+       u32 link_config;
+};
+
+struct mmp_mach_plat_info {
+       const char *name;
+       const char *clk_name;
+       int path_num;
+       struct mmp_mach_path_config *paths;
+};
+
+/* interface for panel drivers */
+struct mmp_mach_panel_info {
+       const char *name;
+       void (*plat_set_onoff)(int status);
+       const char *plat_path_name;
+};
+#endif /* _MMP_DISP_H_ */
index e755448..b039320 100644 (file)
@@ -8,12 +8,8 @@
  * S3C Platform - new-style fimd and framebuffer register definitions
  *
  * This is the register set for the fimd and new style framebuffer interface
- * found from the S3C2443 onwards into the S3C2416, S3C2450 and the
- * S3C64XX series such as the S3C6400 and S3C6410.
- *
- * The file does not contain the cpu specific items which are based on
- * whichever architecture is selected, it only contains the core of the
- * register set. See <mach/regs-fb.h> to get the specifics.
+ * found from the S3C2443 onwards into the S3C2416, S3C2450, the
+ * S3C64XX series such as the S3C6400 and S3C6410, and EXYNOS series.
  *
  * 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
 
 /* VIDCON0 */
 
-#define VIDCON0                                        (0x00)
+#define VIDCON0                                        0x00
 #define VIDCON0_INTERLACE                      (1 << 29)
 #define VIDCON0_VIDOUT_MASK                    (0x7 << 26)
-#define VIDCON0_VIDOUT_SHIFT                   (26)
+#define VIDCON0_VIDOUT_SHIFT                   26
 #define VIDCON0_VIDOUT_RGB                     (0x0 << 26)
 #define VIDCON0_VIDOUT_TV                      (0x1 << 26)
 #define VIDCON0_VIDOUT_I80_LDI0                        (0x2 << 26)
@@ -35,7 +31,7 @@
 #define VIDCON0_VIDOUT_WB_I80_LDI1             (0x7 << 26)
 
 #define VIDCON0_L1_DATA_MASK                   (0x7 << 23)
-#define VIDCON0_L1_DATA_SHIFT                  (23)
+#define VIDCON0_L1_DATA_SHIFT                  23
 #define VIDCON0_L1_DATA_16BPP                  (0x0 << 23)
 #define VIDCON0_L1_DATA_18BPP16                        (0x1 << 23)
 #define VIDCON0_L1_DATA_18BPP9                 (0x2 << 23)
@@ -44,7 +40,7 @@
 #define VIDCON0_L1_DATA_16BPP8                 (0x5 << 23)
 
 #define VIDCON0_L0_DATA_MASK                   (0x7 << 20)
-#define VIDCON0_L0_DATA_SHIFT                  (20)
+#define VIDCON0_L0_DATA_SHIFT                  20
 #define VIDCON0_L0_DATA_16BPP                  (0x0 << 20)
 #define VIDCON0_L0_DATA_18BPP16                        (0x1 << 20)
 #define VIDCON0_L0_DATA_18BPP9                 (0x2 << 20)
@@ -53,7 +49,7 @@
 #define VIDCON0_L0_DATA_16BPP8                 (0x5 << 20)
 
 #define VIDCON0_PNRMODE_MASK                   (0x3 << 17)
-#define VIDCON0_PNRMODE_SHIFT                  (17)
+#define VIDCON0_PNRMODE_SHIFT                  17
 #define VIDCON0_PNRMODE_RGB                    (0x0 << 17)
 #define VIDCON0_PNRMODE_BGR                    (0x1 << 17)
 #define VIDCON0_PNRMODE_SERIAL_RGB             (0x2 << 17)
 
 #define VIDCON0_CLKVALUP                       (1 << 16)
 #define VIDCON0_CLKVAL_F_MASK                  (0xff << 6)
-#define VIDCON0_CLKVAL_F_SHIFT                 (6)
-#define VIDCON0_CLKVAL_F_LIMIT                 (0xff)
+#define VIDCON0_CLKVAL_F_SHIFT                 6
+#define VIDCON0_CLKVAL_F_LIMIT                 0xff
 #define VIDCON0_CLKVAL_F(_x)                   ((_x) << 6)
 #define VIDCON0_VLCKFREE                       (1 << 5)
 #define VIDCON0_CLKDIR                         (1 << 4)
 
 #define VIDCON0_CLKSEL_MASK                    (0x3 << 2)
-#define VIDCON0_CLKSEL_SHIFT                   (2)
+#define VIDCON0_CLKSEL_SHIFT                   2
 #define VIDCON0_CLKSEL_HCLK                    (0x0 << 2)
 #define VIDCON0_CLKSEL_LCD                     (0x1 << 2)
 #define VIDCON0_CLKSEL_27M                     (0x3 << 2)
 #define VIDCON0_ENVID                          (1 << 1)
 #define VIDCON0_ENVID_F                                (1 << 0)
 
-#define VIDCON1                                        (0x04)
+#define VIDCON1                                        0x04
 #define VIDCON1_LINECNT_MASK                   (0x7ff << 16)
-#define VIDCON1_LINECNT_SHIFT                  (16)
+#define VIDCON1_LINECNT_SHIFT                  16
 #define VIDCON1_LINECNT_GET(_v)                        (((_v) >> 16) & 0x7ff)
 #define VIDCON1_FSTATUS_EVEN                   (1 << 15)
 #define VIDCON1_VSTATUS_MASK                   (0x3 << 13)
-#define VIDCON1_VSTATUS_SHIFT                  (13)
+#define VIDCON1_VSTATUS_SHIFT                  13
 #define VIDCON1_VSTATUS_VSYNC                  (0x0 << 13)
 #define VIDCON1_VSTATUS_BACKPORCH              (0x1 << 13)
 #define VIDCON1_VSTATUS_ACTIVE                 (0x2 << 13)
-#define VIDCON1_VSTATUS_FRONTPORCH             (0x0 << 13)
+#define VIDCON1_VSTATUS_FRONTPORCH             (0x3 << 13)
 #define VIDCON1_VCLK_MASK                      (0x3 << 9)
 #define VIDCON1_VCLK_HOLD                      (0x0 << 9)
 #define VIDCON1_VCLK_RUN                       (0x1 << 9)
 
 /* VIDCON2 */
 
-#define VIDCON2                                        (0x08)
+#define VIDCON2                                        0x08
 #define VIDCON2_EN601                          (1 << 23)
 #define VIDCON2_TVFMTSEL_SW                    (1 << 14)
 
 #define VIDCON2_TVFMTSEL1_MASK                 (0x3 << 12)
-#define VIDCON2_TVFMTSEL1_SHIFT                        (12)
+#define VIDCON2_TVFMTSEL1_SHIFT                        12
 #define VIDCON2_TVFMTSEL1_RGB                  (0x0 << 12)
 #define VIDCON2_TVFMTSEL1_YUV422               (0x1 << 12)
 #define VIDCON2_TVFMTSEL1_YUV444               (0x2 << 12)
  * Might not be present in the S3C6410 documentation,
  * but tests prove it's there almost for sure; shouldn't hurt in any case.
  */
-#define PRTCON                                 (0x0c)
+#define PRTCON                                 0x0c
 #define PRTCON_PROTECT                         (1 << 11)
 
 /* VIDTCON0 */
 
-#define VIDTCON0                               (0x10)
+#define VIDTCON0                               0x10
 #define VIDTCON0_VBPDE_MASK                    (0xff << 24)
-#define VIDTCON0_VBPDE_SHIFT                   (24)
-#define VIDTCON0_VBPDE_LIMIT                   (0xff)
+#define VIDTCON0_VBPDE_SHIFT                   24
+#define VIDTCON0_VBPDE_LIMIT                   0xff
 #define VIDTCON0_VBPDE(_x)                     ((_x) << 24)
 
 #define VIDTCON0_VBPD_MASK                     (0xff << 16)
-#define VIDTCON0_VBPD_SHIFT                    (16)
-#define VIDTCON0_VBPD_LIMIT                    (0xff)
+#define VIDTCON0_VBPD_SHIFT                    16
+#define VIDTCON0_VBPD_LIMIT                    0xff
 #define VIDTCON0_VBPD(_x)                      ((_x) << 16)
 
 #define VIDTCON0_VFPD_MASK                     (0xff << 8)
-#define VIDTCON0_VFPD_SHIFT                    (8)
-#define VIDTCON0_VFPD_LIMIT                    (0xff)
+#define VIDTCON0_VFPD_SHIFT                    8
+#define VIDTCON0_VFPD_LIMIT                    0xff
 #define VIDTCON0_VFPD(_x)                      ((_x) << 8)
 
 #define VIDTCON0_VSPW_MASK                     (0xff << 0)
-#define VIDTCON0_VSPW_SHIFT                    (0)
-#define VIDTCON0_VSPW_LIMIT                    (0xff)
+#define VIDTCON0_VSPW_SHIFT                    0
+#define VIDTCON0_VSPW_LIMIT                    0xff
 #define VIDTCON0_VSPW(_x)                      ((_x) << 0)
 
 /* VIDTCON1 */
 
-#define VIDTCON1                               (0x14)
+#define VIDTCON1                               0x14
 #define VIDTCON1_VFPDE_MASK                    (0xff << 24)
-#define VIDTCON1_VFPDE_SHIFT                   (24)
-#define VIDTCON1_VFPDE_LIMIT                   (0xff)
+#define VIDTCON1_VFPDE_SHIFT                   24
+#define VIDTCON1_VFPDE_LIMIT                   0xff
 #define VIDTCON1_VFPDE(_x)                     ((_x) << 24)
 
 #define VIDTCON1_HBPD_MASK                     (0xff << 16)
-#define VIDTCON1_HBPD_SHIFT                    (16)
-#define VIDTCON1_HBPD_LIMIT                    (0xff)
+#define VIDTCON1_HBPD_SHIFT                    16
+#define VIDTCON1_HBPD_LIMIT                    0xff
 #define VIDTCON1_HBPD(_x)                      ((_x) << 16)
 
 #define VIDTCON1_HFPD_MASK                     (0xff << 8)
-#define VIDTCON1_HFPD_SHIFT                    (8)
-#define VIDTCON1_HFPD_LIMIT                    (0xff)
+#define VIDTCON1_HFPD_SHIFT                    8
+#define VIDTCON1_HFPD_LIMIT                    0xff
 #define VIDTCON1_HFPD(_x)                      ((_x) << 8)
 
 #define VIDTCON1_HSPW_MASK                     (0xff << 0)
-#define VIDTCON1_HSPW_SHIFT                    (0)
-#define VIDTCON1_HSPW_LIMIT                    (0xff)
+#define VIDTCON1_HSPW_SHIFT                    0
+#define VIDTCON1_HSPW_LIMIT                    0xff
 #define VIDTCON1_HSPW(_x)                      ((_x) << 0)
 
-#define VIDTCON2                               (0x18)
-#define VIDTCON2                               (0x18)
+#define VIDTCON2                               0x18
 #define VIDTCON2_LINEVAL_E(_x)                 ((((_x) & 0x800) >> 11) << 23)
 #define VIDTCON2_LINEVAL_MASK                  (0x7ff << 11)
-#define VIDTCON2_LINEVAL_SHIFT                 (11)
-#define VIDTCON2_LINEVAL_LIMIT                 (0x7ff)
+#define VIDTCON2_LINEVAL_SHIFT                 11
+#define VIDTCON2_LINEVAL_LIMIT                 0x7ff
 #define VIDTCON2_LINEVAL(_x)                   (((_x) & 0x7ff) << 11)
 
 #define VIDTCON2_HOZVAL_E(_x)                  ((((_x) & 0x800) >> 11) << 22)
 #define VIDTCON2_HOZVAL_MASK                   (0x7ff << 0)
-#define VIDTCON2_HOZVAL_SHIFT                  (0)
-#define VIDTCON2_HOZVAL_LIMIT                  (0x7ff)
+#define VIDTCON2_HOZVAL_SHIFT                  0
+#define VIDTCON2_HOZVAL_LIMIT                  0x7ff
 #define VIDTCON2_HOZVAL(_x)                    (((_x) & 0x7ff) << 0)
 
 /* WINCONx */
 
 #define WINCON(_win)                           (0x20 + ((_win) * 4))
+#define WINCONx_CSCCON_EQ601                   (0x0 << 28)
+#define WINCONx_CSCCON_EQ709                   (0x1 << 28)
 #define WINCONx_CSCWIDTH_MASK                  (0x3 << 26)
-#define WINCONx_CSCWIDTH_SHIFT                 (26)
+#define WINCONx_CSCWIDTH_SHIFT                 26
 #define WINCONx_CSCWIDTH_WIDE                  (0x0 << 26)
 #define WINCONx_CSCWIDTH_NARROW                        (0x3 << 26)
 #define WINCONx_ENLOCAL                                (1 << 22)
 #define WINCONx_WSWP                           (1 << 15)
 #define WINCONx_YCbCr                          (1 << 13)
 #define WINCONx_BURSTLEN_MASK                  (0x3 << 9)
-#define WINCONx_BURSTLEN_SHIFT                 (9)
+#define WINCONx_BURSTLEN_SHIFT                 9
 #define WINCONx_BURSTLEN_16WORD                        (0x0 << 9)
 #define WINCONx_BURSTLEN_8WORD                 (0x1 << 9)
 #define WINCONx_BURSTLEN_4WORD                 (0x2 << 9)
 #define WINCONx_ENWIN                          (1 << 0)
 
 #define WINCON0_BPPMODE_MASK                   (0xf << 2)
-#define WINCON0_BPPMODE_SHIFT                  (2)
+#define WINCON0_BPPMODE_SHIFT                  2
 #define WINCON0_BPPMODE_1BPP                   (0x0 << 2)
 #define WINCON0_BPPMODE_2BPP                   (0x1 << 2)
 #define WINCON0_BPPMODE_4BPP                   (0x2 << 2)
 #define WINCON1_LOCALSEL_CAMIF                 (1 << 23)
 #define WINCON1_BLD_PIX                                (1 << 6)
 #define WINCON1_BPPMODE_MASK                   (0xf << 2)
-#define WINCON1_BPPMODE_SHIFT                  (2)
+#define WINCON1_BPPMODE_SHIFT                  2
 #define WINCON1_BPPMODE_1BPP                   (0x0 << 2)
 #define WINCON1_BPPMODE_2BPP                   (0x1 << 2)
 #define WINCON1_BPPMODE_4BPP                   (0x2 << 2)
 #define WINCON1_ALPHA_SEL                      (1 << 1)
 
 /* S5PV210 */
-#define SHADOWCON                              (0x34)
+#define SHADOWCON                              0x34
 #define SHADOWCON_WINx_PROTECT(_win)           (1 << (10 + (_win)))
 /* DMA channels (all windows) */
 #define SHADOWCON_CHx_ENABLE(_win)             (1 << (_win))
 
 /* VIDOSDx */
 
-#define VIDOSD_BASE                            (0x40)
+#define VIDOSD_BASE                            0x40
 #define VIDOSDxA_TOPLEFT_X_E(_x)               ((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxA_TOPLEFT_X_MASK                        (0x7ff << 11)
-#define VIDOSDxA_TOPLEFT_X_SHIFT               (11)
-#define VIDOSDxA_TOPLEFT_X_LIMIT               (0x7ff)
+#define VIDOSDxA_TOPLEFT_X_SHIFT               11
+#define VIDOSDxA_TOPLEFT_X_LIMIT               0x7ff
 #define VIDOSDxA_TOPLEFT_X(_x)                 (((_x) & 0x7ff) << 11)
 
 #define VIDOSDxA_TOPLEFT_Y_E(_x)               ((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxA_TOPLEFT_Y_MASK                        (0x7ff << 0)
-#define VIDOSDxA_TOPLEFT_Y_SHIFT               (0)
-#define VIDOSDxA_TOPLEFT_Y_LIMIT               (0x7ff)
+#define VIDOSDxA_TOPLEFT_Y_SHIFT               0
+#define VIDOSDxA_TOPLEFT_Y_LIMIT               0x7ff
 #define VIDOSDxA_TOPLEFT_Y(_x)                 (((_x) & 0x7ff) << 0)
 
 #define VIDOSDxB_BOTRIGHT_X_E(_x)              ((((_x) & 0x800) >> 11) << 23)
 #define VIDOSDxB_BOTRIGHT_X_MASK               (0x7ff << 11)
-#define VIDOSDxB_BOTRIGHT_X_SHIFT              (11)
-#define VIDOSDxB_BOTRIGHT_X_LIMIT              (0x7ff)
+#define VIDOSDxB_BOTRIGHT_X_SHIFT              11
+#define VIDOSDxB_BOTRIGHT_X_LIMIT              0x7ff
 #define VIDOSDxB_BOTRIGHT_X(_x)                        (((_x) & 0x7ff) << 11)
 
 #define VIDOSDxB_BOTRIGHT_Y_E(_x)              ((((_x) & 0x800) >> 11) << 22)
 #define VIDOSDxB_BOTRIGHT_Y_MASK               (0x7ff << 0)
-#define VIDOSDxB_BOTRIGHT_Y_SHIFT              (0)
-#define VIDOSDxB_BOTRIGHT_Y_LIMIT              (0x7ff)
+#define VIDOSDxB_BOTRIGHT_Y_SHIFT              0
+#define VIDOSDxB_BOTRIGHT_Y_LIMIT              0x7ff
 #define VIDOSDxB_BOTRIGHT_Y(_x)                        (((_x) & 0x7ff) << 0)
 
 /* For VIDOSD[1..4]C */
 #define VIDISD14C_ALPHA0_R(_x)                 ((_x) << 20)
 #define VIDISD14C_ALPHA0_G_MASK                        (0xf << 16)
-#define VIDISD14C_ALPHA0_G_SHIFT               (16)
-#define VIDISD14C_ALPHA0_G_LIMIT               (0xf)
+#define VIDISD14C_ALPHA0_G_SHIFT               16
+#define VIDISD14C_ALPHA0_G_LIMIT               0xf
 #define VIDISD14C_ALPHA0_G(_x)                 ((_x) << 16)
 #define VIDISD14C_ALPHA0_B_MASK                        (0xf << 12)
-#define VIDISD14C_ALPHA0_B_SHIFT               (12)
-#define VIDISD14C_ALPHA0_B_LIMIT               (0xf)
+#define VIDISD14C_ALPHA0_B_SHIFT               12
+#define VIDISD14C_ALPHA0_B_LIMIT               0xf
 #define VIDISD14C_ALPHA0_B(_x)                 ((_x) << 12)
 #define VIDISD14C_ALPHA1_R_MASK                        (0xf << 8)
-#define VIDISD14C_ALPHA1_R_SHIFT               (8)
-#define VIDISD14C_ALPHA1_R_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_R_SHIFT               8
+#define VIDISD14C_ALPHA1_R_LIMIT               0xf
 #define VIDISD14C_ALPHA1_R(_x)                 ((_x) << 8)
 #define VIDISD14C_ALPHA1_G_MASK                        (0xf << 4)
-#define VIDISD14C_ALPHA1_G_SHIFT               (4)
-#define VIDISD14C_ALPHA1_G_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_G_SHIFT               4
+#define VIDISD14C_ALPHA1_G_LIMIT               0xf
 #define VIDISD14C_ALPHA1_G(_x)                 ((_x) << 4)
 #define VIDISD14C_ALPHA1_B_MASK                        (0xf << 0)
-#define VIDISD14C_ALPHA1_B_SHIFT               (0)
-#define VIDISD14C_ALPHA1_B_LIMIT               (0xf)
+#define VIDISD14C_ALPHA1_B_SHIFT               0
+#define VIDISD14C_ALPHA1_B_LIMIT               0xf
 #define VIDISD14C_ALPHA1_B(_x)                 ((_x) << 0)
 
 /* Video buffer addresses */
 
 #define VIDW_BUF_SIZE_OFFSET_E(_x)             ((((_x) & 0x2000) >> 13) << 27)
 #define VIDW_BUF_SIZE_OFFSET_MASK              (0x1fff << 13)
-#define VIDW_BUF_SIZE_OFFSET_SHIFT             (13)
-#define VIDW_BUF_SIZE_OFFSET_LIMIT             (0x1fff)
+#define VIDW_BUF_SIZE_OFFSET_SHIFT             13
+#define VIDW_BUF_SIZE_OFFSET_LIMIT             0x1fff
 #define VIDW_BUF_SIZE_OFFSET(_x)               (((_x) & 0x1fff) << 13)
 
 #define VIDW_BUF_SIZE_PAGEWIDTH_E(_x)          ((((_x) & 0x2000) >> 13) << 26)
 #define VIDW_BUF_SIZE_PAGEWIDTH_MASK           (0x1fff << 0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT          (0)
-#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT          (0x1fff)
+#define VIDW_BUF_SIZE_PAGEWIDTH_SHIFT          0
+#define VIDW_BUF_SIZE_PAGEWIDTH_LIMIT          0x1fff
 #define VIDW_BUF_SIZE_PAGEWIDTH(_x)            (((_x) & 0x1fff) << 0)
 
 /* Interrupt controls and status */
 
-#define VIDINTCON0                             (0x130)
+#define VIDINTCON0                             0x130
 #define VIDINTCON0_FIFOINTERVAL_MASK           (0x3f << 20)
-#define VIDINTCON0_FIFOINTERVAL_SHIFT          (20)
-#define VIDINTCON0_FIFOINTERVAL_LIMIT          (0x3f)
+#define VIDINTCON0_FIFOINTERVAL_SHIFT          20
+#define VIDINTCON0_FIFOINTERVAL_LIMIT          0x3f
 #define VIDINTCON0_FIFOINTERVAL(_x)            ((_x) << 20)
 
 #define VIDINTCON0_INT_SYSMAINCON              (1 << 19)
 #define VIDINTCON0_INT_I80IFDONE               (1 << 17)
 
 #define VIDINTCON0_FRAMESEL0_MASK              (0x3 << 15)
-#define VIDINTCON0_FRAMESEL0_SHIFT             (15)
+#define VIDINTCON0_FRAMESEL0_SHIFT             15
 #define VIDINTCON0_FRAMESEL0_BACKPORCH         (0x0 << 15)
 #define VIDINTCON0_FRAMESEL0_VSYNC             (0x1 << 15)
 #define VIDINTCON0_FRAMESEL0_ACTIVE            (0x2 << 15)
 
 #define VIDINTCON0_INT_FRAME                   (1 << 12)
 #define VIDINTCON0_FIFIOSEL_MASK               (0x7f << 5)
-#define VIDINTCON0_FIFIOSEL_SHIFT              (5)
+#define VIDINTCON0_FIFIOSEL_SHIFT              5
 #define VIDINTCON0_FIFIOSEL_WINDOW0            (0x1 << 5)
 #define VIDINTCON0_FIFIOSEL_WINDOW1            (0x2 << 5)
 #define VIDINTCON0_FIFIOSEL_WINDOW2            (0x10 << 5)
 #define VIDINTCON0_FIFIOSEL_WINDOW4            (0x40 << 5)
 
 #define VIDINTCON0_FIFOLEVEL_MASK              (0x7 << 2)
-#define VIDINTCON0_FIFOLEVEL_SHIFT             (2)
+#define VIDINTCON0_FIFOLEVEL_SHIFT             2
 #define VIDINTCON0_FIFOLEVEL_TO25PC            (0x0 << 2)
 #define VIDINTCON0_FIFOLEVEL_TO50PC            (0x1 << 2)
 #define VIDINTCON0_FIFOLEVEL_TO75PC            (0x2 << 2)
 #define VIDINTCON0_FIFOLEVEL_FULL              (0x4 << 2)
 
 #define VIDINTCON0_INT_FIFO_MASK               (0x3 << 0)
-#define VIDINTCON0_INT_FIFO_SHIFT              (0)
+#define VIDINTCON0_INT_FIFO_SHIFT              0
 #define VIDINTCON0_INT_ENABLE                  (1 << 0)
 
-#define VIDINTCON1                             (0x134)
+#define VIDINTCON1                             0x134
 #define VIDINTCON1_INT_I180                    (1 << 2)
 #define VIDINTCON1_INT_FRAME                   (1 << 1)
 #define VIDINTCON1_INT_FIFO                    (1 << 0)
 
 /* Window colour-key control registers */
-#define WKEYCON                                        (0x140) /* 6410,V210 */
+#define WKEYCON                                        0x140
 
-#define WKEYCON0                               (0x00)
-#define WKEYCON1                               (0x04)
+#define WKEYCON0                               0x00
+#define WKEYCON1                               0x04
 
 #define WxKEYCON0_KEYBL_EN                     (1 << 26)
 #define WxKEYCON0_KEYEN_F                      (1 << 25)
 #define WxKEYCON0_DIRCON                       (1 << 24)
 #define WxKEYCON0_COMPKEY_MASK                 (0xffffff << 0)
-#define WxKEYCON0_COMPKEY_SHIFT                        (0)
-#define WxKEYCON0_COMPKEY_LIMIT                        (0xffffff)
+#define WxKEYCON0_COMPKEY_SHIFT                        0
+#define WxKEYCON0_COMPKEY_LIMIT                        0xffffff
 #define WxKEYCON0_COMPKEY(_x)                  ((_x) << 0)
 #define WxKEYCON1_COLVAL_MASK                  (0xffffff << 0)
-#define WxKEYCON1_COLVAL_SHIFT                 (0)
-#define WxKEYCON1_COLVAL_LIMIT                 (0xffffff)
+#define WxKEYCON1_COLVAL_SHIFT                 0
+#define WxKEYCON1_COLVAL_LIMIT                 0xffffff
 #define WxKEYCON1_COLVAL(_x)                   ((_x) << 0)
 
 /* Dithering control */
-#define DITHMODE                               (0x170)
+#define DITHMODE                               0x170
 #define DITHMODE_R_POS_MASK                    (0x3 << 5)
-#define DITHMODE_R_POS_SHIFT                   (5)
+#define DITHMODE_R_POS_SHIFT                   5
 #define DITHMODE_R_POS_8BIT                    (0x0 << 5)
 #define DITHMODE_R_POS_6BIT                    (0x1 << 5)
 #define DITHMODE_R_POS_5BIT                    (0x2 << 5)
 #define DITHMODE_G_POS_MASK                    (0x3 << 3)
-#define DITHMODE_G_POS_SHIFT                   (3)
+#define DITHMODE_G_POS_SHIFT                   3
 #define DITHMODE_G_POS_8BIT                    (0x0 << 3)
 #define DITHMODE_G_POS_6BIT                    (0x1 << 3)
 #define DITHMODE_G_POS_5BIT                    (0x2 << 3)
 #define DITHMODE_B_POS_MASK                    (0x3 << 1)
-#define DITHMODE_B_POS_SHIFT                   (1)
+#define DITHMODE_B_POS_SHIFT                   1
 #define DITHMODE_B_POS_8BIT                    (0x0 << 1)
 #define DITHMODE_B_POS_6BIT                    (0x1 << 1)
 #define DITHMODE_B_POS_5BIT                    (0x2 << 1)
 #define WINxMAP(_win)                          (0x180 + ((_win) * 4))
 #define WINxMAP_MAP                            (1 << 24)
 #define WINxMAP_MAP_COLOUR_MASK                        (0xffffff << 0)
-#define WINxMAP_MAP_COLOUR_SHIFT               (0)
-#define WINxMAP_MAP_COLOUR_LIMIT               (0xffffff)
+#define WINxMAP_MAP_COLOUR_SHIFT               0
+#define WINxMAP_MAP_COLOUR_LIMIT               0xffffff
 #define WINxMAP_MAP_COLOUR(_x)                 ((_x) << 0)
 
 /* Winodw palette control */
-#define WPALCON                                        (0x1A0)
+#define WPALCON                                        0x1A0
 #define WPALCON_PAL_UPDATE                     (1 << 9)
 #define WPALCON_W4PAL_16BPP_A555               (1 << 8)
 #define WPALCON_W3PAL_16BPP_A555               (1 << 7)
 #define WPALCON_W2PAL_16BPP_A555               (1 << 6)
 #define WPALCON_W1PAL_MASK                     (0x7 << 3)
-#define WPALCON_W1PAL_SHIFT                    (3)
+#define WPALCON_W1PAL_SHIFT                    3
 #define WPALCON_W1PAL_25BPP_A888               (0x0 << 3)
 #define WPALCON_W1PAL_24BPP                    (0x1 << 3)
 #define WPALCON_W1PAL_19BPP_A666               (0x2 << 3)
 #define WPALCON_W1PAL_16BPP_A555               (0x5 << 3)
 #define WPALCON_W1PAL_16BPP_565                        (0x6 << 3)
 #define WPALCON_W0PAL_MASK                     (0x7 << 0)
-#define WPALCON_W0PAL_SHIFT                    (0)
+#define WPALCON_W0PAL_SHIFT                    0
 #define WPALCON_W0PAL_25BPP_A888               (0x0 << 0)
 #define WPALCON_W0PAL_24BPP                    (0x1 << 0)
 #define WPALCON_W0PAL_19BPP_A666               (0x2 << 0)
 #define WPALCON_W0PAL_16BPP_565                        (0x6 << 0)
 
 /* Blending equation control */
-#define BLENDCON                               (0x260)
+#define BLENDCON                               0x260
 #define BLENDCON_NEW_MASK                      (1 << 0)
 #define BLENDCON_NEW_8BIT_ALPHA_VALUE          (1 << 0)
 #define BLENDCON_NEW_4BIT_ALPHA_VALUE          (0 << 0)
 
-#define S3C_FB_MAX_WIN (5)  /* number of hardware windows available. */
-
 /* Notes on per-window bpp settings
  *
  * Value       Win0     Win1     Win2     Win3     Win 4
 */
 
 /* FIMD Version 8 register offset definitions */
-#define FIMD_V8_VIDTCON0       (0x20010)
-#define FIMD_V8_VIDTCON1       (0x20014)
-#define FIMD_V8_VIDTCON2       (0x20018)
-#define FIMD_V8_VIDTCON3       (0x2001C)
-#define FIMD_V8_VIDCON1                (0x20004)
+#define FIMD_V8_VIDTCON0       0x20010
+#define FIMD_V8_VIDTCON1       0x20014
+#define FIMD_V8_VIDTCON2       0x20018
+#define FIMD_V8_VIDTCON3       0x2001C
+#define FIMD_V8_VIDCON1                0x20004
index 36700e9..f4bddb9 100644 (file)
@@ -593,7 +593,7 @@ COMPAT_SYSCALL_DEFINE5(waitid,
                else
                        ret = put_compat_rusage(&ru, uru);
                if (ret)
-                       return ret;
+                       return -EFAULT;
        }
 
        BUG_ON(info.si_code & __SI_MASK);
index 78e2ecb..b781e66 100644 (file)
@@ -153,8 +153,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
                goto out;
        }
 
-       new_ns = create_new_namespaces(flags, tsk,
-                                      task_cred_xxx(tsk, user_ns), tsk->fs);
+       new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);
        if (IS_ERR(new_ns)) {
                err = PTR_ERR(new_ns);
                goto out;
index 69f38bd..8e451f3 100644 (file)
 #include "smpboot.h"
 
 #ifdef CONFIG_USE_GENERIC_SMP_HELPERS
-static struct {
-       struct list_head        queue;
-       raw_spinlock_t          lock;
-} call_function __cacheline_aligned_in_smp =
-       {
-               .queue          = LIST_HEAD_INIT(call_function.queue),
-               .lock           = __RAW_SPIN_LOCK_UNLOCKED(call_function.lock),
-       };
-
 enum {
        CSD_FLAG_LOCK           = 0x01,
 };
 
 struct call_function_data {
-       struct call_single_data csd;
-       atomic_t                refs;
+       struct call_single_data __percpu *csd;
        cpumask_var_t           cpumask;
        cpumask_var_t           cpumask_ipi;
 };
@@ -60,6 +50,11 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
                if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
                                cpu_to_node(cpu)))
                        return notifier_from_errno(-ENOMEM);
+               cfd->csd = alloc_percpu(struct call_single_data);
+               if (!cfd->csd) {
+                       free_cpumask_var(cfd->cpumask);
+                       return notifier_from_errno(-ENOMEM);
+               }
                break;
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -70,6 +65,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DEAD_FROZEN:
                free_cpumask_var(cfd->cpumask);
                free_cpumask_var(cfd->cpumask_ipi);
+               free_percpu(cfd->csd);
                break;
 #endif
        };
@@ -171,85 +167,6 @@ void generic_exec_single(int cpu, struct call_single_data *data, int wait)
 }
 
 /*
- * Invoked by arch to handle an IPI for call function. Must be called with
- * interrupts disabled.
- */
-void generic_smp_call_function_interrupt(void)
-{
-       struct call_function_data *data;
-       int cpu = smp_processor_id();
-
-       /*
-        * Shouldn't receive this interrupt on a cpu that is not yet online.
-        */
-       WARN_ON_ONCE(!cpu_online(cpu));
-
-       /*
-        * Ensure entry is visible on call_function_queue after we have
-        * entered the IPI. See comment in smp_call_function_many.
-        * If we don't have this, then we may miss an entry on the list
-        * and never get another IPI to process it.
-        */
-       smp_mb();
-
-       /*
-        * It's ok to use list_for_each_rcu() here even though we may
-        * delete 'pos', since list_del_rcu() doesn't clear ->next
-        */
-       list_for_each_entry_rcu(data, &call_function.queue, csd.list) {
-               int refs;
-               smp_call_func_t func;
-
-               /*
-                * Since we walk the list without any locks, we might
-                * see an entry that was completed, removed from the
-                * list and is in the process of being reused.
-                *
-                * We must check that the cpu is in the cpumask before
-                * checking the refs, and both must be set before
-                * executing the callback on this cpu.
-                */
-
-               if (!cpumask_test_cpu(cpu, data->cpumask))
-                       continue;
-
-               smp_rmb();
-
-               if (atomic_read(&data->refs) == 0)
-                       continue;
-
-               func = data->csd.func;          /* save for later warn */
-               func(data->csd.info);
-
-               /*
-                * If the cpu mask is not still set then func enabled
-                * interrupts (BUG), and this cpu took another smp call
-                * function interrupt and executed func(info) twice
-                * on this cpu.  That nested execution decremented refs.
-                */
-               if (!cpumask_test_and_clear_cpu(cpu, data->cpumask)) {
-                       WARN(1, "%pf enabled interrupts and double executed\n", func);
-                       continue;
-               }
-
-               refs = atomic_dec_return(&data->refs);
-               WARN_ON(refs < 0);
-
-               if (refs)
-                       continue;
-
-               WARN_ON(!cpumask_empty(data->cpumask));
-
-               raw_spin_lock(&call_function.lock);
-               list_del_rcu(&data->csd.list);
-               raw_spin_unlock(&call_function.lock);
-
-               csd_unlock(&data->csd);
-       }
-
-}
-
-/*
  * Invoked by arch to handle an IPI for call function single. Must be
  * called from the arch with interrupts disabled.
  */
@@ -453,8 +370,7 @@ void smp_call_function_many(const struct cpumask *mask,
                            smp_call_func_t func, void *info, bool wait)
 {
        struct call_function_data *data;
-       unsigned long flags;
-       int refs, cpu, next_cpu, this_cpu = smp_processor_id();
+       int cpu, next_cpu, this_cpu = smp_processor_id();
 
        /*
         * Can deadlock when called with interrupts disabled.
@@ -486,50 +402,13 @@ void smp_call_function_many(const struct cpumask *mask,
        }
 
        data = &__get_cpu_var(cfd_data);
-       csd_lock(&data->csd);
-
-       /* This BUG_ON verifies our reuse assertions and can be removed */
-       BUG_ON(atomic_read(&data->refs) || !cpumask_empty(data->cpumask));
-
-       /*
-        * The global call function queue list add and delete are protected
-        * by a lock, but the list is traversed without any lock, relying
-        * on the rcu list add and delete to allow safe concurrent traversal.
-        * We reuse the call function data without waiting for any grace
-        * period after some other cpu removes it from the global queue.
-        * This means a cpu might find our data block as it is being
-        * filled out.
-        *
-        * We hold off the interrupt handler on the other cpu by
-        * ordering our writes to the cpu mask vs our setting of the
-        * refs counter.  We assert only the cpu owning the data block
-        * will set a bit in cpumask, and each bit will only be cleared
-        * by the subject cpu.  Each cpu must first find its bit is
-        * set and then check that refs is set indicating the element is
-        * ready to be processed, otherwise it must skip the entry.
-        *
-        * On the previous iteration refs was set to 0 by another cpu.
-        * To avoid the use of transitivity, set the counter to 0 here
-        * so the wmb will pair with the rmb in the interrupt handler.
-        */
-       atomic_set(&data->refs, 0);     /* convert 3rd to 1st party write */
-
-       data->csd.func = func;
-       data->csd.info = info;
 
-       /* Ensure 0 refs is visible before mask.  Also orders func and info */
-       smp_wmb();
-
-       /* We rely on the "and" being processed before the store */
        cpumask_and(data->cpumask, mask, cpu_online_mask);
        cpumask_clear_cpu(this_cpu, data->cpumask);
-       refs = cpumask_weight(data->cpumask);
 
        /* Some callers race with other cpus changing the passed mask */
-       if (unlikely(!refs)) {
-               csd_unlock(&data->csd);
+       if (unlikely(!cpumask_weight(data->cpumask)))
                return;
-       }
 
        /*
         * After we put an entry into the list, data->cpumask
@@ -537,34 +416,32 @@ void smp_call_function_many(const struct cpumask *mask,
         * a SMP function call, so data->cpumask will be zero.
         */
        cpumask_copy(data->cpumask_ipi, data->cpumask);
-       raw_spin_lock_irqsave(&call_function.lock, flags);
-       /*
-        * Place entry at the _HEAD_ of the list, so that any cpu still
-        * observing the entry in generic_smp_call_function_interrupt()
-        * will not miss any other list entries:
-        */
-       list_add_rcu(&data->csd.list, &call_function.queue);
-       /*
-        * We rely on the wmb() in list_add_rcu to complete our writes
-        * to the cpumask before this write to refs, which indicates
-        * data is on the list and is ready to be processed.
-        */
-       atomic_set(&data->refs, refs);
-       raw_spin_unlock_irqrestore(&call_function.lock, flags);
 
-       /*
-        * Make the list addition visible before sending the ipi.
-        * (IPIs must obey or appear to obey normal Linux cache
-        * coherency rules -- see comment in generic_exec_single).
-        */
-       smp_mb();
+       for_each_cpu(cpu, data->cpumask) {
+               struct call_single_data *csd = per_cpu_ptr(data->csd, cpu);
+               struct call_single_queue *dst =
+                                       &per_cpu(call_single_queue, cpu);
+               unsigned long flags;
+
+               csd_lock(csd);
+               csd->func = func;
+               csd->info = info;
+
+               raw_spin_lock_irqsave(&dst->lock, flags);
+               list_add_tail(&csd->list, &dst->list);
+               raw_spin_unlock_irqrestore(&dst->lock, flags);
+       }
 
        /* Send a message to all CPUs in the map */
        arch_send_call_function_ipi_mask(data->cpumask_ipi);
 
-       /* Optionally wait for the CPUs to complete */
-       if (wait)
-               csd_lock_wait(&data->csd);
+       if (wait) {
+               for_each_cpu(cpu, data->cpumask) {
+                       struct call_single_data *csd =
+                                       per_cpu_ptr(data->csd, cpu);
+                       csd_lock_wait(csd);
+               }
+       }
 }
 EXPORT_SYMBOL(smp_call_function_many);
 
index 265b376..840cfda 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/syscalls.h>
 #include <linux/kprobes.h>
 #include <linux/user_namespace.h>
+#include <linux/binfmts.h>
 
 #include <linux/kmsg_dump.h>
 /* Move somewhere else to avoid recompiling? */
@@ -2012,160 +2013,159 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 
        error = 0;
        switch (option) {
-               case PR_SET_PDEATHSIG:
-                       if (!valid_signal(arg2)) {
-                               error = -EINVAL;
-                               break;
-                       }
-                       me->pdeath_signal = arg2;
-                       break;
-               case PR_GET_PDEATHSIG:
-                       error = put_user(me->pdeath_signal, (int __user *)arg2);
-                       break;
-               case PR_GET_DUMPABLE:
-                       error = get_dumpable(me->mm);
+       case PR_SET_PDEATHSIG:
+               if (!valid_signal(arg2)) {
+                       error = -EINVAL;
                        break;
-               case PR_SET_DUMPABLE:
-                       if (arg2 < 0 || arg2 > 1) {
-                               error = -EINVAL;
-                               break;
-                       }
-                       set_dumpable(me->mm, arg2);
+               }
+               me->pdeath_signal = arg2;
+               break;
+       case PR_GET_PDEATHSIG:
+               error = put_user(me->pdeath_signal, (int __user *)arg2);
+               break;
+       case PR_GET_DUMPABLE:
+               error = get_dumpable(me->mm);
+               break;
+       case PR_SET_DUMPABLE:
+               if (arg2 != SUID_DUMP_DISABLE && arg2 != SUID_DUMP_USER) {
+                       error = -EINVAL;
                        break;
+               }
+               set_dumpable(me->mm, arg2);
+               break;
 
-               case PR_SET_UNALIGN:
-                       error = SET_UNALIGN_CTL(me, arg2);
-                       break;
-               case PR_GET_UNALIGN:
-                       error = GET_UNALIGN_CTL(me, arg2);
-                       break;
-               case PR_SET_FPEMU:
-                       error = SET_FPEMU_CTL(me, arg2);
-                       break;
-               case PR_GET_FPEMU:
-                       error = GET_FPEMU_CTL(me, arg2);
-                       break;
-               case PR_SET_FPEXC:
-                       error = SET_FPEXC_CTL(me, arg2);
-                       break;
-               case PR_GET_FPEXC:
-                       error = GET_FPEXC_CTL(me, arg2);
-                       break;
-               case PR_GET_TIMING:
-                       error = PR_TIMING_STATISTICAL;
-                       break;
-               case PR_SET_TIMING:
-                       if (arg2 != PR_TIMING_STATISTICAL)
-                               error = -EINVAL;
-                       break;
-               case PR_SET_NAME:
-                       comm[sizeof(me->comm)-1] = 0;
-                       if (strncpy_from_user(comm, (char __user *)arg2,
-                                             sizeof(me->comm) - 1) < 0)
-                               return -EFAULT;
-                       set_task_comm(me, comm);
-                       proc_comm_connector(me);
-                       break;
-               case PR_GET_NAME:
-                       get_task_comm(comm, me);
-                       if (copy_to_user((char __user *)arg2, comm,
-                                        sizeof(comm)))
-                               return -EFAULT;
-                       break;
-               case PR_GET_ENDIAN:
-                       error = GET_ENDIAN(me, arg2);
-                       break;
-               case PR_SET_ENDIAN:
-                       error = SET_ENDIAN(me, arg2);
-                       break;
-               case PR_GET_SECCOMP:
-                       error = prctl_get_seccomp();
-                       break;
-               case PR_SET_SECCOMP:
-                       error = prctl_set_seccomp(arg2, (char __user *)arg3);
-                       break;
-               case PR_GET_TSC:
-                       error = GET_TSC_CTL(arg2);
-                       break;
-               case PR_SET_TSC:
-                       error = SET_TSC_CTL(arg2);
-                       break;
-               case PR_TASK_PERF_EVENTS_DISABLE:
-                       error = perf_event_task_disable();
-                       break;
-               case PR_TASK_PERF_EVENTS_ENABLE:
-                       error = perf_event_task_enable();
-                       break;
-               case PR_GET_TIMERSLACK:
-                       error = current->timer_slack_ns;
-                       break;
-               case PR_SET_TIMERSLACK:
-                       if (arg2 <= 0)
-                               current->timer_slack_ns =
+       case PR_SET_UNALIGN:
+               error = SET_UNALIGN_CTL(me, arg2);
+               break;
+       case PR_GET_UNALIGN:
+               error = GET_UNALIGN_CTL(me, arg2);
+               break;
+       case PR_SET_FPEMU:
+               error = SET_FPEMU_CTL(me, arg2);
+               break;
+       case PR_GET_FPEMU:
+               error = GET_FPEMU_CTL(me, arg2);
+               break;
+       case PR_SET_FPEXC:
+               error = SET_FPEXC_CTL(me, arg2);
+               break;
+       case PR_GET_FPEXC:
+               error = GET_FPEXC_CTL(me, arg2);
+               break;
+       case PR_GET_TIMING:
+               error = PR_TIMING_STATISTICAL;
+               break;
+       case PR_SET_TIMING:
+               if (arg2 != PR_TIMING_STATISTICAL)
+                       error = -EINVAL;
+               break;
+       case PR_SET_NAME:
+               comm[sizeof(me->comm) - 1] = 0;
+               if (strncpy_from_user(comm, (char __user *)arg2,
+                                     sizeof(me->comm) - 1) < 0)
+                       return -EFAULT;
+               set_task_comm(me, comm);
+               proc_comm_connector(me);
+               break;
+       case PR_GET_NAME:
+               get_task_comm(comm, me);
+               if (copy_to_user((char __user *)arg2, comm, sizeof(comm)))
+                       return -EFAULT;
+               break;
+       case PR_GET_ENDIAN:
+               error = GET_ENDIAN(me, arg2);
+               break;
+       case PR_SET_ENDIAN:
+               error = SET_ENDIAN(me, arg2);
+               break;
+       case PR_GET_SECCOMP:
+               error = prctl_get_seccomp();
+               break;
+       case PR_SET_SECCOMP:
+               error = prctl_set_seccomp(arg2, (char __user *)arg3);
+               break;
+       case PR_GET_TSC:
+               error = GET_TSC_CTL(arg2);
+               break;
+       case PR_SET_TSC:
+               error = SET_TSC_CTL(arg2);
+               break;
+       case PR_TASK_PERF_EVENTS_DISABLE:
+               error = perf_event_task_disable();
+               break;
+       case PR_TASK_PERF_EVENTS_ENABLE:
+               error = perf_event_task_enable();
+               break;
+       case PR_GET_TIMERSLACK:
+               error = current->timer_slack_ns;
+               break;
+       case PR_SET_TIMERSLACK:
+               if (arg2 <= 0)
+                       current->timer_slack_ns =
                                        current->default_timer_slack_ns;
-                       else
-                               current->timer_slack_ns = arg2;
-                       break;
-               case PR_MCE_KILL:
-                       if (arg4 | arg5)
-                               return -EINVAL;
-                       switch (arg2) {
-                       case PR_MCE_KILL_CLEAR:
-                               if (arg3 != 0)
-                                       return -EINVAL;
-                               current->flags &= ~PF_MCE_PROCESS;
-                               break;
-                       case PR_MCE_KILL_SET:
-                               current->flags |= PF_MCE_PROCESS;
-                               if (arg3 == PR_MCE_KILL_EARLY)
-                                       current->flags |= PF_MCE_EARLY;
-                               else if (arg3 == PR_MCE_KILL_LATE)
-                                       current->flags &= ~PF_MCE_EARLY;
-                               else if (arg3 == PR_MCE_KILL_DEFAULT)
-                                       current->flags &=
-                                               ~(PF_MCE_EARLY|PF_MCE_PROCESS);
-                               else
-                                       return -EINVAL;
-                               break;
-                       default:
+               else
+                       current->timer_slack_ns = arg2;
+               break;
+       case PR_MCE_KILL:
+               if (arg4 | arg5)
+                       return -EINVAL;
+               switch (arg2) {
+               case PR_MCE_KILL_CLEAR:
+                       if (arg3 != 0)
                                return -EINVAL;
-                       }
+                       current->flags &= ~PF_MCE_PROCESS;
                        break;
-               case PR_MCE_KILL_GET:
-                       if (arg2 | arg3 | arg4 | arg5)
-                               return -EINVAL;
-                       if (current->flags & PF_MCE_PROCESS)
-                               error = (current->flags & PF_MCE_EARLY) ?
-                                       PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;
+               case PR_MCE_KILL_SET:
+                       current->flags |= PF_MCE_PROCESS;
+                       if (arg3 == PR_MCE_KILL_EARLY)
+                               current->flags |= PF_MCE_EARLY;
+                       else if (arg3 == PR_MCE_KILL_LATE)
+                               current->flags &= ~PF_MCE_EARLY;
+                       else if (arg3 == PR_MCE_KILL_DEFAULT)
+                               current->flags &=
+                                               ~(PF_MCE_EARLY|PF_MCE_PROCESS);
                        else
-                               error = PR_MCE_KILL_DEFAULT;
-                       break;
-               case PR_SET_MM:
-                       error = prctl_set_mm(arg2, arg3, arg4, arg5);
-                       break;
-               case PR_GET_TID_ADDRESS:
-                       error = prctl_get_tid_address(me, (int __user **)arg2);
-                       break;
-               case PR_SET_CHILD_SUBREAPER:
-                       me->signal->is_child_subreaper = !!arg2;
-                       break;
-               case PR_GET_CHILD_SUBREAPER:
-                       error = put_user(me->signal->is_child_subreaper,
-                                        (int __user *) arg2);
-                       break;
-               case PR_SET_NO_NEW_PRIVS:
-                       if (arg2 != 1 || arg3 || arg4 || arg5)
                                return -EINVAL;
-
-                       current->no_new_privs = 1;
                        break;
-               case PR_GET_NO_NEW_PRIVS:
-                       if (arg2 || arg3 || arg4 || arg5)
-                               return -EINVAL;
-                       return current->no_new_privs ? 1 : 0;
                default:
-                       error = -EINVAL;
-                       break;
+                       return -EINVAL;
+               }
+               break;
+       case PR_MCE_KILL_GET:
+               if (arg2 | arg3 | arg4 | arg5)
+                       return -EINVAL;
+               if (current->flags & PF_MCE_PROCESS)
+                       error = (current->flags & PF_MCE_EARLY) ?
+                               PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;
+               else
+                       error = PR_MCE_KILL_DEFAULT;
+               break;
+       case PR_SET_MM:
+               error = prctl_set_mm(arg2, arg3, arg4, arg5);
+               break;
+       case PR_GET_TID_ADDRESS:
+               error = prctl_get_tid_address(me, (int __user **)arg2);
+               break;
+       case PR_SET_CHILD_SUBREAPER:
+               me->signal->is_child_subreaper = !!arg2;
+               break;
+       case PR_GET_CHILD_SUBREAPER:
+               error = put_user(me->signal->is_child_subreaper,
+                                (int __user *)arg2);
+               break;
+       case PR_SET_NO_NEW_PRIVS:
+               if (arg2 != 1 || arg3 || arg4 || arg5)
+                       return -EINVAL;
+
+               current->no_new_privs = 1;
+               break;
+       case PR_GET_NO_NEW_PRIVS:
+               if (arg2 || arg3 || arg4 || arg5)
+                       return -EINVAL;
+               return current->no_new_privs ? 1 : 0;
+       default:
+               error = -EINVAL;
+               break;
        }
        return error;
 }
index c2a27dd..f8342a4 100644 (file)
@@ -240,7 +240,7 @@ EXPORT_SYMBOL(current_fs_time);
  * Avoid unnecessary multiplications/divisions in the
  * two most common HZ cases:
  */
-inline unsigned int jiffies_to_msecs(const unsigned long j)
+unsigned int jiffies_to_msecs(const unsigned long j)
 {
 #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
        return (MSEC_PER_SEC / HZ) * j;
@@ -256,7 +256,7 @@ inline unsigned int jiffies_to_msecs(const unsigned long j)
 }
 EXPORT_SYMBOL(jiffies_to_msecs);
 
-inline unsigned int jiffies_to_usecs(const unsigned long j)
+unsigned int jiffies_to_usecs(const unsigned long j)
 {
 #if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
        return (USEC_PER_SEC / HZ) * j;
index bb8d9b1..e4a7f80 100644 (file)
@@ -243,8 +243,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
        default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
 
 config PANIC_ON_OOPS
-       bool "Panic on Oops" if EXPERT
-       default n
+       bool "Panic on Oops"
        help
          Say Y here to enable the kernel to panic when it oopses. This
          has the same effect as setting oops=panic on the kernel command
index 52cfa69..807b2aa 100644 (file)
@@ -157,7 +157,7 @@ static int match_number(substring_t *s, int *result, int base)
  *
  * Description: Attempts to parse the &substring_t @s as a decimal integer. On
  * success, sets @result to the integer represented by the string and returns 0.
- * Returns either -ENOMEM or -EINVAL on failure.
+ * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
  */
 int match_int(substring_t *s, int *result)
 {
@@ -171,7 +171,7 @@ int match_int(substring_t *s, int *result)
  *
  * Description: Attempts to parse the &substring_t @s as an octal integer. On
  * success, sets @result to the integer represented by the string and returns
- * 0. Returns either -ENOMEM or -EINVAL on failure.
+ * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
  */
 int match_octal(substring_t *s, int *result)
 {
@@ -185,7 +185,7 @@ int match_octal(substring_t *s, int *result)
  *
  * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
  * On success, sets @result to the integer represented by the string and
- * returns 0. Returns either -ENOMEM or -EINVAL on failure.
+ * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
  */
 int match_hex(substring_t *s, int *result)
 {
index fab33a9..0d62fd7 100644 (file)
@@ -1030,6 +1030,7 @@ int kptr_restrict __read_mostly;
  *              N no separator
  *            The maximum supported length is 64 bytes of the input. Consider
  *            to use print_hex_dump() for the larger input.
+ * - 'a' For a phys_addr_t type and its derivative types (passed by reference)
  *
  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
  * function pointers are really function descriptors, which contain a
@@ -1120,6 +1121,12 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                        return netdev_feature_string(buf, end, ptr, spec);
                }
                break;
+       case 'a':
+               spec.flags |= SPECIAL | SMALL | ZEROPAD;
+               spec.field_width = sizeof(phys_addr_t) * 2 + 2;
+               spec.base = 16;
+               return number(buf, end,
+                             (unsigned long long) *((phys_addr_t *)ptr), spec);
        }
        spec.flags |= SMALL;
        if (spec.field_width == -1) {
index 60a6088..82a04d7 100644 (file)
@@ -6,42 +6,40 @@ config XZ_DEC
          the .xz file format as the container. For integrity checking,
          CRC32 is supported. See Documentation/xz.txt for more information.
 
+if XZ_DEC
+
 config XZ_DEC_X86
-       bool "x86 BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "x86 BCJ filter decoder"
+       default y if X86
        select XZ_DEC_BCJ
 
 config XZ_DEC_POWERPC
-       bool "PowerPC BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "PowerPC BCJ filter decoder"
+       default y if POWERPC
        select XZ_DEC_BCJ
 
 config XZ_DEC_IA64
-       bool "IA-64 BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "IA-64 BCJ filter decoder"
+       default y if IA64
        select XZ_DEC_BCJ
 
 config XZ_DEC_ARM
-       bool "ARM BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "ARM BCJ filter decoder"
+       default y if ARM
        select XZ_DEC_BCJ
 
 config XZ_DEC_ARMTHUMB
-       bool "ARM-Thumb BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "ARM-Thumb BCJ filter decoder"
+       default y if (ARM && ARM_THUMB)
        select XZ_DEC_BCJ
 
 config XZ_DEC_SPARC
-       bool "SPARC BCJ filter decoder" if EXPERT
-       default y
-       depends on XZ_DEC
+       bool "SPARC BCJ filter decoder"
+       default y if SPARC
        select XZ_DEC_BCJ
 
+endif
+
 config XZ_DEC_BCJ
        bool
        default n
index 308fdca..0b23db9 100644 (file)
@@ -258,6 +258,19 @@ config BOUNCE
        def_bool y
        depends on BLOCK && MMU && (ZONE_DMA || HIGHMEM)
 
+# On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often
+# have more than 4GB of memory, but we don't currently use the IOTLB to present
+# a 32-bit address to OHCI.  So we need to use a bounce pool instead.
+#
+# We also use the bounce pool to provide stable page writes for jbd.  jbd
+# initiates buffer writeback without locking the page or setting PG_writeback,
+# and fixing that behavior (a second time; jbd2 doesn't have this problem) is
+# a major rework effort.  Instead, use the bounce buffer to snapshot pages
+# (until jbd goes away).  The only jbd user is ext3.
+config NEED_BOUNCE_POOL
+       bool
+       default y if (TILE && USB_OHCI_HCD) || (BLK_DEV_INTEGRITY && JBD)
+
 config NR_QUICK
        int
        depends on QUICKLIST
index d3ca2b3..41733c5 100644 (file)
@@ -221,12 +221,23 @@ static ssize_t max_ratio_store(struct device *dev,
 }
 BDI_SHOW(max_ratio, bdi->max_ratio)
 
+static ssize_t stable_pages_required_show(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *page)
+{
+       struct backing_dev_info *bdi = dev_get_drvdata(dev);
+
+       return snprintf(page, PAGE_SIZE-1, "%d\n",
+                       bdi_cap_stable_pages_required(bdi) ? 1 : 0);
+}
+
 #define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
 
 static struct device_attribute bdi_dev_attrs[] = {
        __ATTR_RW(read_ahead_kb),
        __ATTR_RW(min_ratio),
        __ATTR_RW(max_ratio),
+       __ATTR_RO(stable_pages_required),
        __ATTR_NULL,
 };
 
index 0420867..5f89017 100644 (file)
@@ -178,8 +178,45 @@ static void bounce_end_io_read_isa(struct bio *bio, int err)
        __bounce_end_io_read(bio, isa_page_pool, err);
 }
 
+#ifdef CONFIG_NEED_BOUNCE_POOL
+static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio)
+{
+       struct page *page;
+       struct backing_dev_info *bdi;
+       struct address_space *mapping;
+       struct bio_vec *from;
+       int i;
+
+       if (bio_data_dir(bio) != WRITE)
+               return 0;
+
+       if (!bdi_cap_stable_pages_required(&q->backing_dev_info))
+               return 0;
+
+       /*
+        * Based on the first page that has a valid mapping, decide whether or
+        * not we have to employ bounce buffering to guarantee stable pages.
+        */
+       bio_for_each_segment(from, bio, i) {
+               page = from->bv_page;
+               mapping = page_mapping(page);
+               if (!mapping)
+                       continue;
+               bdi = mapping->backing_dev_info;
+               return mapping->host->i_sb->s_flags & MS_SNAP_STABLE;
+       }
+
+       return 0;
+}
+#else
+static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio)
+{
+       return 0;
+}
+#endif /* CONFIG_NEED_BOUNCE_POOL */
+
 static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
-                              mempool_t *pool)
+                              mempool_t *pool, int force)
 {
        struct page *page;
        struct bio *bio = NULL;
@@ -192,7 +229,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
                /*
                 * is destination page below bounce pfn?
                 */
-               if (page_to_pfn(page) <= queue_bounce_pfn(q))
+               if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force)
                        continue;
 
                /*
@@ -270,6 +307,7 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
 
 void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig)
 {
+       int must_bounce;
        mempool_t *pool;
 
        /*
@@ -278,13 +316,15 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig)
        if (!bio_has_data(*bio_orig))
                return;
 
+       must_bounce = must_snapshot_stable_pages(q, *bio_orig);
+
        /*
         * for non-isa bounce case, just check if the bounce pfn is equal
         * to or bigger than the highest pfn in the system -- in that case,
         * don't waste time iterating over bio segments
         */
        if (!(q->bounce_gfp & GFP_DMA)) {
-               if (queue_bounce_pfn(q) >= blk_max_pfn)
+               if (queue_bounce_pfn(q) >= blk_max_pfn && !must_bounce)
                        return;
                pool = page_pool;
        } else {
@@ -295,7 +335,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig)
        /*
         * slow path
         */
-       __blk_queue_bounce(q, bio_orig, pool);
+       __blk_queue_bounce(q, bio_orig, pool, must_bounce);
 }
 
 EXPORT_SYMBOL(blk_queue_bounce);
index 24a7ea5..c610076 100644 (file)
@@ -1728,6 +1728,7 @@ int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
         * see the dirty page and writeprotect it again.
         */
        set_page_dirty(page);
+       wait_for_stable_page(page);
 out:
        sb_end_pagefault(inode->i_sb);
        return ret;
@@ -2274,7 +2275,7 @@ repeat:
                return NULL;
        }
 found:
-       wait_on_page_writeback(page);
+       wait_for_stable_page(page);
        return page;
 }
 EXPORT_SYMBOL(grab_cache_page_write_begin);
index 66a0024..7300c9d 100644 (file)
@@ -2290,3 +2290,27 @@ int mapping_tagged(struct address_space *mapping, int tag)
        return radix_tree_tagged(&mapping->page_tree, tag);
 }
 EXPORT_SYMBOL(mapping_tagged);
+
+/**
+ * wait_for_stable_page() - wait for writeback to finish, if necessary.
+ * @page:      The page to wait on.
+ *
+ * This function determines if the given page is related to a backing device
+ * that requires page contents to be held stable during writeback.  If so, then
+ * it will wait for any pending writeback to complete.
+ */
+void wait_for_stable_page(struct page *page)
+{
+       struct address_space *mapping = page_mapping(page);
+       struct backing_dev_info *bdi = mapping->backing_dev_info;
+
+       if (!bdi_cap_stable_pages_required(bdi))
+               return;
+#ifdef CONFIG_NEED_BOUNCE_POOL
+       if (mapping->host->i_sb->s_flags & MS_SNAP_STABLE)
+               return;
+#endif /* CONFIG_NEED_BOUNCE_POOL */
+
+       wait_on_page_writeback(page);
+}
+EXPORT_SYMBOL_GPL(wait_for_stable_page);
index 3f2eb57..ed0b9e2 100644 (file)
@@ -11,7 +11,7 @@ menuconfig IPV6
          You will still be able to do traditional IPv4 networking as well.
 
          For general information about IPv6, see
-         <http://playground.sun.com/pub/ipng/html/ipng-main.html>.
+         <https://en.wikipedia.org/wiki/IPv6>.
          For Linux IPv6 development information, see <http://www.linux-ipv6.org>.
          For specific information about IPv6 under Linux, read the HOWTO at
          <http://www.bieringer.de/linux/IPv6/>.
index 2bb08a9..747bcd7 100755 (executable)
@@ -1931,6 +1931,12 @@ sub process {
                              "use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
                }
 
+# check for old HOTPLUG __dev<foo> section markings
+               if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) {
+                       WARN("HOTPLUG_SECTION",
+                            "Using $1 is unnecessary\n" . $herecurr);
+               }
+
 # Check for potential 'bare' types
                my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
                    $realline_next);
@@ -2430,6 +2436,15 @@ sub process {
                             "Prefer pr_warn(... to pr_warning(...\n" . $herecurr);
                }
 
+               if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) {
+                       my $orig = $1;
+                       my $level = lc($orig);
+                       $level = "warn" if ($level eq "warning");
+                       $level = "dbg" if ($level eq "debug");
+                       WARN("PREFER_DEV_LEVEL",
+                            "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr);
+               }
+
 # function brace can't be on same line, except for #defines of do while,
 # or if closed on same line
                if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
@@ -2915,6 +2930,7 @@ sub process {
                        my $var = $1;
                        if ($var !~ /$Constant/ &&
                            $var =~ /[A-Z]\w*[a-z]|[a-z]\w*[A-Z]/ &&
+                           $var !~ /^Page[A-Z]/ &&
                            !defined $camelcase{$var}) {
                                $camelcase{$var} = 1;
                                WARN("CAMELCASE",
@@ -3237,9 +3253,9 @@ sub process {
                }
 
 # prefer usleep_range over udelay
-               if ($line =~ /\budelay\s*\(\s*(\w+)\s*\)/) {
+               if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
                        # ignore udelay's < 10, however
-                       if (! (($1 =~ /(\d+)/) && ($1 < 10)) ) {
+                       if (! ($1 < 10) ) {
                                CHK("USLEEP_RANGE",
                                    "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
                        }
@@ -3460,6 +3476,12 @@ sub process {
                             "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
                }
 
+# check for alloc argument mismatch
+               if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
+                       WARN("ALLOC_ARRAY_ARGS",
+                            "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
+               }
+
 # check for multiple semicolons
                if ($line =~ /;\s*;\s*$/) {
                        WARN("ONE_SEMICOLON",
index 8b673dd..18d4ab5 100755 (executable)
@@ -433,7 +433,7 @@ foreach my $file (@ARGV) {
 
        while (<$patch>) {
            my $patch_line = $_;
-           if (m/^\+\+\+\s+(\S+)/) {
+           if (m/^\+\+\+\s+(\S+)/ or m/^---\s+(\S+)/) {
                my $filename = $1;
                $filename =~ s@^[^/]*/@@;
                $filename =~ s@\n@@;
index 08f06c0..65f9595 100755 (executable)
@@ -149,12 +149,17 @@ dogtags()
 exuberant()
 {
        all_target_sources | xargs $1 -a                        \
-       -I __initdata,__exitdata,__acquires,__releases          \
-       -I __read_mostly,____cacheline_aligned                  \
+       -I __initdata,__exitdata,__initconst,__devinitdata      \
+       -I __devinitconst,__cpuinitdata,__initdata_memblock     \
+       -I __refdata,__attribute                                \
+       -I __acquires,__releases,__deprecated                   \
+       -I __read_mostly,__aligned,____cacheline_aligned        \
        -I ____cacheline_aligned_in_smp                         \
        -I ____cacheline_internodealigned_in_smp                \
+       -I __used,__packed,__packed2__,__must_check,__must_hold \
        -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL                      \
        -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \
+       -I static,const                                         \
        --extra=+f --c-kinds=+px                                \
        --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/'        \
        --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \
@@ -182,8 +187,19 @@ exuberant()
        --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \
        --regex-c++='/__TESTCLEARFLAG_FALSE\(([^,)]*).*/__TestClearPage\1/' \
        --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'                \
-       --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \
-       --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/'
+       --regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \
+       --regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \
+       --regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/'     \
+       --regex-c='/DEFINE_(RAW_SPINLOCK|RWLOCK|SEQLOCK)\((\w*)/\2/v/'  \
+       --regex-c='/DECLARE_(RWSEM|COMPLETION)\((\w*)/\2/v/'            \
+       --regex-c='/DECLARE_BITMAP\((\w*)/\1/v/'                        \
+       --regex-c='/(^|\s)(|L|H)LIST_HEAD\((\w*)/\3/v/'                 \
+       --regex-c='/(^|\s)RADIX_TREE\((\w*)/\2/v/'                      \
+       --regex-c='/DEFINE_PER_CPU\(([^,]*,\s*)(\w*).*\)/\2/v/'         \
+       --regex-c='/DEFINE_PER_CPU_SHARED_ALIGNED\(([^,]*,\s*)(\w*).*\)/\2/v/' \
+       --regex-c='/DECLARE_WAIT_QUEUE_HEAD\((\w*)/\1/v/'               \
+       --regex-c='/DECLARE_(TASKLET|WORK|DELAYED_WORK)\((\w*)/\2/v/'   \
+       --regex-c='/DEFINE_PCI_DEVICE_TABLE\((\w*)/\1/v/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
index d794abc..1c69e38 100644 (file)
@@ -159,6 +159,16 @@ static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
        }
 }
 
+static void __dev_exception_clean(struct dev_cgroup *dev_cgroup)
+{
+       struct dev_exception_item *ex, *tmp;
+
+       list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
+               list_del_rcu(&ex->list);
+               kfree_rcu(ex, rcu);
+       }
+}
+
 /**
  * dev_exception_clean - frees all entries of the exception list
  * @dev_cgroup: dev_cgroup with the exception list to be cleaned
@@ -167,14 +177,9 @@ static void dev_exception_rm(struct dev_cgroup *dev_cgroup,
  */
 static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
 {
-       struct dev_exception_item *ex, *tmp;
-
        lockdep_assert_held(&devcgroup_mutex);
 
-       list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
-               list_del_rcu(&ex->list);
-               kfree_rcu(ex, rcu);
-       }
+       __dev_exception_clean(dev_cgroup);
 }
 
 /*
@@ -215,9 +220,7 @@ static void devcgroup_css_free(struct cgroup *cgroup)
        struct dev_cgroup *dev_cgroup;
 
        dev_cgroup = cgroup_to_devcgroup(cgroup);
-       mutex_lock(&devcgroup_mutex);
-       dev_exception_clean(dev_cgroup);
-       mutex_unlock(&devcgroup_mutex);
+       __dev_exception_clean(dev_cgroup);
        kfree(dev_cgroup);
 }