浏览代码

Merge branch 'akpm' (incoming from Andrew)

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()
  ...
Linus Torvalds 12 年之前
父节点
当前提交
7c2db36e73
共有 100 个文件被更改,包括 5749 次插入741 次删除
  1. 5 0
      Documentation/ABI/testing/sysfs-class-bdi
  2. 2 2
      Documentation/backlight/lp855x-driver.txt
  3. 1 1
      Documentation/devicetree/booting-without-of.txt
  4. 11 3
      Documentation/printk-formats.txt
  5. 6 1
      MAINTAINERS
  6. 9 11
      arch/alpha/kernel/osf_sys.c
  7. 6 0
      arch/arm/boot/dts/armada-370-xp.dtsi
  8. 8 0
      arch/arm/configs/pxa910_defconfig
  9. 4 1
      arch/arm/mach-mmp/include/mach/pxa910.h
  10. 3 0
      arch/arm/mach-mmp/pxa910.c
  11. 92 0
      arch/arm/mach-mmp/ttc_dkb.c
  12. 0 5
      arch/cris/include/uapi/asm/posix_types.h
  13. 1 1
      arch/mn10300/unit-asb2305/pci-irq.c
  14. 0 6
      arch/tile/Kconfig
  15. 5 3
      block/blk-core.c
  16. 4 0
      block/blk-integrity.c
  17. 2 2
      drivers/net/ethernet/sun/Kconfig
  18. 30 7
      drivers/pcmcia/cs.c
  19. 42 0
      drivers/rtc/Kconfig
  20. 5 0
      drivers/rtc/Makefile
  21. 3 1
      drivers/rtc/class.c
  22. 8 9
      drivers/rtc/rtc-at91rm9200.c
  23. 5 10
      drivers/rtc/rtc-cmos.c
  24. 2 5
      drivers/rtc/rtc-coh901331.c
  25. 6 12
      drivers/rtc/rtc-da9052.c
  26. 10 18
      drivers/rtc/rtc-davinci.c
  27. 6 5
      drivers/rtc/rtc-dev.c
  28. 2 6
      drivers/rtc/rtc-ds1305.c
  29. 2 9
      drivers/rtc/rtc-ds1307.c
  30. 3 15
      drivers/rtc/rtc-ds2404.c
  31. 6 4
      drivers/rtc/rtc-efi.c
  32. 4 29
      drivers/rtc/rtc-fm3130.c
  33. 1 3
      drivers/rtc/rtc-imxdi.c
  34. 1 1
      drivers/rtc/rtc-isl12022.c
  35. 338 0
      drivers/rtc/rtc-lp8788.c
  36. 641 0
      drivers/rtc/rtc-max77686.c
  37. 3 3
      drivers/rtc/rtc-max8907.c
  38. 552 0
      drivers/rtc/rtc-max8997.c
  39. 4 1
      drivers/rtc/rtc-mpc5121.c
  40. 31 0
      drivers/rtc/rtc-pcf8523.c
  41. 1 1
      drivers/rtc/rtc-pcf8563.c
  42. 2 2
      drivers/rtc/rtc-pcf8583.c
  43. 2 0
      drivers/rtc/rtc-pl031.c
  44. 15 8
      drivers/rtc/rtc-pxa.c
  45. 3 2
      drivers/rtc/rtc-rs5c313.c
  46. 4 6
      drivers/rtc/rtc-rs5c372.c
  47. 314 0
      drivers/rtc/rtc-rx4581.c
  48. 9 9
      drivers/rtc/rtc-s3c.c
  49. 9 6
      drivers/rtc/rtc-sa1100.c
  50. 1 1
      drivers/rtc/rtc-snvs.c
  51. 2 1
      drivers/rtc/rtc-stmp3xxx.c
  52. 6 4
      drivers/rtc/rtc-sun4v.c
  53. 2 2
      drivers/rtc/rtc-tps6586x.c
  54. 16 28
      drivers/rtc/rtc-tps65910.c
  55. 349 0
      drivers/rtc/rtc-tps80031.c
  56. 5 1
      drivers/rtc/rtc-twl.c
  57. 1 1
      drivers/rtc/rtc-vr41xx.c
  58. 10 18
      drivers/rtc/rtc-vt8500.c
  59. 4 5
      drivers/rtc/rtc-wm831x.c
  60. 13 2
      drivers/video/Kconfig
  61. 2 0
      drivers/video/Makefile
  62. 4 1
      drivers/video/backlight/88pm860x_bl.c
  63. 23 1
      drivers/video/backlight/Kconfig
  64. 46 43
      drivers/video/backlight/Makefile
  65. 1 1
      drivers/video/backlight/aat2870_bl.c
  66. 1 1
      drivers/video/backlight/adp8860_bl.c
  67. 1 1
      drivers/video/backlight/adp8870_bl.c
  68. 31 73
      drivers/video/backlight/ams369fg06.c
  69. 380 0
      drivers/video/backlight/as3711_bl.c
  70. 9 9
      drivers/video/backlight/corgi_lcd.c
  71. 497 0
      drivers/video/backlight/hx8357.c
  72. 11 25
      drivers/video/backlight/l4f00242t03.c
  73. 39 70
      drivers/video/backlight/ld9040.c
  74. 2 2
      drivers/video/backlight/lm3630_bl.c
  75. 1 4
      drivers/video/backlight/lm3639_bl.c
  76. 2 2
      drivers/video/backlight/lms283gf05.c
  77. 441 0
      drivers/video/backlight/lms501kf03.c
  78. 130 39
      drivers/video/backlight/lp855x_bl.c
  79. 5 5
      drivers/video/backlight/ltv350qv.c
  80. 5 5
      drivers/video/backlight/omap1_bl.c
  81. 4 4
      drivers/video/backlight/pwm_bl.c
  82. 57 96
      drivers/video/backlight/s6e63m0.c
  83. 5 5
      drivers/video/backlight/tdo24m.c
  84. 1 1
      drivers/video/backlight/tosa_bl.c
  85. 6 6
      drivers/video/backlight/tosa_lcd.c
  86. 4 5
      drivers/video/backlight/vgg2432a4.c
  87. 9 1
      drivers/video/console/fbcon.c
  88. 15 8
      drivers/video/exynos/exynos_dp_core.c
  89. 18 52
      drivers/video/exynos/exynos_mipi_dsi.c
  90. 4 10
      drivers/video/exynos/s6e8ax0.c
  91. 318 0
      drivers/video/goldfishfb.c
  92. 11 0
      drivers/video/mmp/Kconfig
  93. 1 0
      drivers/video/mmp/Makefile
  94. 258 0
      drivers/video/mmp/core.c
  95. 13 0
      drivers/video/mmp/fb/Kconfig
  96. 1 0
      drivers/video/mmp/fb/Makefile
  97. 685 0
      drivers/video/mmp/fb/mmpfb.c
  98. 54 0
      drivers/video/mmp/fb/mmpfb.h
  99. 20 0
      drivers/video/mmp/hw/Kconfig
  100. 2 0
      drivers/video/mmp/hw/Makefile

+ 5 - 0
Documentation/ABI/testing/sysfs-class-bdi

@@ -48,3 +48,8 @@ max_ratio (read-write)
 	most of the write-back cache.  For example in case of an NFS
 	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
 	mount that is prone to get stuck, or a FUSE mount which cannot
 	be trusted to play fair.
 	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.

+ 2 - 2
Documentation/backlight/lp855x-driver.txt

@@ -4,7 +4,7 @@ Kernel driver lp855x
 Backlight driver for LP855x ICs
 Backlight driver for LP855x ICs
 
 
 Supported chips:
 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>
 Author: Milo(Woogyom) Kim <milo.kim@ti.com>
 
 
@@ -24,7 +24,7 @@ Value : pwm based or register based
 
 
 2) chip_id
 2) chip_id
 The lp855x chip id.
 The lp855x chip id.
-Value : lp8550/lp8551/lp8552/lp8553/lp8556
+Value : lp8550/lp8551/lp8552/lp8553/lp8556/lp8557
 
 
 Platform data for lp855x
 Platform data for lp855x
 ------------------------
 ------------------------

+ 1 - 1
Documentation/devicetree/booting-without-of.txt

@@ -1228,7 +1228,7 @@ hierarchy and routing of interrupts in the hardware.
 The interrupt tree model is fully described in the
 The interrupt tree model is fully described in the
 document "Open Firmware Recommended Practice: Interrupt
 document "Open Firmware Recommended Practice: Interrupt
 Mapping Version 0.9".  The document is available at:
 Mapping Version 0.9".  The document is available at:
-<http://playground.sun.com/1275/practice>.
+<http://www.openfirmware.org/ofwg/practice/>
 
 
 1) interrupts property
 1) interrupts property
 ----------------------
 ----------------------

+ 11 - 3
Documentation/printk-formats.txt

@@ -53,6 +53,14 @@ Struct Resources:
 	For printing struct resources. The 'R' and 'r' specifiers result in a
 	For printing struct resources. The 'R' and 'r' specifiers result in a
 	printed resource with ('R') or without ('r') a decoded flags member.
 	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:
 Raw buffer as a hex string:
 	%*ph	00 01 02  ...  3f
 	%*ph	00 01 02  ...  3f
 	%*phC	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);
 	printk("%lld", (long long)s64_var);
 
 
 If <type> is dependent on a config option for its size (e.g., sector_t,
 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",
 	printk("test: sector number/total blocks: %llu/%llu\n",
 		(unsigned long long)sector, (unsigned long long)blockcount);
 		(unsigned long long)sector, (unsigned long long)blockcount);

+ 6 - 1
MAINTAINERS

@@ -1956,7 +1956,8 @@ F:	drivers/misc/*
 
 
 CHECKPATCH
 CHECKPATCH
 M:	Andy Whitcroft <apw@canonical.com>
 M:	Andy Whitcroft <apw@canonical.com>
-S:	Supported
+M:	Joe Perches <joe@perches.com>
+S:	Maintained
 F:	scripts/checkpatch.pl
 F:	scripts/checkpatch.pl
 
 
 CHINESE DOCUMENTATION
 CHINESE DOCUMENTATION
@@ -5035,6 +5036,10 @@ L:	linux-mm@kvack.org
 W:	http://www.linux-mm.org
 W:	http://www.linux-mm.org
 S:	Maintained
 S:	Maintained
 F:	include/linux/mm.h
 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/
 F:	mm/
 
 
 MEMORY RESOURCE CONTROLLER
 MEMORY RESOURCE CONTROLLER

+ 9 - 11
arch/alpha/kernel/osf_sys.c

@@ -1300,17 +1300,15 @@ static unsigned long
 arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
 arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
 		         unsigned long limit)
 		         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
 unsigned long

+ 6 - 0
arch/arm/boot/dts/armada-370-xp.dtsi

@@ -131,6 +131,12 @@
 			clocks = <&coreclk 0>;
 			clocks = <&coreclk 0>;
 			status = "disabled";
 			status = "disabled";
 		};
 		};
+
+		rtc@10300 {
+			compatible = "marvell,orion-rtc";
+			reg = <0xd0010300 0x20>;
+			interrupts = <50>;
+		};
 	};
 	};
 };
 };
 
 

+ 8 - 0
arch/arm/configs/pxa910_defconfig

@@ -42,6 +42,14 @@ CONFIG_SMC91X=y
 # CONFIG_SERIO is not set
 # CONFIG_SERIO is not set
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA=y
 CONFIG_SERIAL_PXA_CONSOLE=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_LEGACY_PTYS is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_HWMON is not set
 # CONFIG_HWMON is not set

+ 4 - 1
arch/arm/mach-mmp/include/mach/pxa910.h

@@ -8,6 +8,7 @@ extern void __init pxa910_init_irq(void);
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/i2c/pxa-i2c.h>
 #include <mach/devices.h>
 #include <mach/devices.h>
 #include <linux/platform_data/mtd-nand-pxa3xx.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_uart1;
 extern struct pxa_device_desc pxa910_device_uart2;
 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_u2o;
 extern struct platform_device pxa168_device_u2ootg;
 extern struct platform_device pxa168_device_u2ootg;
 extern struct platform_device pxa168_device_u2oehci;
 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_gpio;
 extern struct platform_device pxa910_device_rtc;
 extern struct platform_device pxa910_device_rtc;
 
 

+ 3 - 0
arch/arm/mach-mmp/pxa910.c

@@ -134,6 +134,9 @@ PXA910_DEVICE(pwm2, "pxa910-pwm", 1, NONE, 0xd401a400, 0x10);
 PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA910_DEVICE(pwm3, "pxa910-pwm", 2, NONE, 0xd401a800, 0x10);
 PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
 PXA910_DEVICE(pwm4, "pxa910-pwm", 3, NONE, 0xd401ac00, 0x10);
 PXA910_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
 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[] = {
 struct resource pxa910_resource_gpio[] = {
 	{
 	{

+ 92 - 0
arch/arm/mach-mmp/ttc_dkb.c

@@ -19,6 +19,8 @@
 #include <linux/gpio.h>
 #include <linux/gpio.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/mfd/88pm860x.h>
 #include <linux/platform_data/mv_usb.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-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/arch.h>
@@ -184,6 +186,92 @@ static struct pxa3xx_nand_platform_data dkb_nand_info = {
 };
 };
 #endif
 #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)
 static void __init ttc_dkb_init(void)
 {
 {
 	mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
 	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;
 	pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
 	platform_device_register(&pxa168_device_u2ootg);
 	platform_device_register(&pxa168_device_u2ootg);
 #endif
 #endif
+
+#ifdef CONFIG_MMP_DISP
+	add_disp();
+#endif
 }
 }
 
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")

+ 0 - 5
arch/cris/include/uapi/asm/posix_types.h

@@ -22,11 +22,6 @@ typedef unsigned short	__kernel_uid_t;
 typedef unsigned short	__kernel_gid_t;
 typedef unsigned short	__kernel_gid_t;
 #define __kernel_uid_t __kernel_uid_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;
 typedef unsigned short	__kernel_old_dev_t;
 #define __kernel_old_dev_t __kernel_old_dev_t
 #define __kernel_old_dev_t __kernel_old_dev_t
 
 

+ 1 - 1
arch/mn10300/unit-asb2305/pci-irq.c

@@ -29,7 +29,7 @@ void __init pcibios_fixup_irqs(void)
 	struct pci_dev *dev = NULL;
 	struct pci_dev *dev = NULL;
 	u8 line, pin;
 	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);
 		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
 		if (pin) {
 		if (pin) {
 			dev->irq = XIRQ1;
 			dev->irq = XIRQ1;

+ 0 - 6
arch/tile/Kconfig

@@ -413,12 +413,6 @@ config TILE_USB
 	  Provides USB host adapter support for the built-in EHCI and OHCI
 	  Provides USB host adapter support for the built-in EHCI and OHCI
 	  interfaces on TILE-Gx chips.
 	  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"
 source "drivers/pci/hotplug/Kconfig"
 
 
 endmenu
 endmenu

+ 5 - 3
block/blk-core.c

@@ -1474,6 +1474,11 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio)
 	 */
 	 */
 	blk_queue_bounce(q, &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)) {
 	if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
 		spin_lock_irq(q->queue_lock);
 		spin_lock_irq(q->queue_lock);
 		where = ELEVATOR_INSERT_FLUSH;
 		where = ELEVATOR_INSERT_FLUSH;
@@ -1714,9 +1719,6 @@ generic_make_request_checks(struct bio *bio)
 	 */
 	 */
 	blk_partition_remap(bio);
 	blk_partition_remap(bio);
 
 
-	if (bio_integrity_enabled(bio) && bio_integrity_prep(bio))
-		goto end_io;
-
 	if (bio_check_eod(bio, nr_sectors))
 	if (bio_check_eod(bio, nr_sectors))
 		goto end_io;
 		goto end_io;
 
 

+ 4 - 0
block/blk-integrity.c

@@ -420,6 +420,8 @@ int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
 	} else
 	} else
 		bi->name = bi_unsupported_name;
 		bi->name = bi_unsupported_name;
 
 
+	disk->queue->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(blk_integrity_register);
 EXPORT_SYMBOL(blk_integrity_register);
@@ -438,6 +440,8 @@ void blk_integrity_unregister(struct gendisk *disk)
 	if (!disk || !disk->integrity)
 	if (!disk || !disk->integrity)
 		return;
 		return;
 
 
+	disk->queue->backing_dev_info.capabilities &= ~BDI_CAP_STABLE_WRITES;
+
 	bi = disk->integrity;
 	bi = disk->integrity;
 
 
 	kobject_uevent(&bi->kobj, KOBJ_REMOVE);
 	kobject_uevent(&bi->kobj, KOBJ_REMOVE);

+ 2 - 2
drivers/net/ethernet/sun/Kconfig

@@ -61,7 +61,7 @@ config SUNGEM
 	select SUNGEM_PHY
 	select SUNGEM_PHY
 	---help---
 	---help---
 	  Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
 	  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
 config CASSINI
 	tristate "Sun Cassini support"
 	tristate "Sun Cassini support"
@@ -69,7 +69,7 @@ config CASSINI
 	select CRC32
 	select CRC32
 	---help---
 	---help---
 	  Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
 	  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
 config SUNVNET
 	tristate "Sun Virtual Network support"
 	tristate "Sun Virtual Network support"

+ 30 - 7
drivers/pcmcia/cs.c

@@ -484,7 +484,7 @@ static int socket_early_resume(struct pcmcia_socket *skt)
 
 
 static int socket_late_resume(struct pcmcia_socket *skt)
 static int socket_late_resume(struct pcmcia_socket *skt)
 {
 {
-	int ret;
+	int ret = 0;
 
 
 	mutex_lock(&skt->ops_mutex);
 	mutex_lock(&skt->ops_mutex);
 	skt->state &= ~SOCKET_SUSPEND;
 	skt->state &= ~SOCKET_SUSPEND;
@@ -511,19 +511,31 @@ static int socket_late_resume(struct pcmcia_socket *skt)
 		return socket_insert(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
 #ifdef CONFIG_CARDBUS
 	if (skt->state & SOCKET_CARDBUS) {
 	if (skt->state & SOCKET_CARDBUS) {
 		/* We can't be sure the CardBus card is the same
 		/* We can't be sure the CardBus card is the same
 		 * as the one previously inserted. Therefore, remove
 		 * as the one previously inserted. Therefore, remove
 		 * and re-add... */
 		 * and re-add... */
 		cb_free(skt);
 		cb_free(skt);
-		cb_alloc(skt);
-		return 0;
+		ret = cb_alloc(skt);
+		if (ret)
+			cb_free(skt);
 	}
 	}
 #endif
 #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)
 static int socket_resume(struct pcmcia_socket *skt)
 {
 {
+	int err;
 	if (!(skt->state & SOCKET_SUSPEND))
 	if (!(skt->state & SOCKET_SUSPEND))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	socket_early_resume(skt);
 	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)
 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);
 	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 = {
 static const struct dev_pm_ops pcmcia_socket_pm_ops = {
 	/* dev_resume may be called with IRQs enabled */
 	/* dev_resume may be called with IRQs enabled */
 	SET_SYSTEM_SLEEP_PM_OPS(NULL,
 	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,
 	.resume_noirq = pcmcia_socket_dev_resume_noirq,
 	.thaw_noirq = pcmcia_socket_dev_resume_noirq,
 	.thaw_noirq = pcmcia_socket_dev_resume_noirq,
 	.restore_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)
 #define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)

+ 42 - 0
drivers/rtc/Kconfig

@@ -204,6 +204,12 @@ config RTC_DRV_DS3232
 	  This driver can also be built as a module.  If so, the module
 	  This driver can also be built as a module.  If so, the module
 	  will be called rtc-ds3232.
 	  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
 config RTC_DRV_MAX6900
 	tristate "Maxim MAX6900"
 	tristate "Maxim MAX6900"
 	help
 	help
@@ -243,6 +249,26 @@ config RTC_DRV_MAX8998
 	  This driver can also be built as a module. If so, the module
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-max8998.
 	  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
 config RTC_DRV_RS5C372
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
 	help
 	help
@@ -380,6 +406,14 @@ config RTC_DRV_TPS65910
 	  This driver can also be built as a module. If so, the module
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-tps65910.
 	  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
 config RTC_DRV_RC5T583
 	tristate "RICOH 5T583 RTC driver"
 	tristate "RICOH 5T583 RTC driver"
 	depends on MFD_RC5T583
 	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
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-pcf2123.
 	  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
 endif # SPI_MASTER
 
 
 comment "Platform RTC drivers"
 comment "Platform RTC drivers"

+ 5 - 0
drivers/rtc/Makefile

@@ -58,6 +58,7 @@ obj-$(CONFIG_RTC_DRV_IMXDI)	+= rtc-imxdi.o
 obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_JZ4740)	+= rtc-jz4740.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_LPC32XX)	+= rtc-lpc32xx.o
 obj-$(CONFIG_RTC_DRV_LOONGSON1)	+= rtc-ls1x.o
 obj-$(CONFIG_RTC_DRV_LOONGSON1)	+= rtc-ls1x.o
 obj-$(CONFIG_RTC_DRV_M41T80)	+= rtc-m41t80.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_MAX8907)	+= rtc-max8907.o
 obj-$(CONFIG_RTC_DRV_MAX8925)	+= rtc-max8925.o
 obj-$(CONFIG_RTC_DRV_MAX8925)	+= rtc-max8925.o
 obj-$(CONFIG_RTC_DRV_MAX8998)	+= rtc-max8998.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_MAX6902)	+= rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MAX77686)	+= rtc-max77686.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.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_RS5C348)	+= rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_RV3029C2)	+= rtc-rv3029c2.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_RX8025)	+= rtc-rx8025.o
 obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o
 obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.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_TWL4030)	+= rtc-twl.o
 obj-$(CONFIG_RTC_DRV_TPS6586X)	+= rtc-tps6586x.o
 obj-$(CONFIG_RTC_DRV_TPS6586X)	+= rtc-tps6586x.o
 obj-$(CONFIG_RTC_DRV_TPS65910)	+= rtc-tps65910.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_TX4939)	+= rtc-tx4939.o
 obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o

+ 3 - 1
drivers/rtc/class.c

@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
 */
 */
 
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/rtc.h>
 #include <linux/kdev_t.h>
 #include <linux/kdev_t.h>
@@ -261,7 +263,7 @@ static int __init rtc_init(void)
 {
 {
 	rtc_class = class_create(THIS_MODULE, "rtc");
 	rtc_class = class_create(THIS_MODULE, "rtc");
 	if (IS_ERR(rtc_class)) {
 	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);
 		return PTR_ERR(rtc_class);
 	}
 	}
 	rtc_class->suspend = rtc_suspend;
 	rtc_class->suspend = rtc_suspend;

+ 8 - 9
drivers/rtc/rtc-at91rm9200.c

@@ -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_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
 	tm->tm_year = tm->tm_year - 1900;
 	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,
 		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 		tm->tm_hour, tm->tm_min, tm->tm_sec);
 		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;
 	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,
 		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 		tm->tm_hour, tm->tm_min, tm->tm_sec);
 		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)
 	alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
 			? 1 : 0;
 			? 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,
 		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 		tm->tm_hour, tm->tm_min, tm->tm_sec);
 		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);
 		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,
 		at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
 		tm.tm_min, tm.tm_sec);
 		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)
 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) {
 	if (enabled) {
 		at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
 		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);
 		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);
 			events >> 8, events & 0x000000FF);
 
 
 		return IRQ_HANDLED;
 		return IRQ_HANDLED;
@@ -296,8 +296,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
 				IRQF_SHARED,
 				IRQF_SHARED,
 				"at91_rtc", pdev);
 				"at91_rtc", pdev);
 	if (ret) {
 	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;
 		return ret;
 	}
 	}
 
 
@@ -315,7 +314,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
 	}
 	}
 	platform_set_drvdata(pdev, rtc);
 	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;
 	return 0;
 }
 }
 
 

+ 5 - 10
drivers/rtc/rtc-cmos.c

@@ -706,7 +706,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 			rtc_cmos_int_handler = hpet_rtc_interrupt;
 			rtc_cmos_int_handler = hpet_rtc_interrupt;
 			err = hpet_register_irq_handler(cmos_interrupt);
 			err = hpet_register_irq_handler(cmos_interrupt);
 			if (err != 0) {
 			if (err != 0) {
-				printk(KERN_WARNING "hpet_register_irq_handler "
+				dev_warn(dev, "hpet_register_irq_handler "
 						" failed in rtc_init().");
 						" failed in rtc_init().");
 				goto cleanup1;
 				goto cleanup1;
 			}
 			}
@@ -731,8 +731,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
 		goto cleanup2;
 		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" :
 		!is_valid_irq(rtc_irq) ? "no alarms" :
 			cmos_rtc.mon_alrm ? "alarms up to one year" :
 			cmos_rtc.mon_alrm ? "alarms up to one year" :
 			cmos_rtc.day_alrm ? "alarms up to one month" :
 			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);
 			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 & RTC_AIE) ? ", alarm may wake" : "",
 			tmp);
 			tmp);
 
 
@@ -876,9 +874,7 @@ static int cmos_resume(struct device *dev)
 		spin_unlock_irq(&rtc_lock);
 		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;
 	return 0;
 }
 }
@@ -1098,7 +1094,6 @@ static __init void cmos_of_init(struct platform_device *pdev)
 }
 }
 #else
 #else
 static inline void cmos_of_init(struct platform_device *pdev) {}
 static inline void cmos_of_init(struct platform_device *pdev) {}
-#define of_cmos_match NULL
 #endif
 #endif
 /*----------------------------------------------------------------*/
 /*----------------------------------------------------------------*/
 
 
@@ -1140,7 +1135,7 @@ static struct platform_driver cmos_platform_driver = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 		.pm		= &cmos_pm_ops,
 		.pm		= &cmos_pm_ops,
 #endif
 #endif
-		.of_match_table = of_cmos_match,
+		.of_match_table = of_match_ptr(of_cmos_match),
 	}
 	}
 };
 };
 
 

+ 2 - 5
drivers/rtc/rtc-coh901331.c

@@ -157,7 +157,6 @@ static int __exit coh901331_remove(struct platform_device *pdev)
 	if (rtap) {
 	if (rtap) {
 		rtc_device_unregister(rtap->rtc);
 		rtc_device_unregister(rtap->rtc);
 		clk_unprepare(rtap->clk);
 		clk_unprepare(rtap->clk);
-		clk_put(rtap->clk);
 		platform_set_drvdata(pdev, NULL);
 		platform_set_drvdata(pdev, NULL);
 	}
 	}
 
 
@@ -196,7 +195,7 @@ static int __init coh901331_probe(struct platform_device *pdev)
 			     "RTC COH 901 331 Alarm", rtap))
 			     "RTC COH 901 331 Alarm", rtap))
 		return -EIO;
 		return -EIO;
 
 
-	rtap->clk = clk_get(&pdev->dev, NULL);
+	rtap->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(rtap->clk)) {
 	if (IS_ERR(rtap->clk)) {
 		ret = PTR_ERR(rtap->clk);
 		ret = PTR_ERR(rtap->clk);
 		dev_err(&pdev->dev, "could not get clock\n");
 		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);
 	ret = clk_prepare_enable(rtap->clk);
 	if (ret) {
 	if (ret) {
 		dev_err(&pdev->dev, "could not enable clock\n");
 		dev_err(&pdev->dev, "could not enable clock\n");
-		goto out_no_clk_prepenable;
+		return ret;
 	}
 	}
 	clk_disable(rtap->clk);
 	clk_disable(rtap->clk);
 
 
@@ -224,8 +223,6 @@ static int __init coh901331_probe(struct platform_device *pdev)
  out_no_rtc:
  out_no_rtc:
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 	clk_unprepare(rtap->clk);
 	clk_unprepare(rtap->clk);
- out_no_clk_prepenable:
-	clk_put(rtap->clk);
 	return ret;
 	return ret;
 }
 }
 
 

+ 6 - 12
drivers/rtc/rtc-da9052.c

@@ -240,9 +240,10 @@ static int da9052_rtc_probe(struct platform_device *pdev)
 	rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
 	rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
 	platform_set_drvdata(pdev, rtc);
 	platform_set_drvdata(pdev, rtc);
 	rtc->irq = platform_get_irq_byname(pdev, "ALM");
 	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) {
 	if (ret != 0) {
 		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
 		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret);
 		return 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,
 	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
 				       &da9052_rtc_ops, THIS_MODULE);
 				       &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;
 	return 0;
-
-err_free_irq:
-	free_irq(rtc->irq, rtc);
-	return ret;
 }
 }
 
 
 static int da9052_rtc_remove(struct platform_device *pdev)
 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;
 	struct da9052_rtc *rtc = pdev->dev.platform_data;
 
 
 	rtc_device_unregister(rtc->rtc);
 	rtc_device_unregister(rtc->rtc);
-	free_irq(rtc->irq, rtc);
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 
 
 	return 0;
 	return 0;

+ 10 - 18
drivers/rtc/rtc-davinci.c

@@ -506,19 +506,19 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 	davinci_rtc->pbase = res->start;
 	davinci_rtc->pbase = res->start;
 	davinci_rtc->base_size = resource_size(res);
 	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) {
 	if (!mem) {
 		dev_err(dev, "RTC registers at %08x are not free\n",
 		dev_err(dev, "RTC registers at %08x are not free\n",
 			davinci_rtc->pbase);
 			davinci_rtc->pbase);
 		return -EBUSY;
 		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) {
 	if (!davinci_rtc->base) {
 		dev_err(dev, "unable to ioremap MEM resource\n");
 		dev_err(dev, "unable to ioremap MEM resource\n");
-		ret = -ENOMEM;
-		goto fail2;
+		return -ENOMEM;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, davinci_rtc);
 	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);
 		ret = PTR_ERR(davinci_rtc->rtc);
 		dev_err(dev, "unable to register RTC device, err %d\n",
 		dev_err(dev, "unable to register RTC device, err %d\n",
 				ret);
 				ret);
-		goto fail3;
+		goto fail1;
 	}
 	}
 
 
 	rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
 	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_CTRL);
 	rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
 	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);
 			  0, "davinci_rtc", davinci_rtc);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(dev, "unable to register davinci RTC interrupt\n");
 		dev_err(dev, "unable to register davinci RTC interrupt\n");
-		goto fail4;
+		goto fail2;
 	}
 	}
 
 
 	/* Enable interrupts */
 	/* Enable interrupts */
@@ -557,13 +557,10 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
 
 
 	return 0;
 	return 0;
 
 
-fail4:
+fail2:
 	rtc_device_unregister(davinci_rtc->rtc);
 	rtc_device_unregister(davinci_rtc->rtc);
-fail3:
+fail1:
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
-	iounmap(davinci_rtc->base);
-fail2:
-	release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -575,13 +572,8 @@ static int davinci_rtc_remove(struct platform_device *pdev)
 
 
 	rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
 	rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
 
 
-	free_irq(davinci_rtc->irq, davinci_rtc);
-
 	rtc_device_unregister(davinci_rtc->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);
 	platform_set_drvdata(pdev, NULL);
 
 
 	return 0;
 	return 0;

+ 6 - 5
drivers/rtc/rtc-dev.c

@@ -11,6 +11,8 @@
  * published by the Free Software Foundation.
  * published by the Free Software Foundation.
 */
 */
 
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/rtc.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
@@ -462,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
 		return;
 		return;
 
 
 	if (rtc->id >= RTC_DEV_MAX) {
 	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;
 		return;
 	}
 	}
 
 
@@ -480,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc)
 void rtc_dev_add_device(struct rtc_device *rtc)
 void rtc_dev_add_device(struct rtc_device *rtc)
 {
 {
 	if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
 	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);
 			rtc->name, MAJOR(rtc_devt), rtc->id);
 	else
 	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);
 			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");
 	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
 	if (err < 0)
 	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)
 void __exit rtc_dev_exit(void)

+ 2 - 6
drivers/rtc/rtc-ds1305.c

@@ -635,9 +635,7 @@ static int ds1305_probe(struct spi_device *spi)
 		goto fail0;
 		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
 	/* Sanity check register values ... partially compensating for the
 	 * fact that SPI has no device handshake.  A pullup on MISO would
 	 * 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;
 			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 */
 	/* see if non-Linux software set up AM/PM mode */

+ 2 - 9
drivers/rtc/rtc-ds1307.c

@@ -322,12 +322,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 		return -EIO;
 		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_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
 	t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 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;
 		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,
 	result = ds1307->write_block_data(ds1307->client,
 		ds1307->offset, 7, buf);
 		ds1307->offset, 7, buf);

+ 3 - 15
drivers/rtc/rtc-ds2404.c

@@ -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++) {
 	for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
 		err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
 		err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
 		if (err) {
 		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);
 				ds2404_gpio[i].name, err);
 			goto err_request;
 			goto err_request;
 		}
 		}
@@ -177,7 +177,7 @@ static void ds2404_write_memory(struct device *dev, u16 offset,
 
 
 	for (i = 0; i < length; i++) {
 	for (i = 0; i < length; i++) {
 		if (out[i] != ds2404_read_byte(dev)) {
 		if (out[i] != ds2404_read_byte(dev)) {
-			printk(KERN_ERR "read invalid data\n");
+			dev_err(dev, "read invalid data\n");
 			return;
 			return;
 		}
 		}
 	}
 	}
@@ -283,19 +283,7 @@ static struct platform_driver rtc_device_driver = {
 		.owner	= THIS_MODULE,
 		.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_DESCRIPTION("DS2404 RTC");
 MODULE_AUTHOR("Sven Schnelle");
 MODULE_AUTHOR("Sven Schnelle");

+ 6 - 4
drivers/rtc/rtc-efi.c

@@ -13,6 +13,8 @@
  *
  *
  */
  */
 
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/time.h>
 #include <linux/time.h>
@@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft)
 	int ndays = 0;
 	int ndays = 0;
 
 
 	if (eft->year < 1998) {
 	if (eft->year < 1998) {
-		printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+		pr_err("EFI year < 1998, invalid date\n");
 		return -1;
 		return -1;
 	}
 	}
 
 
@@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
 	eft->day	= wtime->tm_mday;
 	eft->day	= wtime->tm_mday;
 	eft->hour	= wtime->tm_hour;
 	eft->hour	= wtime->tm_hour;
 	eft->minute	= wtime->tm_min;
 	eft->minute	= wtime->tm_min;
-	eft->second 	= wtime->tm_sec;
+	eft->second	= wtime->tm_sec;
 	eft->nanosecond = 0;
 	eft->nanosecond = 0;
 	eft->daylight	= wtime->tm_isdst ? EFI_ISDST : 0;
 	eft->daylight	= wtime->tm_isdst ? EFI_ISDST : 0;
 	eft->timezone	= EFI_UNSPECIFIED_TIMEZONE;
 	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);
 	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;
 	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) {
 	if (status != EFI_SUCCESS) {
 		/* should never happen */
 		/* should never happen */
-		printk(KERN_ERR "efitime: can't read time\n");
+		dev_err(dev, "can't read time\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 

+ 4 - 29
drivers/rtc/rtc-fm3130.c

@@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
 
 
 	fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
 	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_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
 	t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 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;
 	tmp = t->tm_year - 100;
 	buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
 	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);
 	fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
 
 
@@ -517,18 +502,8 @@ bad_alarm:
 bad_clock:
 bad_clock:
 
 
 	if (!fm3130->data_valid || !fm3130->alarm_valid)
 	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.
 	/* We won't bail out here because we just got invalid data.
 	   Time setting from u-boot doesn't work anyway */
 	   Time setting from u-boot doesn't work anyway */

+ 1 - 3
drivers/rtc/rtc-imxdi.c

@@ -406,7 +406,7 @@ static int dryice_rtc_probe(struct platform_device *pdev)
 
 
 	mutex_init(&imxdi->write_mutex);
 	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))
 	if (IS_ERR(imxdi->clk))
 		return PTR_ERR(imxdi->clk);
 		return PTR_ERR(imxdi->clk);
 	clk_prepare_enable(imxdi->clk);
 	clk_prepare_enable(imxdi->clk);
@@ -475,7 +475,6 @@ static int dryice_rtc_probe(struct platform_device *pdev)
 
 
 err:
 err:
 	clk_disable_unprepare(imxdi->clk);
 	clk_disable_unprepare(imxdi->clk);
-	clk_put(imxdi->clk);
 
 
 	return rc;
 	return rc;
 }
 }
@@ -492,7 +491,6 @@ static int dryice_rtc_remove(struct platform_device *pdev)
 	rtc_device_unregister(imxdi->rtc);
 	rtc_device_unregister(imxdi->rtc);
 
 
 	clk_disable_unprepare(imxdi->clk);
 	clk_disable_unprepare(imxdi->clk);
-	clk_put(imxdi->clk);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
drivers/rtc/rtc-isl12022.c

@@ -227,7 +227,7 @@ static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 					 buf[ISL12022_REG_SC + i]);
 					 buf[ISL12022_REG_SC + i]);
 		if (ret)
 		if (ret)
 			return -EIO;
 			return -EIO;
-	};
+	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 338 - 0
drivers/rtc/rtc-lp8788.c

@@ -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");

+ 641 - 0
drivers/rtc/rtc-max77686.c

@@ -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");

+ 3 - 3
drivers/rtc/rtc-max8907.c

@@ -205,8 +205,9 @@ static int max8907_rtc_probe(struct platform_device *pdev)
 		goto err_unregister;
 		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) {
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
 		dev_err(&pdev->dev, "Failed to request IRQ%d: %d\n",
 			rtc->irq, ret);
 			rtc->irq, ret);
@@ -224,7 +225,6 @@ static int max8907_rtc_remove(struct platform_device *pdev)
 {
 {
 	struct max8907_rtc *rtc = platform_get_drvdata(pdev);
 	struct max8907_rtc *rtc = platform_get_drvdata(pdev);
 
 
-	free_irq(rtc->irq, rtc);
 	rtc_device_unregister(rtc->rtc_dev);
 	rtc_device_unregister(rtc->rtc_dev);
 
 
 	return 0;
 	return 0;

+ 552 - 0
drivers/rtc/rtc-max8997.c

@@ -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");

+ 4 - 1
drivers/rtc/rtc-mpc5121.c

@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/rtc.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 #include <linux/io.h>
 #include <linux/io.h>
@@ -403,17 +404,19 @@ static int mpc5121_rtc_remove(struct platform_device *op)
 	return 0;
 	return 0;
 }
 }
 
 
+#ifdef CONFIG_OF
 static struct of_device_id mpc5121_rtc_match[] = {
 static struct of_device_id mpc5121_rtc_match[] = {
 	{ .compatible = "fsl,mpc5121-rtc", },
 	{ .compatible = "fsl,mpc5121-rtc", },
 	{ .compatible = "fsl,mpc5200-rtc", },
 	{ .compatible = "fsl,mpc5200-rtc", },
 	{},
 	{},
 };
 };
+#endif
 
 
 static struct platform_driver mpc5121_rtc_driver = {
 static struct platform_driver mpc5121_rtc_driver = {
 	.driver = {
 	.driver = {
 		.name = "mpc5121-rtc",
 		.name = "mpc5121-rtc",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
-		.of_match_table = mpc5121_rtc_match,
+		.of_match_table = of_match_ptr(mpc5121_rtc_match),
 	},
 	},
 	.probe = mpc5121_rtc_probe,
 	.probe = mpc5121_rtc_probe,
 	.remove = mpc5121_rtc_remove,
 	.remove = mpc5121_rtc_remove,

+ 31 - 0
drivers/rtc/rtc-pcf8523.c

@@ -23,6 +23,7 @@
 #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */
 #define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */
 #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */
 #define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */
 #define REG_CONTROL3_PM_MASK 0xe0
 #define REG_CONTROL3_PM_MASK 0xe0
+#define REG_CONTROL3_BLF (1 << 2) /* battery low bit, read-only */
 
 
 #define REG_SECONDS  0x03
 #define REG_SECONDS  0x03
 #define REG_SECONDS_OS (1 << 7)
 #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);
 	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 = {
 static const struct rtc_class_ops pcf8523_rtc_ops = {
 	.read_time = pcf8523_rtc_read_time,
 	.read_time = pcf8523_rtc_read_time,
 	.set_time = pcf8523_rtc_set_time,
 	.set_time = pcf8523_rtc_set_time,
+	.ioctl = pcf8523_rtc_ioctl,
 };
 };
 
 
 static int pcf8523_probe(struct i2c_client *client,
 static int pcf8523_probe(struct i2c_client *client,

+ 1 - 1
drivers/rtc/rtc-pcf8563.c

@@ -181,7 +181,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 				__func__, err, data[0], data[1]);
 				__func__, err, data[0], data[1]);
 			return -EIO;
 			return -EIO;
 		}
 		}
-	};
+	}
 
 
 	return 0;
 	return 0;
 }
 }

+ 2 - 2
drivers/rtc/rtc-pcf8583.c

@@ -185,8 +185,8 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
 	if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
 	if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
 		unsigned char new_ctrl = 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)
 		if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
 			return err;
 			return err;

+ 2 - 0
drivers/rtc/rtc-pl031.c

@@ -384,6 +384,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
 		goto out_no_irq;
 		goto out_no_irq;
 	}
 	}
 
 
+	device_init_wakeup(&adev->dev, 1);
+
 	return 0;
 	return 0;
 
 
 out_no_irq:
 out_no_irq:

+ 15 - 8
drivers/rtc/rtc-pxa.c

@@ -62,6 +62,10 @@
 #define RYxR_MONTH_S	5
 #define RYxR_MONTH_S	5
 #define RYxR_MONTH_MASK	(0xf << RYxR_MONTH_S)
 #define RYxR_MONTH_MASK	(0xf << RYxR_MONTH_S)
 #define RYxR_DAY_MASK	0x1f
 #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_S	12
 #define RDxR_HOUR_MASK	(0x1f << RDxR_HOUR_S)
 #define RDxR_HOUR_MASK	(0x1f << RDxR_HOUR_S)
 #define RDxR_MIN_S	6
 #define RDxR_MIN_S	6
@@ -91,6 +95,7 @@ struct pxa_rtc {
 	spinlock_t		lock;		/* Protects this structure */
 	spinlock_t		lock;		/* Protects this structure */
 };
 };
 
 
+
 static u32 ryxr_calc(struct rtc_time *tm)
 static u32 ryxr_calc(struct rtc_time *tm)
 {
 {
 	return ((tm->tm_year + 1900) << RYxR_YEAR_S)
 	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)
 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;
 		| 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_year = ((rycr & RYxR_YEAR_MASK) >> RYxR_YEAR_S) - 1900;
 	tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
 	tm->tm_mon = (((rycr & RYxR_MONTH_MASK) >> RYxR_MONTH_S)) - 1;
 	tm->tm_mday = (rycr & RYxR_DAY_MASK);
 	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_hour = (rdcr & RDxR_HOUR_MASK) >> RDxR_HOUR_S;
 	tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
 	tm->tm_min = (rdcr & RDxR_MIN_MASK) >> RDxR_MIN_S;
 	tm->tm_sec = rdcr & RDxR_SEC_MASK;
 	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 = {
 static const struct rtc_class_ops pxa_rtc_ops = {
-	.open = pxa_rtc_open,
-	.release = pxa_rtc_release,
 	.read_time = pxa_rtc_read_time,
 	.read_time = pxa_rtc_read_time,
 	.set_time = pxa_rtc_set_time,
 	.set_time = pxa_rtc_set_time,
 	.read_alarm = pxa_rtc_read_alarm,
 	.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");
 		dev_err(dev, "No alarm IRQ resource defined\n");
 		goto err_ress;
 		goto err_ress;
 	}
 	}
-
+	pxa_rtc_open(dev);
 	ret = -ENOMEM;
 	ret = -ENOMEM;
 	pxa_rtc->base = ioremap(pxa_rtc->ress->start,
 	pxa_rtc->base = ioremap(pxa_rtc->ress->start,
 				resource_size(pxa_rtc->ress));
 				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 pxa_rtc *pxa_rtc = platform_get_drvdata(pdev);
 
 
+	struct device *dev = &pdev->dev;
+	pxa_rtc_release(dev);
+
 	rtc_device_unregister(pxa_rtc->rtc);
 	rtc_device_unregister(pxa_rtc->rtc);
 
 
 	spin_lock_irq(&pxa_rtc->lock);
 	spin_lock_irq(&pxa_rtc->lock);
@@ -444,10 +454,7 @@ static struct platform_driver pxa_rtc_driver = {
 
 
 static int __init pxa_rtc_init(void)
 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)
 static void __exit pxa_rtc_exit(void)

+ 3 - 2
drivers/rtc/rtc-rs5c313.c

@@ -39,6 +39,8 @@
  *	1.13	Nobuhiro Iwamatsu: Updata driver.
  *	1.13	Nobuhiro Iwamatsu: Updata driver.
  */
  */
 
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/rtc.h>
 #include <linux/rtc.h>
@@ -352,8 +354,7 @@ static void rs5c313_check_xstp_bit(void)
 		tm.tm_year 	= 2000 - 1900;
 		tm.tm_year 	= 2000 - 1900;
 
 
 		rs5c313_rtc_set_time(NULL, &tm);
 		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;
 	RS5C313_CEDISABLE;
 	ndelay(700);		/* CE:L */
 	ndelay(700);		/* CE:L */

+ 4 - 6
drivers/rtc/rtc-rs5c372.c

@@ -311,8 +311,7 @@ static int rs5c_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 		buf &= ~RS5C_CTRL1_AALE;
 		buf &= ~RS5C_CTRL1_AALE;
 
 
 	if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
 	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;
 		status = -EIO;
 	} else
 	} else
 		rs5c->regs[RS5C_REG_CTRL1] = buf;
 		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);
 		addr = RS5C_ADDR(RS5C_REG_CTRL1);
 		buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
 		buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
 		if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
 		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;
 			return -EIO;
 		}
 		}
 		rs5c->regs[RS5C_REG_CTRL1] = buf[0];
 		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++) {
 	for (i = 0; i < sizeof(buf); i++) {
 		addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
 		addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
 		if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
 		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;
 			return -EIO;
 		}
 		}
 	}
 	}
@@ -405,8 +404,7 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 		addr = RS5C_ADDR(RS5C_REG_CTRL1);
 		addr = RS5C_ADDR(RS5C_REG_CTRL1);
 		buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
 		buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
 		if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
 		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];
 		rs5c->regs[RS5C_REG_CTRL1] = buf[0];
 	}
 	}
 
 

+ 314 - 0
drivers/rtc/rtc-rx4581.c

@@ -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");

+ 9 - 9
drivers/rtc/rtc-s3c.c

@@ -115,7 +115,7 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
 {
 	unsigned int tmp;
 	unsigned int tmp;
 
 
-	pr_debug("%s: aie=%d\n", __func__, enabled);
+	dev_dbg(dev, "%s: aie=%d\n", __func__, enabled);
 
 
 	clk_enable(rtc_clk);
 	clk_enable(rtc_clk);
 	tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 	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;
 	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,
 		 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);
 		 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;
 	void __iomem *base = s3c_rtc_base;
 	int year = tm->tm_year - 100;
 	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,
 		 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
 		 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;
 	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,
 		 alm_en,
 		 1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
 		 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);
 		 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;
 	unsigned int alrm_en;
 
 
 	clk_enable(rtc_clk);
 	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,
 		 alrm->enabled,
 		 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
 		 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
 		 tm->tm_hour, tm->tm_min, tm->tm_sec);
 		 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);
 		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);
 	writeb(alrm_en, base + S3C2410_RTCALM);
 
 
@@ -459,7 +459,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 	int ret;
 	int ret;
 	int tmp;
 	int tmp;
 
 
-	pr_debug("%s: probe=%p\n", __func__, pdev);
+	dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev);
 
 
 	/* find the IRQs */
 	/* find the IRQs */
 
 
@@ -475,7 +475,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 		return s3c_rtc_alarmno;
 		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);
 		 s3c_rtc_tickno, s3c_rtc_alarmno);
 
 
 	/* get the memory region */
 	/* get the memory region */
@@ -504,7 +504,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
 
 	s3c_rtc_enable(pdev, 1);
 	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));
 		 readw(s3c_rtc_base + S3C2410_RTCCON));
 
 
 	device_init_wakeup(&pdev->dev, 1);
 	device_init_wakeup(&pdev->dev, 1);

+ 9 - 6
drivers/rtc/rtc-sa1100.c

@@ -108,9 +108,6 @@ static int sa1100_rtc_open(struct device *dev)
 	struct rtc_device *rtc = info->rtc;
 	struct rtc_device *rtc = info->rtc;
 	int ret;
 	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);
 	ret = request_irq(info->irq_1hz, sa1100_rtc_interrupt, 0, "rtc 1Hz", dev);
 	if (ret) {
 	if (ret) {
 		dev_err(dev, "IRQ %d already in use.\n", info->irq_1hz);
 		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);
 	free_irq(info->irq_1hz, dev);
  fail_ui:
  fail_ui:
 	clk_disable_unprepare(info->clk);
 	clk_disable_unprepare(info->clk);
- fail_clk:
 	return ret;
 	return ret;
 }
 }
 
 
@@ -144,7 +140,6 @@ static void sa1100_rtc_release(struct device *dev)
 
 
 	free_irq(info->irq_alarm, dev);
 	free_irq(info->irq_alarm, dev);
 	free_irq(info->irq_1hz, 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)
 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);
 	spin_lock_init(&info->lock);
 	platform_set_drvdata(pdev, info);
 	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
 	 * 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.
 	 * 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;
 	return 0;
 err_dev:
 err_dev:
+	clk_disable_unprepare(info->clk);
+err_enable_clk:
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 	clk_put(info->clk);
 	clk_put(info->clk);
 err_clk:
 err_clk:
@@ -318,6 +318,7 @@ static int sa1100_rtc_remove(struct platform_device *pdev)
 
 
 	if (info) {
 	if (info) {
 		rtc_device_unregister(info->rtc);
 		rtc_device_unregister(info->rtc);
+		clk_disable_unprepare(info->clk);
 		clk_put(info->clk);
 		clk_put(info->clk);
 		platform_set_drvdata(pdev, NULL);
 		platform_set_drvdata(pdev, NULL);
 		kfree(info);
 		kfree(info);
@@ -349,12 +350,14 @@ static const struct dev_pm_ops sa1100_rtc_pm_ops = {
 };
 };
 #endif
 #endif
 
 
+#ifdef CONFIG_OF
 static struct of_device_id sa1100_rtc_dt_ids[] = {
 static struct of_device_id sa1100_rtc_dt_ids[] = {
 	{ .compatible = "mrvl,sa1100-rtc", },
 	{ .compatible = "mrvl,sa1100-rtc", },
 	{ .compatible = "mrvl,mmp-rtc", },
 	{ .compatible = "mrvl,mmp-rtc", },
 	{}
 	{}
 };
 };
 MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
 MODULE_DEVICE_TABLE(of, sa1100_rtc_dt_ids);
+#endif
 
 
 static struct platform_driver sa1100_rtc_driver = {
 static struct platform_driver sa1100_rtc_driver = {
 	.probe		= sa1100_rtc_probe,
 	.probe		= sa1100_rtc_probe,
@@ -364,7 +367,7 @@ static struct platform_driver sa1100_rtc_driver = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 		.pm	= &sa1100_rtc_pm_ops,
 		.pm	= &sa1100_rtc_pm_ops,
 #endif
 #endif
-		.of_match_table = sa1100_rtc_dt_ids,
+		.of_match_table = of_match_ptr(sa1100_rtc_dt_ids),
 	},
 	},
 };
 };
 
 

+ 1 - 1
drivers/rtc/rtc-snvs.c

@@ -338,7 +338,7 @@ static struct platform_driver snvs_rtc_driver = {
 		.name	= "snvs_rtc",
 		.name	= "snvs_rtc",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.pm	= &snvs_rtc_pm_ops,
 		.pm	= &snvs_rtc_pm_ops,
-		.of_match_table = snvs_dt_ids,
+		.of_match_table = of_match_ptr(snvs_dt_ids),
 	},
 	},
 	.probe		= snvs_rtc_probe,
 	.probe		= snvs_rtc_probe,
 	.remove		= snvs_rtc_remove,
 	.remove		= snvs_rtc_remove,

+ 2 - 1
drivers/rtc/rtc-stmp3xxx.c

@@ -26,6 +26,7 @@
 #include <linux/rtc.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
 #include <linux/of_device.h>
+#include <linux/of.h>
 
 
 #include <mach/common.h>
 #include <mach/common.h>
 
 
@@ -280,7 +281,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {
 	.driver		= {
 	.driver		= {
 		.name	= "stmp3xxx-rtc",
 		.name	= "stmp3xxx-rtc",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
-		.of_match_table = rtc_dt_ids,
+		.of_match_table = of_match_ptr(rtc_dt_ids),
 	},
 	},
 };
 };
 
 

+ 6 - 4
drivers/rtc/rtc-sun4v.c

@@ -3,6 +3,8 @@
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
  */
  */
 
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
@@ -26,10 +28,10 @@ retry:
 			udelay(100);
 			udelay(100);
 			goto retry;
 			goto retry;
 		}
 		}
-		printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+		pr_warn("tod_get() timed out.\n");
 		return 0;
 		return 0;
 	}
 	}
-	printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+	pr_warn("tod_get() not supported.\n");
 	return 0;
 	return 0;
 }
 }
 
 
@@ -53,10 +55,10 @@ retry:
 			udelay(100);
 			udelay(100);
 			goto retry;
 			goto retry;
 		}
 		}
-		printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+		pr_warn("tod_set() timed out.\n");
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
-	printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+	pr_warn("tod_set() not supported.\n");
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 

+ 2 - 2
drivers/rtc/rtc-tps6586x.c

@@ -282,7 +282,8 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
 		goto fail_rtc_register;
 		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,
 				IRQF_ONESHOT | IRQF_EARLY_RESUME,
 				dev_name(&pdev->dev), rtc);
 				dev_name(&pdev->dev), rtc);
 	if (ret < 0) {
 	if (ret < 0) {
@@ -311,7 +312,6 @@ static int tps6586x_rtc_remove(struct platform_device *pdev)
 	tps6586x_update(tps_dev, RTC_CTRL, 0,
 	tps6586x_update(tps_dev, RTC_CTRL, 0,
 		RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
 		RTC_ENABLE | OSC_SRC_SEL | PRE_BYPASS | CL_SEL_MASK);
 	rtc_device_unregister(rtc->rtc);
 	rtc_device_unregister(rtc->rtc);
-	free_irq(rtc->irq, rtc);
 	return 0;
 	return 0;
 }
 }
 
 

+ 16 - 28
drivers/rtc/rtc-tps65910.c

@@ -22,13 +22,13 @@
 #include <linux/rtc.h>
 #include <linux/rtc.h>
 #include <linux/bcd.h>
 #include <linux/bcd.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/tps65910.h>
 #include <linux/mfd/tps65910.h>
 
 
 struct tps65910_rtc {
 struct tps65910_rtc {
 	struct rtc_device	*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*/
 /* 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,
 	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);
 		dev_name(&pdev->dev), &pdev->dev);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&pdev->dev, "IRQ is not free.\n");
 		dev_err(&pdev->dev, "IRQ is not free.\n");
 		return ret;
 		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,
 	tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
 		&tps65910_rtc_ops, THIS_MODULE);
 		&tps65910_rtc_ops, THIS_MODULE);
@@ -304,49 +305,36 @@ static int tps65910_rtc_remove(struct platform_device *pdev)
 }
 }
 
 
 #ifdef CONFIG_PM_SLEEP
 #ifdef CONFIG_PM_SLEEP
-
 static int tps65910_rtc_suspend(struct device *dev)
 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)
 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 = {
 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 = {
 static struct platform_driver tps65910_rtc_driver = {
 	.probe		= tps65910_rtc_probe,
 	.probe		= tps65910_rtc_probe,
 	.remove		= tps65910_rtc_remove,
 	.remove		= tps65910_rtc_remove,
 	.driver		= {
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.name	= "tps65910-rtc",
 		.name	= "tps65910-rtc",
-		.pm	= DEV_PM_OPS,
+		.pm	= &tps65910_rtc_pm_ops,
 	},
 	},
 };
 };
 
 

+ 349 - 0
drivers/rtc/rtc-tps80031.c

@@ -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");

+ 5 - 1
drivers/rtc/rtc-twl.c

@@ -27,6 +27,7 @@
 #include <linux/bcd.h>
 #include <linux/bcd.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
 
 
 #include <linux/i2c/twl.h>
 #include <linux/i2c/twl.h>
 
 
@@ -588,11 +589,14 @@ static int twl_rtc_resume(struct platform_device *pdev)
 #define twl_rtc_resume  NULL
 #define twl_rtc_resume  NULL
 #endif
 #endif
 
 
+#ifdef CONFIG_OF
 static const struct of_device_id twl_rtc_of_match[] = {
 static const struct of_device_id twl_rtc_of_match[] = {
 	{.compatible = "ti,twl4030-rtc", },
 	{.compatible = "ti,twl4030-rtc", },
 	{ },
 	{ },
 };
 };
 MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
 MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
+#endif
+
 MODULE_ALIAS("platform:twl_rtc");
 MODULE_ALIAS("platform:twl_rtc");
 
 
 static struct platform_driver twl4030rtc_driver = {
 static struct platform_driver twl4030rtc_driver = {
@@ -604,7 +608,7 @@ static struct platform_driver twl4030rtc_driver = {
 	.driver		= {
 	.driver		= {
 		.owner		= THIS_MODULE,
 		.owner		= THIS_MODULE,
 		.name		= "twl_rtc",
 		.name		= "twl_rtc",
-		.of_match_table = twl_rtc_of_match,
+		.of_match_table = of_match_ptr(twl_rtc_of_match),
 	},
 	},
 };
 };
 
 

+ 1 - 1
drivers/rtc/rtc-vr41xx.c

@@ -352,7 +352,7 @@ static int rtc_probe(struct platform_device *pdev)
 	disable_irq(aie_irq);
 	disable_irq(aie_irq);
 	disable_irq(pie_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;
 	return 0;
 
 

+ 10 - 18
drivers/rtc/rtc-vt8500.c

@@ -231,20 +231,21 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
 		return -ENXIO;
 		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) {
 	if (vt8500_rtc->res == NULL) {
 		dev_err(&pdev->dev, "failed to request I/O memory\n");
 		dev_err(&pdev->dev, "failed to request I/O memory\n");
 		return -EBUSY;
 		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));
 				      resource_size(vt8500_rtc->res));
 	if (!vt8500_rtc->regbase) {
 	if (!vt8500_rtc->regbase) {
 		dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
 		dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
 		ret = -EBUSY;
 		ret = -EBUSY;
-		goto err_release;
+		goto err_return;
 	}
 	}
 
 
 	/* Enable RTC and set it to 24-hour mode */
 	/* 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);
 		ret = PTR_ERR(vt8500_rtc->rtc);
 		dev_err(&pdev->dev,
 		dev_err(&pdev->dev,
 			"Failed to register RTC device -> %d\n", ret);
 			"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) {
 	if (ret < 0) {
 		dev_err(&pdev->dev, "can't get irq %i, err %d\n",
 		dev_err(&pdev->dev, "can't get irq %i, err %d\n",
 			vt8500_rtc->irq_alarm, ret);
 			vt8500_rtc->irq_alarm, ret);
@@ -272,11 +273,7 @@ static int vt8500_rtc_probe(struct platform_device *pdev)
 
 
 err_unreg:
 err_unreg:
 	rtc_device_unregister(vt8500_rtc->rtc);
 	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;
 	return ret;
 }
 }
 
 
@@ -284,15 +281,10 @@ static int vt8500_rtc_remove(struct platform_device *pdev)
 {
 {
 	struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
 	struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
 
 
-	free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
-
 	rtc_device_unregister(vt8500_rtc->rtc);
 	rtc_device_unregister(vt8500_rtc->rtc);
 
 
 	/* Disable alarm matching */
 	/* Disable alarm matching */
 	writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
 	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);
 	platform_set_drvdata(pdev, NULL);
 
 

+ 4 - 5
drivers/rtc/rtc-wm831x.c

@@ -443,9 +443,10 @@ static int wm831x_rtc_probe(struct platform_device *pdev)
 		goto err;
 		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) {
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
 		dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
 			alm_irq, ret);
 			alm_irq, ret);
@@ -462,9 +463,7 @@ err:
 static int wm831x_rtc_remove(struct platform_device *pdev)
 static int wm831x_rtc_remove(struct platform_device *pdev)
 {
 {
 	struct wm831x_rtc *wm831x_rtc = platform_get_drvdata(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);
 	rtc_device_unregister(wm831x_rtc->rtc);
 
 
 	return 0;
 	return 0;

+ 13 - 2
drivers/video/Kconfig

@@ -364,7 +364,7 @@ config FB_SA1100
 	  Y here.
 	  Y here.
 
 
 config FB_IMX
 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
 	depends on FB && IMX_HAVE_PLATFORM_IMX_FB
 	select FB_CFB_FILLRECT
 	select FB_CFB_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_COPYAREA
@@ -2025,7 +2025,8 @@ config FB_TMIO_ACCELL
 
 
 config FB_S3C
 config FB_S3C
 	tristate "Samsung S3C framebuffer support"
 	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_FILLRECT
 	select FB_CFB_COPYAREA
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select FB_CFB_IMAGEBLIT
@@ -2183,6 +2184,15 @@ config FB_XILINX
 	  framebuffer. ML300 carries a 640*480 LCD display on the board,
 	  framebuffer. ML300 carries a 640*480 LCD display on the board,
 	  ML403 uses a standard DB15 VGA connector.
 	  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
 config FB_COBALT
 	tristate "Cobalt server LCD frame buffer support"
 	tristate "Cobalt server LCD frame buffer support"
 	depends on FB && (MIPS_COBALT || MIPS_SEAD3)
 	depends on FB && (MIPS_COBALT || MIPS_SEAD3)
@@ -2422,6 +2432,7 @@ config FB_PUV3_UNIGFX
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 source "drivers/video/omap2/Kconfig"
 source "drivers/video/exynos/Kconfig"
 source "drivers/video/exynos/Kconfig"
+source "drivers/video/mmp/Kconfig"
 source "drivers/video/backlight/Kconfig"
 source "drivers/video/backlight/Kconfig"
 
 
 if VT
 if VT

+ 2 - 0
drivers/video/Makefile

@@ -98,6 +98,7 @@ obj-$(CONFIG_FB_ATMEL)		  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
 obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
+obj-$(CONFIG_FB_GOLDFISH)         += goldfishfb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
 obj-$(CONFIG_FB_68328)            += 68328fb.o
 obj-$(CONFIG_FB_GBE)              += gbefb.o
 obj-$(CONFIG_FB_GBE)              += gbefb.o
 obj-$(CONFIG_FB_CIRRUS)		  += cirrusfb.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_PXA)		  += pxafb.o
 obj-$(CONFIG_FB_PXA168)		  += pxa168fb.o
 obj-$(CONFIG_FB_PXA168)		  += pxa168fb.o
 obj-$(CONFIG_PXA3XX_GCU)	  += pxa3xx-gcu.o
 obj-$(CONFIG_PXA3XX_GCU)	  += pxa3xx-gcu.o
+obj-$(CONFIG_MMP_DISP)           += mmp/
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_W100)		  += w100fb.o
 obj-$(CONFIG_FB_TMIO)		  += tmiofb.o
 obj-$(CONFIG_FB_TMIO)		  += tmiofb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o
 obj-$(CONFIG_FB_AU1100)		  += au1100fb.o

+ 4 - 1
drivers/video/backlight/88pm860x_bl.c

@@ -165,8 +165,10 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev,
 				    struct pm860x_backlight_data *data,
 				    struct pm860x_backlight_data *data,
 				    char *name)
 				    char *name)
 {
 {
-	struct device_node *nproot = pdev->dev.parent->of_node, *np;
+	struct device_node *nproot, *np;
 	int iset = 0;
 	int iset = 0;
+
+	nproot = of_node_get(pdev->dev.parent->of_node);
 	if (!nproot)
 	if (!nproot)
 		return -ENODEV;
 		return -ENODEV;
 	nproot = of_find_node_by_name(nproot, "backlights");
 	nproot = of_find_node_by_name(nproot, "backlights");
@@ -184,6 +186,7 @@ static int pm860x_backlight_dt_init(struct platform_device *pdev,
 			break;
 			break;
 		}
 		}
 	}
 	}
+	of_node_put(nproot);
 	return 0;
 	return 0;
 }
 }
 #else
 #else

+ 23 - 1
drivers/video/backlight/Kconfig

@@ -126,6 +126,21 @@ config LCD_AMS369FG06
 	  If you have an AMS369FG06 AMOLED Panel, say Y to enable its
 	  If you have an AMS369FG06 AMOLED Panel, say Y to enable its
 	  LCD control driver.
 	  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
 endif # LCD_CLASS_DEVICE
 
 
 #
 #
@@ -366,7 +381,7 @@ config BACKLIGHT_LP855X
 	tristate "Backlight driver for TI LP855X"
 	tristate "Backlight driver for TI LP855X"
 	depends on BACKLIGHT_CLASS_DEVICE && I2C
 	depends on BACKLIGHT_CLASS_DEVICE && I2C
 	help
 	help
-	  This supports TI LP8550, LP8551, LP8552, LP8553 and LP8556
+	  This supports TI LP8550, LP8551, LP8552, LP8553, LP8556 and LP8557
 	  backlight driver.
 	  backlight driver.
 
 
 config BACKLIGHT_OT200
 config BACKLIGHT_OT200
@@ -390,6 +405,13 @@ config BACKLIGHT_TPS65217
 	  If you have a Texas Instruments TPS65217 say Y to enable the
 	  If you have a Texas Instruments TPS65217 say Y to enable the
 	  backlight driver.
 	  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_CLASS_DEVICE
 
 
 endif # BACKLIGHT_LCD_SUPPORT
 endif # BACKLIGHT_LCD_SUPPORT

+ 46 - 43
drivers/video/backlight/Makefile

@@ -1,47 +1,50 @@
 # Backlight & LCD drivers
 # 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_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

+ 1 - 1
drivers/video/backlight/aat2870_bl.c

@@ -74,7 +74,7 @@ static int aat2870_bl_get_brightness(struct backlight_device *bd)
 
 
 static int aat2870_bl_update_status(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 =
 	struct aat2870_data *aat2870 =
 			dev_get_drvdata(aat2870_bl->pdev->dev.parent);
 			dev_get_drvdata(aat2870_bl->pdev->dev.parent);
 	int brightness = bd->props.brightness;
 	int brightness = bd->props.brightness;

+ 1 - 1
drivers/video/backlight/adp8860_bl.c

@@ -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)
 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;
 	return 0;
 }
 }

+ 1 - 1
drivers/video/backlight/adp8870_bl.c

@@ -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)
 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;
 	return 0;
 }
 }

+ 31 - 73
drivers/video/backlight/ams369fg06.c

@@ -10,25 +10,16 @@
  * under the terms of the GNU General Public License as published by the
  * 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
  * Free Software Foundation; either version 2 of the License, or (at your
  * option) any later version.
  * 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/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
 #include <linux/lcd.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 SLEEPMSEC		0x1000
 #define ENDDEF			0x2000
 #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]);
 			ret = ams369fg06_spi_write(lcd, wbuf[i], wbuf[i+1]);
 			if (ret)
 			if (ret)
 				break;
 				break;
-		} else
-			mdelay(wbuf[i+1]);
+		} else {
+			msleep(wbuf[i+1]);
+		}
 		i += 2;
 		i += 2;
 	}
 	}
 
 
@@ -313,41 +305,32 @@ static int ams369fg06_ldi_disable(struct ams369fg06 *lcd)
 
 
 static int ams369fg06_power_is_on(int power)
 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)
 static int ams369fg06_power_on(struct ams369fg06 *lcd)
 {
 {
 	int ret = 0;
 	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;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL.\n");
-		return -EFAULT;
-	}
-
 	bd = lcd->bd;
 	bd = lcd->bd;
-	if (!bd) {
-		dev_err(lcd->dev, "backlight device is NULL.\n");
-		return -EFAULT;
-	}
 
 
 	if (!pd->power_on) {
 	if (!pd->power_on) {
 		dev_err(lcd->dev, "power_on is NULL.\n");
 		dev_err(lcd->dev, "power_on is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	} else {
 	} else {
 		pd->power_on(lcd->ld, 1);
 		pd->power_on(lcd->ld, 1);
-		mdelay(pd->power_on_delay);
+		msleep(pd->power_on_delay);
 	}
 	}
 
 
 	if (!pd->reset) {
 	if (!pd->reset) {
 		dev_err(lcd->dev, "reset is NULL.\n");
 		dev_err(lcd->dev, "reset is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	} else {
 	} else {
 		pd->reset(lcd->ld);
 		pd->reset(lcd->ld);
-		mdelay(pd->reset_delay);
+		msleep(pd->reset_delay);
 	}
 	}
 
 
 	ret = ams369fg06_ldi_init(lcd);
 	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)
 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;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL\n");
-		return -EFAULT;
-	}
 
 
 	ret = ams369fg06_ldi_disable(lcd);
 	ret = ams369fg06_ldi_disable(lcd);
 	if (ret) {
 	if (ret) {
@@ -389,13 +368,9 @@ static int ams369fg06_power_off(struct ams369fg06 *lcd)
 		return -EIO;
 		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;
 	return 0;
 }
 }
@@ -446,7 +421,7 @@ static int ams369fg06_set_brightness(struct backlight_device *bd)
 {
 {
 	int ret = 0;
 	int ret = 0;
 	int brightness = bd->props.brightness;
 	int brightness = bd->props.brightness;
-	struct ams369fg06 *lcd = dev_get_drvdata(&bd->dev);
+	struct ams369fg06 *lcd = bl_get_data(bd);
 
 
 	if (brightness < MIN_BRIGHTNESS ||
 	if (brightness < MIN_BRIGHTNESS ||
 		brightness > bd->props.max_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;
 	lcd->lcd_pd = spi->dev.platform_data;
 	if (!lcd->lcd_pd) {
 	if (!lcd->lcd_pd) {
 		dev_err(&spi->dev, "platform data is NULL\n");
 		dev_err(&spi->dev, "platform data is NULL\n");
-		return -EFAULT;
+		return -EINVAL;
 	}
 	}
 
 
 	ld = lcd_device_register("ams369fg06", &spi->dev, lcd,
 	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;
 		lcd->power = FB_BLANK_POWERDOWN;
 
 
 		ams369fg06_power(lcd, FB_BLANK_UNBLANK);
 		ams369fg06_power(lcd, FB_BLANK_UNBLANK);
-	} else
+	} else {
 		lcd->power = FB_BLANK_UNBLANK;
 		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");
 	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)
 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);
 	ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
 	backlight_device_unregister(lcd->bd);
 	backlight_device_unregister(lcd->bd);
@@ -560,44 +536,26 @@ static int ams369fg06_remove(struct spi_device *spi)
 }
 }
 
 
 #if defined(CONFIG_PM)
 #if defined(CONFIG_PM)
-static unsigned int before_power;
-
 static int ams369fg06_suspend(struct spi_device *spi, pm_message_t mesg)
 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);
 	dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 
 
-	before_power = lcd->power;
-
 	/*
 	/*
 	 * when lcd panel is suspend, lcd panel becomes off
 	 * when lcd panel is suspend, lcd panel becomes off
 	 * regardless of status.
 	 * 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)
 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
 #else
 #define ams369fg06_suspend	NULL
 #define ams369fg06_suspend	NULL
@@ -606,7 +564,7 @@ static int ams369fg06_resume(struct spi_device *spi)
 
 
 static void ams369fg06_shutdown(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);
 	ams369fg06_power(lcd, FB_BLANK_POWERDOWN);
 }
 }

+ 380 - 0
drivers/video/backlight/as3711_bl.c

@@ -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");

+ 9 - 9
drivers/video/backlight/corgi_lcd.c

@@ -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)
 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;
 	int mode = CORGI_LCD_MODE_QVGA;
 
 
 	if (m->xres == 640 || m->xres == 480)
 	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)
 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))
 	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
 		corgi_lcd_power_on(lcd);
 		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)
 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;
 	return lcd->power;
 }
 }
@@ -391,7 +391,7 @@ static struct lcd_ops corgi_lcd_ops = {
 
 
 static int corgi_bl_get_intensity(struct backlight_device *bd)
 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;
 	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)
 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;
 	int intensity = bd->props.brightness;
 
 
 	if (bd->props.power != FB_BLANK_UNBLANK)
 	if (bd->props.power != FB_BLANK_UNBLANK)
@@ -460,7 +460,7 @@ static const struct backlight_ops corgi_bl_ops = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state)
 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;
 	corgibl_flags |= CORGIBL_SUSPENDED;
 	corgi_bl_set_intensity(lcd, 0);
 	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)
 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;
 	corgibl_flags &= ~CORGIBL_SUSPENDED;
 	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
 	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;
 	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);
 	corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK);
 	backlight_update_status(lcd->bl_dev);
 	backlight_update_status(lcd->bl_dev);
 
 
@@ -594,7 +594,7 @@ err_unregister_lcd:
 
 
 static int corgi_lcd_remove(struct spi_device *spi)
 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.power = FB_BLANK_UNBLANK;
 	lcd->bl_dev->props.brightness = 0;
 	lcd->bl_dev->props.brightness = 0;

+ 497 - 0
drivers/video/backlight/hx8357.c

@@ -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");

+ 11 - 25
drivers/video/backlight/l4f00242t03.c

@@ -49,7 +49,7 @@ static void l4f00242t03_reset(unsigned int gpio)
 static void l4f00242t03_lcd_init(struct spi_device *spi)
 static void l4f00242t03_lcd_init(struct spi_device *spi)
 {
 {
 	struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
 	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) };
 	const u16 cmd[] = { 0x36, param(0), 0x3A, param(0x60) };
 
 
 	dev_dbg(&spi->dev, "initializing LCD\n");
 	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)
 static void l4f00242t03_lcd_powerdown(struct spi_device *spi)
 {
 {
 	struct l4f00242t03_pdata *pdata = spi->dev.platform_data;
 	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");
 	dev_dbg(&spi->dev, "Powering down LCD\n");
 
 
@@ -168,7 +168,7 @@ static int l4f00242t03_probe(struct spi_device *spi)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	dev_set_drvdata(&spi->dev, priv);
+	spi_set_drvdata(spi, priv);
 	spi->bits_per_word = 9;
 	spi->bits_per_word = 9;
 	spi_setup(spi);
 	spi_setup(spi);
 
 
@@ -190,27 +190,24 @@ static int l4f00242t03_probe(struct spi_device *spi)
 		return ret;
 		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)) {
 	if (IS_ERR(priv->io_reg)) {
 		dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
 		dev_err(&spi->dev, "%s: Unable to get the IO regulator\n",
 		       __func__);
 		       __func__);
 		return PTR_ERR(priv->io_reg);
 		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)) {
 	if (IS_ERR(priv->core_reg)) {
-		ret = PTR_ERR(priv->core_reg);
 		dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
 		dev_err(&spi->dev, "%s: Unable to get the core regulator\n",
 		       __func__);
 		       __func__);
-		goto err1;
+		return PTR_ERR(priv->core_reg);
 	}
 	}
 
 
 	priv->ld = lcd_device_register("l4f00242t03",
 	priv->ld = lcd_device_register("l4f00242t03",
 					&spi->dev, priv, &l4f_ops);
 					&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 */
 	/* Init the LCD */
 	l4f00242t03_lcd_init(spi);
 	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");
 	dev_info(&spi->dev, "Epson l4f00242t03 lcd probed.\n");
 
 
 	return 0;
 	return 0;
-
-err2:
-	regulator_put(priv->core_reg);
-err1:
-	regulator_put(priv->io_reg);
-
-	return ret;
 }
 }
 
 
 static int l4f00242t03_remove(struct spi_device *spi)
 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);
 	l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
 	lcd_device_unregister(priv->ld);
 	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;
 	return 0;
 }
 }
 
 
 static void l4f00242t03_shutdown(struct spi_device *spi)
 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)
 	if (priv)
 		l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);
 		l4f00242t03_lcd_power_set(priv->ld, FB_BLANK_POWERDOWN);

+ 39 - 70
drivers/video/backlight/ld9040.c

@@ -9,29 +9,20 @@
  * under the terms of the GNU General Public License as published by the
  * 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
  * Free Software Foundation; either version 2 of the License, or (at your
  * option) any later version.
  * 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/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/lcd.h>
 #include <linux/lcd.h>
-#include <linux/backlight.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
 
 
 #include "ld9040_gamma.h"
 #include "ld9040_gamma.h"
 
 
@@ -43,7 +34,6 @@
 
 
 #define MIN_BRIGHTNESS		0
 #define MIN_BRIGHTNESS		0
 #define MAX_BRIGHTNESS		24
 #define MAX_BRIGHTNESS		24
-#define power_is_on(pwr)	((pwr) <= FB_BLANK_NORMAL)
 
 
 struct ld9040 {
 struct ld9040 {
 	struct device			*dev;
 	struct device			*dev;
@@ -78,7 +68,7 @@ static void ld9040_regulator_enable(struct ld9040 *lcd)
 
 
 		lcd->enabled = true;
 		lcd->enabled = true;
 	}
 	}
-	mdelay(pd->power_on_delay);
+	msleep(pd->power_on_delay);
 out:
 out:
 	mutex_unlock(&lcd->lock);
 	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]);
 			ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
 			if (ret)
 			if (ret)
 				break;
 				break;
-		} else
-			udelay(wbuf[i+1]*1000);
+		} else {
+			msleep(wbuf[i+1]);
+		}
 		i += 2;
 		i += 2;
 	}
 	}
 
 
@@ -513,14 +504,9 @@ gamma_err:
 
 
 static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
 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)
 static int ld9040_ldi_init(struct ld9040 *lcd)
 {
 {
 	int ret, i;
 	int ret, i;
@@ -539,7 +525,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd)
 	for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
 	for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
 		ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
 		ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
 		/* workaround: minimum delay time for transferring CMD */
 		/* workaround: minimum delay time for transferring CMD */
-		udelay(300);
+		usleep_range(300, 310);
 		if (ret)
 		if (ret)
 			break;
 			break;
 	}
 	}
@@ -549,11 +535,7 @@ static int ld9040_ldi_init(struct ld9040 *lcd)
 
 
 static int ld9040_ldi_enable(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)
 static int ld9040_ldi_disable(struct ld9040 *lcd)
@@ -566,25 +548,27 @@ static int ld9040_ldi_disable(struct ld9040 *lcd)
 	return ret;
 	return ret;
 }
 }
 
 
+static int ld9040_power_is_on(int power)
+{
+	return power <= FB_BLANK_NORMAL;
+}
+
 static int ld9040_power_on(struct ld9040 *lcd)
 static int ld9040_power_on(struct ld9040 *lcd)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	struct lcd_platform_data *pd = NULL;
+	struct lcd_platform_data *pd;
+
 	pd = lcd->lcd_pd;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL.\n");
-		return -EFAULT;
-	}
 
 
 	/* lcd power on */
 	/* lcd power on */
 	ld9040_regulator_enable(lcd);
 	ld9040_regulator_enable(lcd);
 
 
 	if (!pd->reset) {
 	if (!pd->reset) {
 		dev_err(lcd->dev, "reset is NULL.\n");
 		dev_err(lcd->dev, "reset is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	} else {
 	} else {
 		pd->reset(lcd->ld);
 		pd->reset(lcd->ld);
-		mdelay(pd->reset_delay);
+		msleep(pd->reset_delay);
 	}
 	}
 
 
 	ret = ld9040_ldi_init(lcd);
 	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)
 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;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL.\n");
-		return -EFAULT;
-	}
 
 
 	ret = ld9040_ldi_disable(lcd);
 	ret = ld9040_ldi_disable(lcd);
 	if (ret) {
 	if (ret) {
@@ -619,7 +599,7 @@ static int ld9040_power_off(struct ld9040 *lcd)
 		return -EIO;
 		return -EIO;
 	}
 	}
 
 
-	mdelay(pd->power_off_delay);
+	msleep(pd->power_off_delay);
 
 
 	/* lcd power off */
 	/* lcd power off */
 	ld9040_regulator_disable(lcd);
 	ld9040_regulator_disable(lcd);
@@ -631,9 +611,9 @@ static int ld9040_power(struct ld9040 *lcd, int power)
 {
 {
 	int ret = 0;
 	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);
 		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);
 		ret = ld9040_power_off(lcd);
 
 
 	if (!ret)
 	if (!ret)
@@ -698,7 +678,6 @@ static const struct backlight_ops ld9040_backlight_ops  = {
 	.update_status = ld9040_set_brightness,
 	.update_status = ld9040_set_brightness,
 };
 };
 
 
-
 static int ld9040_probe(struct spi_device *spi)
 static int ld9040_probe(struct spi_device *spi)
 {
 {
 	int ret = 0;
 	int ret = 0;
@@ -726,22 +705,20 @@ static int ld9040_probe(struct spi_device *spi)
 	lcd->lcd_pd = spi->dev.platform_data;
 	lcd->lcd_pd = spi->dev.platform_data;
 	if (!lcd->lcd_pd) {
 	if (!lcd->lcd_pd) {
 		dev_err(&spi->dev, "platform data is NULL.\n");
 		dev_err(&spi->dev, "platform data is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	}
 	}
 
 
 	mutex_init(&lcd->lock);
 	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) {
 	if (ret) {
 		dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
 		dev_err(lcd->dev, "Failed to get regulators: %d\n", ret);
 		return ret;
 		return ret;
 	}
 	}
 
 
 	ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
 	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;
 	lcd->ld = ld;
 
 
@@ -772,30 +749,28 @@ static int ld9040_probe(struct spi_device *spi)
 		lcd->power = FB_BLANK_POWERDOWN;
 		lcd->power = FB_BLANK_POWERDOWN;
 
 
 		ld9040_power(lcd, FB_BLANK_UNBLANK);
 		ld9040_power(lcd, FB_BLANK_UNBLANK);
-	} else
+	} else {
 		lcd->power = FB_BLANK_UNBLANK;
 		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");
 	dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
 	return 0;
 	return 0;
 
 
 out_unregister_lcd:
 out_unregister_lcd:
 	lcd_device_unregister(lcd->ld);
 	lcd_device_unregister(lcd->ld);
-out_free_regulator:
-	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
 static int ld9040_remove(struct spi_device *spi)
 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);
 	ld9040_power(lcd, FB_BLANK_POWERDOWN);
 	backlight_device_unregister(lcd->bd);
 	backlight_device_unregister(lcd->bd);
 	lcd_device_unregister(lcd->ld);
 	lcd_device_unregister(lcd->ld);
-	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -803,8 +778,7 @@ static int ld9040_remove(struct spi_device *spi)
 #if defined(CONFIG_PM)
 #if defined(CONFIG_PM)
 static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
 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);
 	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
 	 * when lcd panel is suspend, lcd panel becomes off
 	 * regardless of status.
 	 * 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)
 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;
 	lcd->power = FB_BLANK_POWERDOWN;
 
 
-	ret = ld9040_power(lcd, FB_BLANK_UNBLANK);
-
-	return ret;
+	return ld9040_power(lcd, FB_BLANK_UNBLANK);
 }
 }
 #else
 #else
 #define ld9040_suspend		NULL
 #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. */
 /* Power down all displays on reboot, poweroff or halt. */
 static void ld9040_shutdown(struct spi_device *spi)
 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);
 	ld9040_power(lcd, FB_BLANK_POWERDOWN);
 }
 }

+ 2 - 2
drivers/video/backlight/lm3630_bl.c

@@ -320,7 +320,7 @@ static int lm3630_backlight_register(struct lm3630_chip_data *pchip,
 		    backlight_device_register(name, pchip->dev, pchip,
 		    backlight_device_register(name, pchip->dev, pchip,
 					      &lm3630_bank_a_ops, &props);
 					      &lm3630_bank_a_ops, &props);
 		if (IS_ERR(pchip->bled1))
 		if (IS_ERR(pchip->bled1))
-			return -EIO;
+			return PTR_ERR(pchip->bled1);
 		break;
 		break;
 	case BLED_2:
 	case BLED_2:
 		props.brightness = pdata->init_brt_led2;
 		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,
 		    backlight_device_register(name, pchip->dev, pchip,
 					      &lm3630_bank_b_ops, &props);
 					      &lm3630_bank_b_ops, &props);
 		if (IS_ERR(pchip->bled2))
 		if (IS_ERR(pchip->bled2))
-			return -EIO;
+			return PTR_ERR(pchip->bled2);
 		break;
 		break;
 	}
 	}
 	return 0;
 	return 0;

+ 1 - 4
drivers/video/backlight/lm3639_bl.c

@@ -350,14 +350,13 @@ static int lm3639_probe(struct i2c_client *client,
 				      &lm3639_bled_ops, &props);
 				      &lm3639_bled_ops, &props);
 	if (IS_ERR(pchip->bled)) {
 	if (IS_ERR(pchip->bled)) {
 		dev_err(&client->dev, "fail : backlight register\n");
 		dev_err(&client->dev, "fail : backlight register\n");
-		ret = -EIO;
+		ret = PTR_ERR(pchip->bled);
 		goto err_out;
 		goto err_out;
 	}
 	}
 
 
 	ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
 	ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&client->dev, "failed : add sysfs entries\n");
 		dev_err(&client->dev, "failed : add sysfs entries\n");
-		ret = -EIO;
 		goto err_bled_mode;
 		goto err_bled_mode;
 	}
 	}
 
 
@@ -369,7 +368,6 @@ static int lm3639_probe(struct i2c_client *client,
 				    &client->dev, &pchip->cdev_flash);
 				    &client->dev, &pchip->cdev_flash);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&client->dev, "fail : flash register\n");
 		dev_err(&client->dev, "fail : flash register\n");
-		ret = -EIO;
 		goto err_flash;
 		goto err_flash;
 	}
 	}
 
 
@@ -381,7 +379,6 @@ static int lm3639_probe(struct i2c_client *client,
 				    &client->dev, &pchip->cdev_torch);
 				    &client->dev, &pchip->cdev_torch);
 	if (ret < 0) {
 	if (ret < 0) {
 		dev_err(&client->dev, "fail : torch register\n");
 		dev_err(&client->dev, "fail : torch register\n");
-		ret = -EIO;
 		goto err_torch;
 		goto err_torch;
 	}
 	}
 
 

+ 2 - 2
drivers/video/backlight/lms283gf05.c

@@ -180,7 +180,7 @@ static int lms283gf05_probe(struct spi_device *spi)
 	st->spi = spi;
 	st->spi = spi;
 	st->ld = ld;
 	st->ld = ld;
 
 
-	dev_set_drvdata(&spi->dev, st);
+	spi_set_drvdata(spi, st);
 
 
 	/* kick in the LCD */
 	/* kick in the LCD */
 	if (pdata)
 	if (pdata)
@@ -192,7 +192,7 @@ static int lms283gf05_probe(struct spi_device *spi)
 
 
 static int lms283gf05_remove(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);
 	lcd_device_unregister(st->ld);
 
 

+ 441 - 0
drivers/video/backlight/lms501kf03.c

@@ -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");

+ 130 - 39
drivers/video/backlight/lp855x_bl.c

@@ -17,21 +17,48 @@
 #include <linux/platform_data/lp855x.h>
 #include <linux/platform_data/lp855x.h>
 #include <linux/pwm.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 BUF_SIZE		20
 #define DEFAULT_BL_NAME		"lcd-backlight"
 #define DEFAULT_BL_NAME		"lcd-backlight"
 #define MAX_BRIGHTNESS		255
 #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 {
 struct lp855x {
 	const char *chipname;
 	const char *chipname;
 	enum lp855x_chip_id chip_id;
 	enum lp855x_chip_id chip_id;
+	struct lp855x_device_config *cfg;
 	struct i2c_client *client;
 	struct i2c_client *client;
 	struct backlight_device *bl;
 	struct backlight_device *bl;
 	struct device *dev;
 	struct device *dev;
@@ -39,9 +66,15 @@ struct lp855x {
 	struct pwm_device *pwm;
 	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;
 	int ret;
+	u8 tmp;
 
 
 	ret = i2c_smbus_read_byte_data(lp->client, reg);
 	ret = i2c_smbus_read_byte_data(lp->client, reg);
 	if (ret < 0) {
 	if (ret < 0) {
@@ -49,13 +82,11 @@ static int lp855x_read_byte(struct lp855x *lp, u8 reg, u8 *data)
 		return ret;
 		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)
 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 LP8551:
 	case LP8552:
 	case LP8552:
 	case LP8553:
 	case LP8553:
-		start = EEPROM_START;
-		end = EEPROM_END;
+		start = LP855X_EEPROM_START;
+		end = LP855X_EEPROM_END;
 		break;
 		break;
 	case LP8556:
 	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;
 		break;
 	default:
 	default:
 		return false;
 		return false;
@@ -81,21 +116,76 @@ static bool lp855x_is_valid_rom_area(struct lp855x *lp, u8 addr)
 	return (addr >= start && addr <= end);
 	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;
 	u8 val, addr;
 	int i, ret;
 	int i, ret;
 	struct lp855x_platform_data *pd = lp->pdata;
 	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;
 	val = pd->initial_brightness;
-	ret = lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+	ret = lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
 	if (ret)
 	if (ret)
-		return ret;
+		goto err;
 
 
 	val = pd->device_control;
 	val = pd->device_control;
-	ret = lp855x_write_byte(lp, DEVICE_CTRL, val);
+	ret = lp855x_write_byte(lp, lp->cfg->reg_devicectrl, val);
 	if (ret)
 	if (ret)
-		return ret;
+		goto err;
 
 
 	if (pd->load_new_rom_data && pd->size_program) {
 	if (pd->load_new_rom_data && pd->size_program) {
 		for (i = 0; i < pd->size_program; i++) {
 		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);
 			ret = lp855x_write_byte(lp, addr, val);
 			if (ret)
 			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;
 	return ret;
 }
 }
 
 
@@ -151,7 +252,7 @@ static int lp855x_bl_update_status(struct backlight_device *bl)
 
 
 	} else if (mode == REGISTER_BASED) {
 	} else if (mode == REGISTER_BASED) {
 		u8 val = bl->props.brightness;
 		u8 val = bl->props.brightness;
-		lp855x_write_byte(lp, BRIGHTNESS_CTRL, val);
+		lp855x_write_byte(lp, lp->cfg->reg_brightness, val);
 	}
 	}
 
 
 	return 0;
 	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)
 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;
 	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;
 	lp->chip_id = id->driver_data;
 	i2c_set_clientdata(cl, lp);
 	i2c_set_clientdata(cl, lp);
 
 
-	ret = lp855x_init_registers(lp);
+	ret = lp855x_configure(lp);
 	if (ret) {
 	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);
 	ret = lp855x_backlight_register(lp);
@@ -318,6 +408,7 @@ static const struct i2c_device_id lp855x_ids[] = {
 	{"lp8552", LP8552},
 	{"lp8552", LP8552},
 	{"lp8553", LP8553},
 	{"lp8553", LP8553},
 	{"lp8556", LP8556},
 	{"lp8556", LP8556},
+	{"lp8557", LP8557},
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, lp855x_ids);
 MODULE_DEVICE_TABLE(i2c, lp855x_ids);

+ 5 - 5
drivers/video/backlight/ltv350qv.c

@@ -252,7 +252,7 @@ static int ltv350qv_probe(struct spi_device *spi)
 	if (ret)
 	if (ret)
 		goto out_unregister;
 		goto out_unregister;
 
 
-	dev_set_drvdata(&spi->dev, lcd);
+	spi_set_drvdata(spi, lcd);
 
 
 	return 0;
 	return 0;
 
 
@@ -263,7 +263,7 @@ out_unregister:
 
 
 static int ltv350qv_remove(struct spi_device *spi)
 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);
 	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
 	lcd_device_unregister(lcd->ld);
 	lcd_device_unregister(lcd->ld);
@@ -274,14 +274,14 @@ static int ltv350qv_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
 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);
 	return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
 }
 }
 
 
 static int ltv350qv_resume(struct spi_device *spi)
 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);
 	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 */
 /* Power down all displays on reboot, poweroff or halt */
 static void ltv350qv_shutdown(struct spi_device *spi)
 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);
 	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
 }
 }

+ 5 - 5
drivers/video/backlight/omap1_bl.c

@@ -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)
 static int omapbl_suspend(struct platform_device *pdev, pm_message_t state)
 {
 {
 	struct backlight_device *dev = platform_get_drvdata(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, FB_BLANK_POWERDOWN);
 	omapbl_blank(bl, FB_BLANK_POWERDOWN);
 	return 0;
 	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)
 static int omapbl_resume(struct platform_device *pdev)
 {
 {
 	struct backlight_device *dev = platform_get_drvdata(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);
 	omapbl_blank(bl, bl->powermode);
 	return 0;
 	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)
 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);
 	omapbl_blank(bl, state);
 	bl->powermode = 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)
 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->current_intensity != dev->props.brightness) {
 		if (bl->powermode == FB_BLANK_UNBLANK)
 		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)
 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;
 	return bl->current_intensity;
 }
 }
 
 

+ 4 - 4
drivers/video/backlight/pwm_bl.c

@@ -37,7 +37,7 @@ struct pwm_bl_data {
 
 
 static int pwm_backlight_update_status(struct backlight_device *bl)
 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 brightness = bl->props.brightness;
 	int max = bl->props.max_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,
 static int pwm_backlight_check_fb(struct backlight_device *bl,
 				  struct fb_info *info)
 				  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);
 	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)
 static int pwm_backlight_remove(struct platform_device *pdev)
 {
 {
 	struct backlight_device *bl = platform_get_drvdata(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);
 	backlight_device_unregister(bl);
 	pwm_config(pb->pwm, 0, pb->period);
 	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)
 static int pwm_backlight_suspend(struct device *dev)
 {
 {
 	struct backlight_device *bl = dev_get_drvdata(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)
 	if (pb->notify)
 		pb->notify(pb->dev, 0);
 		pb->notify(pb->dev, 0);

+ 57 - 96
drivers/video/backlight/s6e63m0.c

@@ -9,28 +9,19 @@
  * under the terms of the GNU General Public License as published by the
  * 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
  * Free Software Foundation; either version 2 of the License, or (at your
  * option) any later version.
  * 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/delay.h>
+#include <linux/fb.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/lcd.h>
 #include <linux/lcd.h>
-#include <linux/backlight.h>
 #include <linux/module.h>
 #include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/wait.h>
 
 
 #include "s6e63m0_gamma.h"
 #include "s6e63m0_gamma.h"
 
 
@@ -43,8 +34,6 @@
 #define MIN_BRIGHTNESS		0
 #define MIN_BRIGHTNESS		0
 #define MAX_BRIGHTNESS		10
 #define MAX_BRIGHTNESS		10
 
 
-#define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
-
 struct s6e63m0 {
 struct s6e63m0 {
 	struct device			*dev;
 	struct device			*dev;
 	struct spi_device		*spi;
 	struct spi_device		*spi;
@@ -57,7 +46,7 @@ struct s6e63m0 {
 	struct lcd_platform_data	*lcd_pd;
 	struct lcd_platform_data	*lcd_pd;
 };
 };
 
 
-static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
+static const unsigned short seq_panel_condition_set[] = {
 	0xF8, 0x01,
 	0xF8, 0x01,
 	DATA_ONLY, 0x27,
 	DATA_ONLY, 0x27,
 	DATA_ONLY, 0x27,
 	DATA_ONLY, 0x27,
@@ -76,7 +65,7 @@ static const unsigned short SEQ_PANEL_CONDITION_SET[] = {
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
+static const unsigned short seq_display_condition_set[] = {
 	0xf2, 0x02,
 	0xf2, 0x02,
 	DATA_ONLY, 0x03,
 	DATA_ONLY, 0x03,
 	DATA_ONLY, 0x1c,
 	DATA_ONLY, 0x1c,
@@ -90,7 +79,7 @@ static const unsigned short SEQ_DISPLAY_CONDITION_SET[] = {
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_GAMMA_SETTING[] = {
+static const unsigned short seq_gamma_setting[] = {
 	0xfa, 0x00,
 	0xfa, 0x00,
 	DATA_ONLY, 0x18,
 	DATA_ONLY, 0x18,
 	DATA_ONLY, 0x08,
 	DATA_ONLY, 0x08,
@@ -119,7 +108,7 @@ static const unsigned short SEQ_GAMMA_SETTING[] = {
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_ETC_CONDITION_SET[] = {
+static const unsigned short seq_etc_condition_set[] = {
 	0xf6, 0x00,
 	0xf6, 0x00,
 	DATA_ONLY, 0x8c,
 	DATA_ONLY, 0x8c,
 	DATA_ONLY, 0x07,
 	DATA_ONLY, 0x07,
@@ -318,47 +307,47 @@ static const unsigned short SEQ_ETC_CONDITION_SET[] = {
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_ACL_ON[] = {
+static const unsigned short seq_acl_on[] = {
 	/* ACL on */
 	/* ACL on */
 	0xc0, 0x01,
 	0xc0, 0x01,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_ACL_OFF[] = {
+static const unsigned short seq_acl_off[] = {
 	/* ACL off */
 	/* ACL off */
 	0xc0, 0x00,
 	0xc0, 0x00,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_ELVSS_ON[] = {
+static const unsigned short seq_elvss_on[] = {
 	/* ELVSS on */
 	/* ELVSS on */
 	0xb1, 0x0b,
 	0xb1, 0x0b,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_ELVSS_OFF[] = {
+static const unsigned short seq_elvss_off[] = {
 	/* ELVSS off */
 	/* ELVSS off */
 	0xb1, 0x0a,
 	0xb1, 0x0a,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_STAND_BY_OFF[] = {
+static const unsigned short seq_stand_by_off[] = {
 	0x11, COMMAND_ONLY,
 	0x11, COMMAND_ONLY,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_STAND_BY_ON[] = {
+static const unsigned short seq_stand_by_on[] = {
 	0x10, COMMAND_ONLY,
 	0x10, COMMAND_ONLY,
 
 
 	ENDDEF, 0x0000
 	ENDDEF, 0x0000
 };
 };
 
 
-static const unsigned short SEQ_DISPLAY_ON[] = {
+static const unsigned short seq_display_on[] = {
 	0x29, COMMAND_ONLY,
 	0x29, COMMAND_ONLY,
 
 
 	ENDDEF, 0x0000
 	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]);
 			ret = s6e63m0_spi_write(lcd, wbuf[i], wbuf[i+1]);
 			if (ret)
 			if (ret)
 				break;
 				break;
-		} else
-			udelay(wbuf[i+1]*1000);
+		} else {
+			msleep(wbuf[i+1]);
+		}
 		i += 2;
 		i += 2;
 	}
 	}
 
 
@@ -457,12 +447,12 @@ static int s6e63m0_ldi_init(struct s6e63m0 *lcd)
 {
 {
 	int ret, i;
 	int ret, i;
 	const unsigned short *init_seq[] = {
 	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++) {
 	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;
 	int ret = 0, i;
 	const unsigned short *enable_seq[] = {
 	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++) {
 	for (i = 0; i < ARRAY_SIZE(enable_seq); i++) {
@@ -495,43 +485,39 @@ static int s6e63m0_ldi_disable(struct s6e63m0 *lcd)
 {
 {
 	int ret;
 	int ret;
 
 
-	ret = s6e63m0_panel_send_sequence(lcd, SEQ_STAND_BY_ON);
+	ret = s6e63m0_panel_send_sequence(lcd, seq_stand_by_on);
 
 
 	return ret;
 	return ret;
 }
 }
 
 
+static int s6e63m0_power_is_on(int power)
+{
+	return power <= FB_BLANK_NORMAL;
+}
+
 static int s6e63m0_power_on(struct s6e63m0 *lcd)
 static int s6e63m0_power_on(struct s6e63m0 *lcd)
 {
 {
 	int ret = 0;
 	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;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL.\n");
-		return -EFAULT;
-	}
-
 	bd = lcd->bd;
 	bd = lcd->bd;
-	if (!bd) {
-		dev_err(lcd->dev, "backlight device is NULL.\n");
-		return -EFAULT;
-	}
 
 
 	if (!pd->power_on) {
 	if (!pd->power_on) {
 		dev_err(lcd->dev, "power_on is NULL.\n");
 		dev_err(lcd->dev, "power_on is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	} else {
 	} else {
 		pd->power_on(lcd->ld, 1);
 		pd->power_on(lcd->ld, 1);
-		mdelay(pd->power_on_delay);
+		msleep(pd->power_on_delay);
 	}
 	}
 
 
 	if (!pd->reset) {
 	if (!pd->reset) {
 		dev_err(lcd->dev, "reset is NULL.\n");
 		dev_err(lcd->dev, "reset is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	} else {
 	} else {
 		pd->reset(lcd->ld);
 		pd->reset(lcd->ld);
-		mdelay(pd->reset_delay);
+		msleep(pd->reset_delay);
 	}
 	}
 
 
 	ret = s6e63m0_ldi_init(lcd);
 	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)
 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;
 	pd = lcd->lcd_pd;
-	if (!pd) {
-		dev_err(lcd->dev, "platform data is NULL.\n");
-		return -EFAULT;
-	}
 
 
 	ret = s6e63m0_ldi_disable(lcd);
 	ret = s6e63m0_ldi_disable(lcd);
 	if (ret) {
 	if (ret) {
@@ -573,13 +555,9 @@ static int s6e63m0_power_off(struct s6e63m0 *lcd)
 		return -EIO;
 		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;
 	return 0;
 }
 }
@@ -588,9 +566,9 @@ static int s6e63m0_power(struct s6e63m0 *lcd, int power)
 {
 {
 	int ret = 0;
 	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);
 		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);
 		ret = s6e63m0_power_off(lcd);
 
 
 	if (!ret)
 	if (!ret)
@@ -760,7 +738,7 @@ static int s6e63m0_probe(struct spi_device *spi)
 	lcd->lcd_pd = spi->dev.platform_data;
 	lcd->lcd_pd = spi->dev.platform_data;
 	if (!lcd->lcd_pd) {
 	if (!lcd->lcd_pd) {
 		dev_err(&spi->dev, "platform data is NULL.\n");
 		dev_err(&spi->dev, "platform data is NULL.\n");
-		return -EFAULT;
+		return -EINVAL;
 	}
 	}
 
 
 	ld = lcd_device_register("s6e63m0", &spi->dev, lcd, &s6e63m0_lcd_ops);
 	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.
 	 * know that.
 	 */
 	 */
 	lcd->gamma_table_count =
 	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);
 	ret = device_create_file(&(spi->dev), &dev_attr_gamma_mode);
 	if (ret < 0)
 	if (ret < 0)
@@ -811,10 +789,11 @@ static int s6e63m0_probe(struct spi_device *spi)
 		lcd->power = FB_BLANK_POWERDOWN;
 		lcd->power = FB_BLANK_POWERDOWN;
 
 
 		s6e63m0_power(lcd, FB_BLANK_UNBLANK);
 		s6e63m0_power(lcd, FB_BLANK_UNBLANK);
-	} else
+	} else {
 		lcd->power = FB_BLANK_UNBLANK;
 		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");
 	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)
 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);
 	s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
 	device_remove_file(&spi->dev, &dev_attr_gamma_table);
 	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)
 #if defined(CONFIG_PM)
-static unsigned int before_power;
-
 static int s6e63m0_suspend(struct spi_device *spi, pm_message_t mesg)
 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);
 	dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
 
 
-	before_power = lcd->power;
-
 	/*
 	/*
 	 * when lcd panel is suspend, lcd panel becomes off
 	 * when lcd panel is suspend, lcd panel becomes off
 	 * regardless of status.
 	 * 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)
 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
 #else
 #define s6e63m0_suspend		NULL
 #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. */
 /* Power down all displays on reboot, poweroff or halt. */
 static void s6e63m0_shutdown(struct spi_device *spi)
 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);
 	s6e63m0_power(lcd, FB_BLANK_POWERDOWN);
 }
 }

+ 5 - 5
drivers/video/backlight/tdo24m.c

@@ -390,7 +390,7 @@ static int tdo24m_probe(struct spi_device *spi)
 	if (IS_ERR(lcd->lcd_dev))
 	if (IS_ERR(lcd->lcd_dev))
 		return PTR_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);
 	err = tdo24m_power(lcd, FB_BLANK_UNBLANK);
 	if (err)
 	if (err)
 		goto out_unregister;
 		goto out_unregister;
@@ -404,7 +404,7 @@ out_unregister:
 
 
 static int tdo24m_remove(struct spi_device *spi)
 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);
 	tdo24m_power(lcd, FB_BLANK_POWERDOWN);
 	lcd_device_unregister(lcd->lcd_dev);
 	lcd_device_unregister(lcd->lcd_dev);
@@ -415,14 +415,14 @@ static int tdo24m_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int tdo24m_suspend(struct spi_device *spi, pm_message_t state)
 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);
 	return tdo24m_power(lcd, FB_BLANK_POWERDOWN);
 }
 }
 
 
 static int tdo24m_resume(struct spi_device *spi)
 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);
 	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 */
 /* Power down all displays on reboot, poweroff or halt */
 static void tdo24m_shutdown(struct spi_device *spi)
 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);
 	tdo24m_power(lcd, FB_BLANK_POWERDOWN);
 }
 }

+ 1 - 1
drivers/video/backlight/tosa_bl.c

@@ -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)
 static int tosa_bl_update_status(struct backlight_device *dev)
 {
 {
 	struct backlight_properties *props = &dev->props;
 	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 power = max(props->power, props->fb_blank);
 	int brightness = props->brightness;
 	int brightness = props->brightness;
 
 

+ 6 - 6
drivers/video/backlight/tosa_lcd.c

@@ -193,7 +193,7 @@ static int tosa_lcd_probe(struct spi_device *spi)
 		return ret;
 		return ret;
 
 
 	data->spi = spi;
 	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,
 	ret = devm_gpio_request_one(&spi->dev, TOSA_GPIO_TG_ON,
 				GPIOF_OUT_INIT_LOW, "tg #pwr");
 				GPIOF_OUT_INIT_LOW, "tg #pwr");
@@ -220,13 +220,13 @@ static int tosa_lcd_probe(struct spi_device *spi)
 err_register:
 err_register:
 	tosa_lcd_tg_off(data);
 	tosa_lcd_tg_off(data);
 err_gpio_tg:
 err_gpio_tg:
-	dev_set_drvdata(&spi->dev, NULL);
+	spi_set_drvdata(spi, NULL);
 	return ret;
 	return ret;
 }
 }
 
 
 static int tosa_lcd_remove(struct spi_device *spi)
 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);
 	lcd_device_unregister(data->lcd);
 
 
@@ -235,7 +235,7 @@ static int tosa_lcd_remove(struct spi_device *spi)
 
 
 	tosa_lcd_tg_off(data);
 	tosa_lcd_tg_off(data);
 
 
-	dev_set_drvdata(&spi->dev, NULL);
+	spi_set_drvdata(spi, NULL);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -243,7 +243,7 @@ static int tosa_lcd_remove(struct spi_device *spi)
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int tosa_lcd_suspend(struct spi_device *spi, pm_message_t state)
 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);
 	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)
 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);
 	tosa_lcd_tg_init(data);
 	if (POWER_IS_ON(data->lcd_power))
 	if (POWER_IS_ON(data->lcd_power))

+ 4 - 5
drivers/video/backlight/vgg2432a4.c

@@ -208,12 +208,11 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd,
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int vgg2432a4_suspend(struct spi_device *spi, pm_message_t state)
 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)
 static int vgg2432a4_resume(struct spi_device *spi)
 {
 {
-	return ili9320_resume(dev_get_drvdata(&spi->dev));
+	return ili9320_resume(spi_get_drvdata(spi));
 }
 }
 #else
 #else
 #define vgg2432a4_suspend	NULL
 #define vgg2432a4_suspend	NULL
@@ -242,12 +241,12 @@ static int vgg2432a4_probe(struct spi_device *spi)
 
 
 static int vgg2432a4_remove(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)
 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 = {
 static struct spi_driver vgg2432a4_driver = {

+ 9 - 1
drivers/video/console/fbcon.c

@@ -1242,8 +1242,16 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
 	if (!height || !width)
 	if (!height || !width)
 		return;
 		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;
 		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 */
 	/* Split blits that cross physical y_wrap boundary */
 
 

+ 15 - 8
drivers/video/exynos/exynos_dp_core.c

@@ -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)
 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;
 	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) {
 	if (!dp_phy_node) {
 		dev_err(dp->dev, "could not find dptx-phy node\n");
 		dev_err(dp->dev, "could not find dptx-phy node\n");
 		return -ENODEV;
 		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)) {
 	if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
 		dev_err(dp->dev, "faild to get reg for dptx-phy\n");
 		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",
 	if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
 				&dp->enable_mask)) {
 				&dp->enable_mask)) {
 		dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n");
 		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);
 	dp->phy_addr = ioremap(phy_base, SZ_4);
 	if (!dp->phy_addr) {
 	if (!dp->phy_addr) {
 		dev_err(dp->dev, "failed to ioremap dp-phy\n");
 		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)
 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_platdata *pdata = pdev->dev.platform_data;
 	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
 
-	disable_irq(dp->irq);
-
 	flush_work(&dp->hotplug_work);
 	flush_work(&dp->hotplug_work);
 
 
 	if (pdev->dev.of_node) {
 	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_platdata *pdata = dev->platform_data;
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
 
+	disable_irq(dp->irq);
+
 	flush_work(&dp->hotplug_work);
 	flush_work(&dp->hotplug_work);
 
 
 	if (dev->of_node) {
 	if (dev->of_node) {

+ 18 - 52
drivers/video/exynos/exynos_mipi_dsi.c

@@ -338,7 +338,8 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	struct mipi_dsim_ddi *dsim_ddi;
 	struct mipi_dsim_ddi *dsim_ddi;
 	int ret = -EINVAL;
 	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) {
 	if (!dsim) {
 		dev_err(&pdev->dev, "failed to allocate dsim object.\n");
 		dev_err(&pdev->dev, "failed to allocate dsim object.\n");
 		return -ENOMEM;
 		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;
 	dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
 	if (dsim_pd == NULL) {
 	if (dsim_pd == NULL) {
 		dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
 		dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
-		goto err_clock_get;
+		return -EINVAL;
 	}
 	}
 	/* get mipi_dsim_config. */
 	/* get mipi_dsim_config. */
 	dsim_config = dsim_pd->dsim_config;
 	dsim_config = dsim_pd->dsim_config;
 	if (dsim_config == NULL) {
 	if (dsim_config == NULL) {
 		dev_err(&pdev->dev, "failed to get dsim config data.\n");
 		dev_err(&pdev->dev, "failed to get dsim config data.\n");
-		goto err_clock_get;
+		return -EINVAL;
 	}
 	}
 
 
 	dsim->dsim_config = dsim_config;
 	dsim->dsim_config = dsim_config;
@@ -366,41 +367,28 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 
 
 	mutex_init(&dsim->lock);
 	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) {
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to get regulators: %d\n", 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)) {
 	if (IS_ERR(dsim->clock)) {
 		dev_err(&pdev->dev, "failed to get dsim clock source\n");
 		dev_err(&pdev->dev, "failed to get dsim clock source\n");
-		ret = -ENODEV;
-		goto err_clock_get;
+		return -ENODEV;
 	}
 	}
 
 
 	clk_enable(dsim->clock);
 	clk_enable(dsim->clock);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	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) {
 	if (!dsim->reg_base) {
 		dev_err(&pdev->dev, "failed to remap io region\n");
 		dev_err(&pdev->dev, "failed to remap io region\n");
 		ret = -ENOMEM;
 		ret = -ENOMEM;
-		goto err_ioremap;
+		goto error;
 	}
 	}
 
 
 	mutex_init(&dsim->lock);
 	mutex_init(&dsim->lock);
@@ -410,26 +398,27 @@ static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 	if (!dsim_ddi) {
 	if (!dsim_ddi) {
 		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
 		dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
 		ret = -EINVAL;
 		ret = -EINVAL;
-		goto err_bind;
+		goto error;
 	}
 	}
 
 
 	dsim->irq = platform_get_irq(pdev, 0);
 	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");
 		dev_err(&pdev->dev, "failed to request dsim irq resource\n");
 		ret = -EINVAL;
 		ret = -EINVAL;
-		goto err_platform_get_irq;
+		goto error;
 	}
 	}
 
 
 	init_completion(&dsim_wr_comp);
 	init_completion(&dsim_wr_comp);
 	init_completion(&dsim_rd_comp);
 	init_completion(&dsim_rd_comp);
 	platform_set_drvdata(pdev, dsim);
 	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);
 			IRQF_SHARED, dev_name(&pdev->dev), dsim);
 	if (ret != 0) {
 	if (ret != 0) {
 		dev_err(&pdev->dev, "failed to request dsim irq\n");
 		dev_err(&pdev->dev, "failed to request dsim irq\n");
 		ret = -EINVAL;
 		ret = -EINVAL;
-		goto err_bind;
+		goto error;
 	}
 	}
 
 
 	/* enable interrupts */
 	/* enable interrupts */
@@ -471,22 +460,8 @@ done:
 
 
 	return 0;
 	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_disable(dsim->clock);
-	clk_put(dsim->clock);
-err_clock_get:
-	kfree(dsim);
-
-err_platform_get_irq:
 	return ret;
 	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_ddi *dsim_ddi, *next;
 	struct mipi_dsim_lcd_driver *dsim_lcd_drv;
 	struct mipi_dsim_lcd_driver *dsim_lcd_drv;
 
 
-	iounmap(dsim->reg_base);
-
 	clk_disable(dsim->clock);
 	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) {
 	list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
 		if (dsim_ddi) {
 		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;
 	return 0;
 }
 }
 
 

+ 4 - 10
drivers/video/exynos/s6e8ax0.c

@@ -776,7 +776,7 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
 	int ret;
 	int ret;
 	u8 mtp_id[3] = {0, };
 	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) {
 	if (!lcd) {
 		dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
 		dev_err(&dsim_dev->dev, "failed to allocate s6e8ax0 structure.\n");
 		return -ENOMEM;
 		return -ENOMEM;
@@ -788,18 +788,17 @@ static int s6e8ax0_probe(struct mipi_dsim_lcd_device *dsim_dev)
 
 
 	mutex_init(&lcd->lock);
 	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) {
 	if (ret) {
 		dev_err(lcd->dev, "Failed to get regulators: %d\n", 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,
 	lcd->ld = lcd_device_register("s6e8ax0", lcd->dev, lcd,
 			&s6e8ax0_lcd_ops);
 			&s6e8ax0_lcd_ops);
 	if (IS_ERR(lcd->ld)) {
 	if (IS_ERR(lcd->ld)) {
 		dev_err(lcd->dev, "failed to register lcd ops.\n");
 		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,
 	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:
 err_backlight_register:
 	lcd_device_unregister(lcd->ld);
 	lcd_device_unregister(lcd->ld);
-
-err_lcd_register:
-	regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
-	kfree(lcd);
-
 	return ret;
 	return ret;
 }
 }
 
 

+ 318 - 0
drivers/video/goldfishfb.c

@@ -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");

+ 11 - 0
drivers/video/mmp/Kconfig

@@ -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

+ 1 - 0
drivers/video/mmp/Makefile

@@ -0,0 +1 @@
+obj-y += core.o hw/ panel/ fb/

+ 258 - 0
drivers/video/mmp/core.c

@@ -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);

+ 13 - 0
drivers/video/mmp/fb/Kconfig

@@ -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

+ 1 - 0
drivers/video/mmp/fb/Makefile

@@ -0,0 +1 @@
+obj-$(CONFIG_MMP_FB)  += mmpfb.o

+ 685 - 0
drivers/video/mmp/fb/mmpfb.c

@@ -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");

+ 54 - 0
drivers/video/mmp/fb/mmpfb.h

@@ -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_ */

+ 20 - 0
drivers/video/mmp/hw/Kconfig

@@ -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

+ 2 - 0
drivers/video/mmp/hw/Makefile

@@ -0,0 +1,2 @@
+obj-$(CONFIG_MMP_DISP_CONTROLLER)  += mmp_ctrl.o
+obj-$(CONFIG_MMP_DISP_SPI)	   += mmp_spi.o

部分文件因为文件数量过多而无法显示