aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:50:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:50:13 -0400
commit517d08699b250021303f9a7cf0d758b6dc0748ed (patch)
tree5e5b0134c3fffb78fe9d8b1641a64ff28fdd7bbc /drivers
parent8eeee4e2f04fc551f50c9d9847da2d73d7d33728 (diff)
parenta34601c5d84134055782ee031d58d82f5440e918 (diff)
Merge branch 'akpm'
* akpm: (182 commits) fbdev: bf54x-lq043fb: use kzalloc over kmalloc/memset fbdev: *bfin*: fix __dev{init,exit} markings fbdev: *bfin*: drop unnecessary calls to memset fbdev: bfin-t350mcqb-fb: drop unused local variables fbdev: blackfin has __raw I/O accessors, so use them in fb.h fbdev: s1d13xxxfb: add accelerated bitblt functions tcx: use standard fields for framebuffer physical address and length fbdev: add support for handoff from firmware to hw framebuffers intelfb: fix a bug when changing video timing fbdev: use framebuffer_release() for freeing fb_info structures radeon: P2G2CLK_ALWAYS_ONb tested twice, should 2nd be P2G2CLK_DAC_ALWAYS_ONb? s3c-fb: CPUFREQ frequency scaling support s3c-fb: fix resource releasing on error during probing carminefb: fix possible access beyond end of carmine_modedb[] acornfb: remove fb_mmap function mb862xxfb: use CONFIG_OF instead of CONFIG_PPC_OF mb862xxfb: restrict compliation of platform driver to PPC Samsung SoC Framebuffer driver: add Alpha Channel support atmel-lcdc: fix pixclock upper bound detection offb: use framebuffer_alloc() to allocate fb_info struct ... Manually fix up conflicts due to kmemcheck in mm/slab.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/base/node.c4
-rw-r--r--drivers/char/vt.c13
-rw-r--r--drivers/clocksource/acpi_pm.c1
-rw-r--r--drivers/eisa/eisa.ids5
-rw-r--r--drivers/firmware/memmap.c16
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c8
-rw-r--r--drivers/hwmon/Kconfig2
-rw-r--r--drivers/hwmon/hp_accel.c20
-rw-r--r--drivers/hwmon/lis3lv02d.c187
-rw-r--r--drivers/hwmon/lis3lv02d.h29
-rw-r--r--drivers/hwmon/lis3lv02d_spi.c1
-rw-r--r--drivers/input/joystick/analog.c2
-rw-r--r--drivers/input/misc/pcspkr.c1
-rw-r--r--drivers/media/video/videobuf-dma-contig.c94
-rw-r--r--drivers/misc/sgi-gru/grufile.c2
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c9
-rw-r--r--drivers/spi/spi_mpc83xx.c6
-rw-r--r--drivers/video/Kconfig1
-rw-r--r--drivers/video/acornfb.c38
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/aty/radeon_pm.c3
-rw-r--r--drivers/video/bf54x-lq043fb.c15
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c15
-rw-r--r--drivers/video/carminefb.c2
-rw-r--r--drivers/video/chipsfb.c1
-rw-r--r--drivers/video/efifb.c5
-rw-r--r--drivers/video/fbmem.c31
-rw-r--r--drivers/video/igafb.c8
-rw-r--r--drivers/video/intelfb/intelfbdrv.c5
-rw-r--r--drivers/video/logo/Makefile12
-rw-r--r--drivers/video/logo/logo.c15
-rw-r--r--drivers/video/mb862xx/mb862xxfb.c2
-rw-r--r--drivers/video/modedb.c8
-rw-r--r--drivers/video/offb.c8
-rw-r--r--drivers/video/pm2fb.c2
-rw-r--r--drivers/video/s1d13xxxfb.c341
-rw-r--r--drivers/video/s3c-fb.c53
-rw-r--r--drivers/video/s3c2410fb.c67
-rw-r--r--drivers/video/s3c2410fb.h5
-rw-r--r--drivers/video/sis/sis_main.c4
-rw-r--r--drivers/video/stifb.c2
-rw-r--r--drivers/video/tcx.c27
-rw-r--r--drivers/video/vesafb.c15
-rw-r--r--drivers/vlynq/Kconfig20
-rw-r--r--drivers/vlynq/Makefile5
-rw-r--r--drivers/vlynq/vlynq.c814
49 files changed, 1596 insertions, 335 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 00cf9553f740..a442c8f29fc1 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -104,6 +104,8 @@ source "drivers/auxdisplay/Kconfig"
104 104
105source "drivers/uio/Kconfig" 105source "drivers/uio/Kconfig"
106 106
107source "drivers/vlynq/Kconfig"
108
107source "drivers/xen/Kconfig" 109source "drivers/xen/Kconfig"
108 110
109source "drivers/staging/Kconfig" 111source "drivers/staging/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 9e7d4e56c85b..00b44f4ccf03 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_PPC_PS3) += ps3/
105obj-$(CONFIG_OF) += of/ 105obj-$(CONFIG_OF) += of/
106obj-$(CONFIG_SSB) += ssb/ 106obj-$(CONFIG_SSB) += ssb/
107obj-$(CONFIG_VIRTIO) += virtio/ 107obj-$(CONFIG_VIRTIO) += virtio/
108obj-$(CONFIG_VLYNQ) += vlynq/
108obj-$(CONFIG_STAGING) += staging/ 109obj-$(CONFIG_STAGING) += staging/
109obj-y += platform/ 110obj-y += platform/
110obj-y += ieee802154/ 111obj-y += ieee802154/
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 40b809742a1c..91d4087b4039 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -72,10 +72,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
72 "Node %d Inactive(anon): %8lu kB\n" 72 "Node %d Inactive(anon): %8lu kB\n"
73 "Node %d Active(file): %8lu kB\n" 73 "Node %d Active(file): %8lu kB\n"
74 "Node %d Inactive(file): %8lu kB\n" 74 "Node %d Inactive(file): %8lu kB\n"
75#ifdef CONFIG_UNEVICTABLE_LRU
76 "Node %d Unevictable: %8lu kB\n" 75 "Node %d Unevictable: %8lu kB\n"
77 "Node %d Mlocked: %8lu kB\n" 76 "Node %d Mlocked: %8lu kB\n"
78#endif
79#ifdef CONFIG_HIGHMEM 77#ifdef CONFIG_HIGHMEM
80 "Node %d HighTotal: %8lu kB\n" 78 "Node %d HighTotal: %8lu kB\n"
81 "Node %d HighFree: %8lu kB\n" 79 "Node %d HighFree: %8lu kB\n"
@@ -105,10 +103,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
105 nid, K(node_page_state(nid, NR_INACTIVE_ANON)), 103 nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
106 nid, K(node_page_state(nid, NR_ACTIVE_FILE)), 104 nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
107 nid, K(node_page_state(nid, NR_INACTIVE_FILE)), 105 nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
108#ifdef CONFIG_UNEVICTABLE_LRU
109 nid, K(node_page_state(nid, NR_UNEVICTABLE)), 106 nid, K(node_page_state(nid, NR_UNEVICTABLE)),
110 nid, K(node_page_state(nid, NR_MLOCK)), 107 nid, K(node_page_state(nid, NR_MLOCK)),
111#endif
112#ifdef CONFIG_HIGHMEM 108#ifdef CONFIG_HIGHMEM
113 nid, K(i.totalhigh), 109 nid, K(i.totalhigh),
114 nid, K(i.freehigh), 110 nid, K(i.freehigh),
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index c796a86ab7f3..d9113b4c76e3 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -171,8 +171,9 @@ int do_poke_blanked_console;
171int console_blanked; 171int console_blanked;
172 172
173static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ 173static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
174static int blankinterval = 10*60*HZ;
175static int vesa_off_interval; 174static int vesa_off_interval;
175static int blankinterval = 10*60;
176core_param(consoleblank, blankinterval, int, 0444);
176 177
177static DECLARE_WORK(console_work, console_callback); 178static DECLARE_WORK(console_work, console_callback);
178 179
@@ -1485,7 +1486,7 @@ static void setterm_command(struct vc_data *vc)
1485 update_attr(vc); 1486 update_attr(vc);
1486 break; 1487 break;
1487 case 9: /* set blanking interval */ 1488 case 9: /* set blanking interval */
1488 blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ; 1489 blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
1489 poke_blanked_console(); 1490 poke_blanked_console();
1490 break; 1491 break;
1491 case 10: /* set bell frequency in Hz */ 1492 case 10: /* set bell frequency in Hz */
@@ -2871,7 +2872,7 @@ static int __init con_init(void)
2871 2872
2872 if (blankinterval) { 2873 if (blankinterval) {
2873 blank_state = blank_normal_wait; 2874 blank_state = blank_normal_wait;
2874 mod_timer(&console_timer, jiffies + blankinterval); 2875 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
2875 } 2876 }
2876 2877
2877 for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { 2878 for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
@@ -3677,7 +3678,7 @@ void do_unblank_screen(int leaving_gfx)
3677 return; /* but leave console_blanked != 0 */ 3678 return; /* but leave console_blanked != 0 */
3678 3679
3679 if (blankinterval) { 3680 if (blankinterval) {
3680 mod_timer(&console_timer, jiffies + blankinterval); 3681 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3681 blank_state = blank_normal_wait; 3682 blank_state = blank_normal_wait;
3682 } 3683 }
3683 3684
@@ -3711,7 +3712,7 @@ void unblank_screen(void)
3711static void blank_screen_t(unsigned long dummy) 3712static void blank_screen_t(unsigned long dummy)
3712{ 3713{
3713 if (unlikely(!keventd_up())) { 3714 if (unlikely(!keventd_up())) {
3714 mod_timer(&console_timer, jiffies + blankinterval); 3715 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3715 return; 3716 return;
3716 } 3717 }
3717 blank_timer_expired = 1; 3718 blank_timer_expired = 1;
@@ -3741,7 +3742,7 @@ void poke_blanked_console(void)
3741 if (console_blanked) 3742 if (console_blanked)
3742 unblank_screen(); 3743 unblank_screen();
3743 else if (blankinterval) { 3744 else if (blankinterval) {
3744 mod_timer(&console_timer, jiffies + blankinterval); 3745 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3745 blank_state = blank_normal_wait; 3746 blank_state = blank_normal_wait;
3746 } 3747 }
3747} 3748}
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 40bd8c61c7d7..72a633a6ec98 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -18,6 +18,7 @@
18 18
19#include <linux/acpi_pmtmr.h> 19#include <linux/acpi_pmtmr.h>
20#include <linux/clocksource.h> 20#include <linux/clocksource.h>
21#include <linux/timex.h>
21#include <linux/errno.h> 22#include <linux/errno.h>
22#include <linux/init.h> 23#include <linux/init.h>
23#include <linux/pci.h> 24#include <linux/pci.h>
diff --git a/drivers/eisa/eisa.ids b/drivers/eisa/eisa.ids
index ed69837d8b74..6cbb7a514436 100644
--- a/drivers/eisa/eisa.ids
+++ b/drivers/eisa/eisa.ids
@@ -1140,6 +1140,11 @@ NON0301 "c't Universale Graphic Adapter"
1140NON0401 "c't Universal Ethernet Adapter" 1140NON0401 "c't Universal Ethernet Adapter"
1141NON0501 "c't Universal 16-Bit Sound Adapter" 1141NON0501 "c't Universal 16-Bit Sound Adapter"
1142NON0601 "c't Universal 8-Bit Adapter" 1142NON0601 "c't Universal 8-Bit Adapter"
1143NPI0120 "Network Peripherals NP-EISA-1 FDDI Interface"
1144NPI0221 "Network Peripherals NP-EISA-2 FDDI Interface"
1145NPI0223 "Network Peripherals NP-EISA-2E Enhanced FDDI Interface"
1146NPI0301 "Network Peripherals NP-EISA-3 FDDI Interface"
1147NPI0303 "Network Peripherals NP-EISA-3E Enhanced FDDI Interface"
1143NSS0011 "Newport Systems Solutions WNIC Adapter" 1148NSS0011 "Newport Systems Solutions WNIC Adapter"
1144NVL0701 "Novell NE3200 Bus Master Ethernet" 1149NVL0701 "Novell NE3200 Bus Master Ethernet"
1145NVL0702 "Novell NE3200T Bus Master Ethernet" 1150NVL0702 "Novell NE3200T Bus Master Ethernet"
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
index 05aa2d406ac6..d5ea8a68d338 100644
--- a/drivers/firmware/memmap.c
+++ b/drivers/firmware/memmap.c
@@ -31,8 +31,12 @@
31 * information is necessary as for the resource tree. 31 * information is necessary as for the resource tree.
32 */ 32 */
33struct firmware_map_entry { 33struct firmware_map_entry {
34 resource_size_t start; /* start of the memory range */ 34 /*
35 resource_size_t end; /* end of the memory range (incl.) */ 35 * start and end must be u64 rather than resource_size_t, because e820
36 * resources can lie at addresses above 4G.
37 */
38 u64 start; /* start of the memory range */
39 u64 end; /* end of the memory range (incl.) */
36 const char *type; /* type of the memory range */ 40 const char *type; /* type of the memory range */
37 struct list_head list; /* entry for the linked list */ 41 struct list_head list; /* entry for the linked list */
38 struct kobject kobj; /* kobject for each entry */ 42 struct kobject kobj; /* kobject for each entry */
@@ -101,7 +105,7 @@ static LIST_HEAD(map_entries);
101 * Common implementation of firmware_map_add() and firmware_map_add_early() 105 * Common implementation of firmware_map_add() and firmware_map_add_early()
102 * which expects a pre-allocated struct firmware_map_entry. 106 * which expects a pre-allocated struct firmware_map_entry.
103 **/ 107 **/
104static int firmware_map_add_entry(resource_size_t start, resource_size_t end, 108static int firmware_map_add_entry(u64 start, u64 end,
105 const char *type, 109 const char *type,
106 struct firmware_map_entry *entry) 110 struct firmware_map_entry *entry)
107{ 111{
@@ -132,8 +136,7 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
132 * 136 *
133 * Returns 0 on success, or -ENOMEM if no memory could be allocated. 137 * Returns 0 on success, or -ENOMEM if no memory could be allocated.
134 **/ 138 **/
135int firmware_map_add(resource_size_t start, resource_size_t end, 139int firmware_map_add(u64 start, u64 end, const char *type)
136 const char *type)
137{ 140{
138 struct firmware_map_entry *entry; 141 struct firmware_map_entry *entry;
139 142
@@ -157,8 +160,7 @@ int firmware_map_add(resource_size_t start, resource_size_t end,
157 * 160 *
158 * Returns 0 on success, or -ENOMEM if no memory could be allocated. 161 * Returns 0 on success, or -ENOMEM if no memory could be allocated.
159 **/ 162 **/
160int __init firmware_map_add_early(resource_size_t start, resource_size_t end, 163int __init firmware_map_add_early(u64 start, u64 end, const char *type)
161 const char *type)
162{ 164{
163 struct firmware_map_entry *entry; 165 struct firmware_map_entry *entry;
164 166
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 0ecf6b76a401..8e28e5993df5 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
504 info->fbops = &intelfb_ops; 504 info->fbops = &intelfb_ops;
505 505
506 info->fix.line_length = fb->pitch; 506 info->fix.line_length = fb->pitch;
507
508 /* setup aperture base/size for vesafb takeover */
509 info->aperture_base = dev->mode_config.fb_base;
510 if (IS_I9XX(dev))
511 info->aperture_size = pci_resource_len(dev->pdev, 2);
512 else
513 info->aperture_size = pci_resource_len(dev->pdev, 0);
514
507 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset; 515 info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
508 info->fix.smem_len = size; 516 info->fix.smem_len = size;
509 517
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index f8090e137fef..2d5016691d40 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -950,6 +950,7 @@ config SENSORS_HDAPS
950config SENSORS_LIS3LV02D 950config SENSORS_LIS3LV02D
951 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" 951 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
952 depends on ACPI && INPUT 952 depends on ACPI && INPUT
953 select INPUT_POLLDEV
953 select NEW_LEDS 954 select NEW_LEDS
954 select LEDS_CLASS 955 select LEDS_CLASS
955 default n 956 default n
@@ -977,6 +978,7 @@ config SENSORS_LIS3LV02D
977config SENSORS_LIS3_SPI 978config SENSORS_LIS3_SPI
978 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" 979 tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
979 depends on !ACPI && SPI_MASTER && INPUT 980 depends on !ACPI && SPI_MASTER && INPUT
981 select INPUT_POLLDEV
980 default n 982 default n
981 help 983 help
982 This driver provides support for the LIS3LV02Dx accelerometer connected 984 This driver provides support for the LIS3LV02Dx accelerometer connected
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c
index abca7e9f953b..6679854c85b0 100644
--- a/drivers/hwmon/hp_accel.c
+++ b/drivers/hwmon/hp_accel.c
@@ -27,9 +27,6 @@
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/input.h>
31#include <linux/kthread.h>
32#include <linux/semaphore.h>
33#include <linux/delay.h> 30#include <linux/delay.h>
34#include <linux/wait.h> 31#include <linux/wait.h>
35#include <linux/poll.h> 32#include <linux/poll.h>
@@ -161,6 +158,7 @@ static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
161static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; 158static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
162static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; 159static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
163static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; 160static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
161static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
164static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; 162static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
165static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3}; 163static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
166static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; 164static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
@@ -194,13 +192,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
194 AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), 192 AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
195 AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), 193 AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
196 AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), 194 AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
195 AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
197 AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), 196 AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
198 AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), 197 AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
199 AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted), 198 AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
200 AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd), 199 AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
201 AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd), 200 AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
202 AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right), 201 AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
203 AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted), 202 AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
203 AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
204 AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
204 /* Intel-based HP Pavilion dv5 */ 205 /* Intel-based HP Pavilion dv5 */
205 AXIS_DMI_MATCH2("HPDV5_I", 206 AXIS_DMI_MATCH2("HPDV5_I",
206 PRODUCT_NAME, "HP Pavilion dv5", 207 PRODUCT_NAME, "HP Pavilion dv5",
@@ -216,7 +217,6 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
216 { NULL, } 217 { NULL, }
217/* Laptop models without axis info (yet): 218/* Laptop models without axis info (yet):
218 * "NC6910" "HP Compaq 6910" 219 * "NC6910" "HP Compaq 6910"
219 * HP Compaq 8710x Notebook PC / Mobile Workstation
220 * "NC2400" "HP Compaq nc2400" 220 * "NC2400" "HP Compaq nc2400"
221 * "NX74x0" "HP Compaq nx74" 221 * "NX74x0" "HP Compaq nx74"
222 * "NX6325" "HP Compaq nx6325" 222 * "NX6325" "HP Compaq nx6325"
@@ -324,7 +324,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
324 flush_work(&hpled_led.work); 324 flush_work(&hpled_led.work);
325 led_classdev_unregister(&hpled_led.led_classdev); 325 led_classdev_unregister(&hpled_led.led_classdev);
326 326
327 return lis3lv02d_remove_fs(); 327 return lis3lv02d_remove_fs(&lis3_dev);
328} 328}
329 329
330 330
@@ -338,13 +338,7 @@ static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
338 338
339static int lis3lv02d_resume(struct acpi_device *device) 339static int lis3lv02d_resume(struct acpi_device *device)
340{ 340{
341 /* put back the device in the right state (ACPI might turn it on) */ 341 lis3lv02d_poweron(&lis3_dev);
342 mutex_lock(&lis3_dev.lock);
343 if (lis3_dev.usage > 0)
344 lis3lv02d_poweron(&lis3_dev);
345 else
346 lis3lv02d_poweroff(&lis3_dev);
347 mutex_unlock(&lis3_dev.lock);
348 return 0; 342 return 0;
349} 343}
350#else 344#else
diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c
index 778eb7795983..271338bdb6be 100644
--- a/drivers/hwmon/lis3lv02d.c
+++ b/drivers/hwmon/lis3lv02d.c
@@ -27,9 +27,7 @@
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/input.h> 30#include <linux/input-polldev.h>
31#include <linux/kthread.h>
32#include <linux/semaphore.h>
33#include <linux/delay.h> 31#include <linux/delay.h>
34#include <linux/wait.h> 32#include <linux/wait.h>
35#include <linux/poll.h> 33#include <linux/poll.h>
@@ -105,56 +103,39 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
105{ 103{
106 int position[3]; 104 int position[3];
107 105
108 position[0] = lis3_dev.read_data(lis3, OUTX); 106 position[0] = lis3->read_data(lis3, OUTX);
109 position[1] = lis3_dev.read_data(lis3, OUTY); 107 position[1] = lis3->read_data(lis3, OUTY);
110 position[2] = lis3_dev.read_data(lis3, OUTZ); 108 position[2] = lis3->read_data(lis3, OUTZ);
111 109
112 *x = lis3lv02d_get_axis(lis3_dev.ac.x, position); 110 *x = lis3lv02d_get_axis(lis3->ac.x, position);
113 *y = lis3lv02d_get_axis(lis3_dev.ac.y, position); 111 *y = lis3lv02d_get_axis(lis3->ac.y, position);
114 *z = lis3lv02d_get_axis(lis3_dev.ac.z, position); 112 *z = lis3lv02d_get_axis(lis3->ac.z, position);
115} 113}
116 114
117void lis3lv02d_poweroff(struct lis3lv02d *lis3) 115void lis3lv02d_poweroff(struct lis3lv02d *lis3)
118{ 116{
119 lis3_dev.is_on = 0; 117 /* disable X,Y,Z axis and power down */
118 lis3->write(lis3, CTRL_REG1, 0x00);
120} 119}
121EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); 120EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
122 121
123void lis3lv02d_poweron(struct lis3lv02d *lis3) 122void lis3lv02d_poweron(struct lis3lv02d *lis3)
124{ 123{
125 lis3_dev.is_on = 1; 124 u8 reg;
126 lis3_dev.init(lis3);
127}
128EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
129 125
130/* 126 lis3->init(lis3);
131 * To be called before starting to use the device. It makes sure that the
132 * device will always be on until a call to lis3lv02d_decrease_use(). Not to be
133 * used from interrupt context.
134 */
135static void lis3lv02d_increase_use(struct lis3lv02d *dev)
136{
137 mutex_lock(&dev->lock);
138 dev->usage++;
139 if (dev->usage == 1) {
140 if (!dev->is_on)
141 lis3lv02d_poweron(dev);
142 }
143 mutex_unlock(&dev->lock);
144}
145 127
146/* 128 /*
147 * To be called whenever a usage of the device is stopped. 129 * Common configuration
148 * It will make sure to turn off the device when there is not usage. 130 * BDU: LSB and MSB values are not updated until both have been read.
149 */ 131 * So the value read will always be correct.
150static void lis3lv02d_decrease_use(struct lis3lv02d *dev) 132 */
151{ 133 lis3->read(lis3, CTRL_REG2, &reg);
152 mutex_lock(&dev->lock); 134 reg |= CTRL2_BDU;
153 dev->usage--; 135 lis3->write(lis3, CTRL_REG2, reg);
154 if (dev->usage == 0)
155 lis3lv02d_poweroff(dev);
156 mutex_unlock(&dev->lock);
157} 136}
137EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
138
158 139
159static irqreturn_t lis302dl_interrupt(int irq, void *dummy) 140static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
160{ 141{
@@ -198,15 +179,12 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
198 printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq); 179 printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
199 return -EBUSY; 180 return -EBUSY;
200 } 181 }
201 lis3lv02d_increase_use(&lis3_dev);
202 printk("lis3: registered interrupt %d\n", lis3_dev.irq);
203 return 0; 182 return 0;
204} 183}
205 184
206static int lis3lv02d_misc_release(struct inode *inode, struct file *file) 185static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
207{ 186{
208 fasync_helper(-1, file, 0, &lis3_dev.async_queue); 187 fasync_helper(-1, file, 0, &lis3_dev.async_queue);
209 lis3lv02d_decrease_use(&lis3_dev);
210 free_irq(lis3_dev.irq, &lis3_dev); 188 free_irq(lis3_dev.irq, &lis3_dev);
211 clear_bit(0, &lis3_dev.misc_opened); /* release the device */ 189 clear_bit(0, &lis3_dev.misc_opened); /* release the device */
212 return 0; 190 return 0;
@@ -290,46 +268,16 @@ static struct miscdevice lis3lv02d_misc_device = {
290 .fops = &lis3lv02d_misc_fops, 268 .fops = &lis3lv02d_misc_fops,
291}; 269};
292 270
293/** 271static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
294 * lis3lv02d_joystick_kthread - Kthread polling function
295 * @data: unused - here to conform to threadfn prototype
296 */
297static int lis3lv02d_joystick_kthread(void *data)
298{ 272{
299 int x, y, z; 273 int x, y, z;
300 274
301 while (!kthread_should_stop()) { 275 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
302 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 276 input_report_abs(pidev->input, ABS_X, x - lis3_dev.xcalib);
303 input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib); 277 input_report_abs(pidev->input, ABS_Y, y - lis3_dev.ycalib);
304 input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib); 278 input_report_abs(pidev->input, ABS_Z, z - lis3_dev.zcalib);
305 input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib);
306
307 input_sync(lis3_dev.idev);
308
309 try_to_freeze();
310 msleep_interruptible(MDPS_POLL_INTERVAL);
311 }
312
313 return 0;
314}
315
316static int lis3lv02d_joystick_open(struct input_dev *input)
317{
318 lis3lv02d_increase_use(&lis3_dev);
319 lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
320 if (IS_ERR(lis3_dev.kthread)) {
321 lis3lv02d_decrease_use(&lis3_dev);
322 return PTR_ERR(lis3_dev.kthread);
323 }
324
325 return 0;
326} 279}
327 280
328static void lis3lv02d_joystick_close(struct input_dev *input)
329{
330 kthread_stop(lis3_dev.kthread);
331 lis3lv02d_decrease_use(&lis3_dev);
332}
333 281
334static inline void lis3lv02d_calibrate_joystick(void) 282static inline void lis3lv02d_calibrate_joystick(void)
335{ 283{
@@ -339,33 +287,36 @@ static inline void lis3lv02d_calibrate_joystick(void)
339 287
340int lis3lv02d_joystick_enable(void) 288int lis3lv02d_joystick_enable(void)
341{ 289{
290 struct input_dev *input_dev;
342 int err; 291 int err;
343 292
344 if (lis3_dev.idev) 293 if (lis3_dev.idev)
345 return -EINVAL; 294 return -EINVAL;
346 295
347 lis3_dev.idev = input_allocate_device(); 296 lis3_dev.idev = input_allocate_polled_device();
348 if (!lis3_dev.idev) 297 if (!lis3_dev.idev)
349 return -ENOMEM; 298 return -ENOMEM;
350 299
300 lis3_dev.idev->poll = lis3lv02d_joystick_poll;
301 lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
302 input_dev = lis3_dev.idev->input;
303
351 lis3lv02d_calibrate_joystick(); 304 lis3lv02d_calibrate_joystick();
352 305
353 lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer"; 306 input_dev->name = "ST LIS3LV02DL Accelerometer";
354 lis3_dev.idev->phys = DRIVER_NAME "/input0"; 307 input_dev->phys = DRIVER_NAME "/input0";
355 lis3_dev.idev->id.bustype = BUS_HOST; 308 input_dev->id.bustype = BUS_HOST;
356 lis3_dev.idev->id.vendor = 0; 309 input_dev->id.vendor = 0;
357 lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev; 310 input_dev->dev.parent = &lis3_dev.pdev->dev;
358 lis3_dev.idev->open = lis3lv02d_joystick_open;
359 lis3_dev.idev->close = lis3lv02d_joystick_close;
360 311
361 set_bit(EV_ABS, lis3_dev.idev->evbit); 312 set_bit(EV_ABS, input_dev->evbit);
362 input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 313 input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
363 input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 314 input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
364 input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3); 315 input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
365 316
366 err = input_register_device(lis3_dev.idev); 317 err = input_register_polled_device(lis3_dev.idev);
367 if (err) { 318 if (err) {
368 input_free_device(lis3_dev.idev); 319 input_free_polled_device(lis3_dev.idev);
369 lis3_dev.idev = NULL; 320 lis3_dev.idev = NULL;
370 } 321 }
371 322
@@ -378,8 +329,9 @@ void lis3lv02d_joystick_disable(void)
378 if (!lis3_dev.idev) 329 if (!lis3_dev.idev)
379 return; 330 return;
380 331
381 misc_deregister(&lis3lv02d_misc_device); 332 if (lis3_dev.irq)
382 input_unregister_device(lis3_dev.idev); 333 misc_deregister(&lis3lv02d_misc_device);
334 input_unregister_polled_device(lis3_dev.idev);
383 lis3_dev.idev = NULL; 335 lis3_dev.idev = NULL;
384} 336}
385EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); 337EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
@@ -390,9 +342,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
390{ 342{
391 int x, y, z; 343 int x, y, z;
392 344
393 lis3lv02d_increase_use(&lis3_dev);
394 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); 345 lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
395 lis3lv02d_decrease_use(&lis3_dev);
396 return sprintf(buf, "(%d,%d,%d)\n", x, y, z); 346 return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
397} 347}
398 348
@@ -406,9 +356,7 @@ static ssize_t lis3lv02d_calibrate_store(struct device *dev,
406 struct device_attribute *attr, 356 struct device_attribute *attr,
407 const char *buf, size_t count) 357 const char *buf, size_t count)
408{ 358{
409 lis3lv02d_increase_use(&lis3_dev);
410 lis3lv02d_calibrate_joystick(); 359 lis3lv02d_calibrate_joystick();
411 lis3lv02d_decrease_use(&lis3_dev);
412 return count; 360 return count;
413} 361}
414 362
@@ -420,9 +368,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
420 u8 ctrl; 368 u8 ctrl;
421 int val; 369 int val;
422 370
423 lis3lv02d_increase_use(&lis3_dev);
424 lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); 371 lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
425 lis3lv02d_decrease_use(&lis3_dev);
426 val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; 372 val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
427 return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); 373 return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
428} 374}
@@ -446,17 +392,17 @@ static struct attribute_group lis3lv02d_attribute_group = {
446 392
447static int lis3lv02d_add_fs(struct lis3lv02d *lis3) 393static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
448{ 394{
449 lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); 395 lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
450 if (IS_ERR(lis3_dev.pdev)) 396 if (IS_ERR(lis3->pdev))
451 return PTR_ERR(lis3_dev.pdev); 397 return PTR_ERR(lis3->pdev);
452 398
453 return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); 399 return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
454} 400}
455 401
456int lis3lv02d_remove_fs(void) 402int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
457{ 403{
458 sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group); 404 sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
459 platform_device_unregister(lis3_dev.pdev); 405 platform_device_unregister(lis3->pdev);
460 return 0; 406 return 0;
461} 407}
462EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); 408EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
@@ -482,18 +428,35 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
482 break; 428 break;
483 default: 429 default:
484 printk(KERN_ERR DRIVER_NAME 430 printk(KERN_ERR DRIVER_NAME
485 ": unknown sensor type 0x%X\n", lis3_dev.whoami); 431 ": unknown sensor type 0x%X\n", dev->whoami);
486 return -EINVAL; 432 return -EINVAL;
487 } 433 }
488 434
489 mutex_init(&dev->lock);
490 lis3lv02d_add_fs(dev); 435 lis3lv02d_add_fs(dev);
491 lis3lv02d_increase_use(dev); 436 lis3lv02d_poweron(dev);
492 437
493 if (lis3lv02d_joystick_enable()) 438 if (lis3lv02d_joystick_enable())
494 printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n"); 439 printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
495 440
496 printk("lis3_init_device: irq %d\n", dev->irq); 441 /* passing in platform specific data is purely optional and only
442 * used by the SPI transport layer at the moment */
443 if (dev->pdata) {
444 struct lis3lv02d_platform_data *p = dev->pdata;
445
446 if (p->click_flags && (dev->whoami == LIS_SINGLE_ID)) {
447 dev->write(dev, CLICK_CFG, p->click_flags);
448 dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
449 dev->write(dev, CLICK_LATENCY, p->click_latency);
450 dev->write(dev, CLICK_WINDOW, p->click_window);
451 dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
452 dev->write(dev, CLICK_THSY_X,
453 (p->click_thresh_x & 0xf) |
454 (p->click_thresh_y << 4));
455 }
456
457 if (p->irq_cfg)
458 dev->write(dev, CTRL_REG3, p->irq_cfg);
459 }
497 460
498 /* bail if we did not get an IRQ from the bus layer */ 461 /* bail if we did not get an IRQ from the bus layer */
499 if (!dev->irq) { 462 if (!dev->irq) {
@@ -502,11 +465,9 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
502 goto out; 465 goto out;
503 } 466 }
504 467
505 printk("lis3: registering device\n");
506 if (misc_register(&lis3lv02d_misc_device)) 468 if (misc_register(&lis3lv02d_misc_device))
507 printk(KERN_ERR DRIVER_NAME ": misc_register failed\n"); 469 printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
508out: 470out:
509 lis3lv02d_decrease_use(dev);
510 return 0; 471 return 0;
511} 472}
512EXPORT_SYMBOL_GPL(lis3lv02d_init_device); 473EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h
index 745ec96806d4..e320e2f511f1 100644
--- a/drivers/hwmon/lis3lv02d.h
+++ b/drivers/hwmon/lis3lv02d.h
@@ -18,6 +18,8 @@
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21#include <linux/platform_device.h>
22#include <linux/input-polldev.h>
21 23
22/* 24/*
23 * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to 25 * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
@@ -27,12 +29,14 @@
27 * They can also be connected via I²C. 29 * They can also be connected via I²C.
28 */ 30 */
29 31
32#include <linux/lis3lv02d.h>
33
30/* 2-byte registers */ 34/* 2-byte registers */
31#define LIS_DOUBLE_ID 0x3A /* LIS3LV02D[LQ] */ 35#define LIS_DOUBLE_ID 0x3A /* LIS3LV02D[LQ] */
32/* 1-byte registers */ 36/* 1-byte registers */
33#define LIS_SINGLE_ID 0x3B /* LIS[32]02DL and others */ 37#define LIS_SINGLE_ID 0x3B /* LIS[32]02DL and others */
34 38
35enum lis3lv02d_reg { 39enum lis3_reg {
36 WHO_AM_I = 0x0F, 40 WHO_AM_I = 0x0F,
37 OFFSET_X = 0x16, 41 OFFSET_X = 0x16,
38 OFFSET_Y = 0x17, 42 OFFSET_Y = 0x17,
@@ -60,6 +64,19 @@ enum lis3lv02d_reg {
60 FF_WU_THS_L = 0x34, 64 FF_WU_THS_L = 0x34,
61 FF_WU_THS_H = 0x35, 65 FF_WU_THS_H = 0x35,
62 FF_WU_DURATION = 0x36, 66 FF_WU_DURATION = 0x36,
67};
68
69enum lis302d_reg {
70 CLICK_CFG = 0x38,
71 CLICK_SRC = 0x39,
72 CLICK_THSY_X = 0x3B,
73 CLICK_THSZ = 0x3C,
74 CLICK_TIMELIMIT = 0x3D,
75 CLICK_LATENCY = 0x3E,
76 CLICK_WINDOW = 0x3F,
77};
78
79enum lis3lv02d_reg {
63 DD_CFG = 0x38, 80 DD_CFG = 0x38,
64 DD_SRC = 0x39, 81 DD_SRC = 0x39,
65 DD_ACK = 0x3A, 82 DD_ACK = 0x3A,
@@ -169,22 +186,20 @@ struct lis3lv02d {
169 s16 (*read_data) (struct lis3lv02d *lis3, int reg); 186 s16 (*read_data) (struct lis3lv02d *lis3, int reg);
170 int mdps_max_val; 187 int mdps_max_val;
171 188
172 struct input_dev *idev; /* input device */ 189 struct input_polled_dev *idev; /* input device */
173 struct task_struct *kthread; /* kthread for input */
174 struct mutex lock;
175 struct platform_device *pdev; /* platform device */ 190 struct platform_device *pdev; /* platform device */
176 atomic_t count; /* interrupt count after last read */ 191 atomic_t count; /* interrupt count after last read */
177 int xcalib; /* calibrated null value for x */ 192 int xcalib; /* calibrated null value for x */
178 int ycalib; /* calibrated null value for y */ 193 int ycalib; /* calibrated null value for y */
179 int zcalib; /* calibrated null value for z */ 194 int zcalib; /* calibrated null value for z */
180 unsigned char is_on; /* whether the device is on or off */
181 unsigned char usage; /* usage counter */
182 struct axis_conversion ac; /* hw -> logical axis */ 195 struct axis_conversion ac; /* hw -> logical axis */
183 196
184 u32 irq; /* IRQ number */ 197 u32 irq; /* IRQ number */
185 struct fasync_struct *async_queue; /* queue for the misc device */ 198 struct fasync_struct *async_queue; /* queue for the misc device */
186 wait_queue_head_t misc_wait; /* Wait queue for the misc device */ 199 wait_queue_head_t misc_wait; /* Wait queue for the misc device */
187 unsigned long misc_opened; /* bit0: whether the device is open */ 200 unsigned long misc_opened; /* bit0: whether the device is open */
201
202 struct lis3lv02d_platform_data *pdata; /* for passing board config */
188}; 203};
189 204
190int lis3lv02d_init_device(struct lis3lv02d *lis3); 205int lis3lv02d_init_device(struct lis3lv02d *lis3);
@@ -192,6 +207,6 @@ int lis3lv02d_joystick_enable(void);
192void lis3lv02d_joystick_disable(void); 207void lis3lv02d_joystick_disable(void);
193void lis3lv02d_poweroff(struct lis3lv02d *lis3); 208void lis3lv02d_poweroff(struct lis3lv02d *lis3);
194void lis3lv02d_poweron(struct lis3lv02d *lis3); 209void lis3lv02d_poweron(struct lis3lv02d *lis3);
195int lis3lv02d_remove_fs(void); 210int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
196 211
197extern struct lis3lv02d lis3_dev; 212extern struct lis3lv02d lis3_dev;
diff --git a/drivers/hwmon/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
index 07ae74b0e191..3827ff04485f 100644
--- a/drivers/hwmon/lis3lv02d_spi.c
+++ b/drivers/hwmon/lis3lv02d_spi.c
@@ -72,6 +72,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
72 lis3_dev.write = lis3_spi_write; 72 lis3_dev.write = lis3_spi_write;
73 lis3_dev.irq = spi->irq; 73 lis3_dev.irq = spi->irq;
74 lis3_dev.ac = lis3lv02d_axis_normal; 74 lis3_dev.ac = lis3lv02d_axis_normal;
75 lis3_dev.pdata = spi->dev.platform_data;
75 spi_set_drvdata(spi, &lis3_dev); 76 spi_set_drvdata(spi, &lis3_dev);
76 77
77 ret = lis3lv02d_init_device(&lis3_dev); 78 ret = lis3lv02d_init_device(&lis3_dev);
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 356b3a25efa2..1c0b529c06aa 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -35,7 +35,7 @@
35#include <linux/input.h> 35#include <linux/input.h>
36#include <linux/gameport.h> 36#include <linux/gameport.h>
37#include <linux/jiffies.h> 37#include <linux/jiffies.h>
38#include <asm/timex.h> 38#include <linux/timex.h>
39 39
40#define DRIVER_DESC "Analog joystick and gamepad driver" 40#define DRIVER_DESC "Analog joystick and gamepad driver"
41 41
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index d6a30cee7bc7..6d67af5387ad 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,6 +17,7 @@
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/input.h> 18#include <linux/input.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/timex.h>
20#include <asm/io.h> 21#include <asm/io.h>
21 22
22MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); 23MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 6109fb5f34e2..0c29a019bc89 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -17,6 +17,7 @@
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/pagemap.h>
20#include <linux/dma-mapping.h> 21#include <linux/dma-mapping.h>
21#include <media/videobuf-dma-contig.h> 22#include <media/videobuf-dma-contig.h>
22 23
@@ -25,6 +26,7 @@ struct videobuf_dma_contig_memory {
25 void *vaddr; 26 void *vaddr;
26 dma_addr_t dma_handle; 27 dma_addr_t dma_handle;
27 unsigned long size; 28 unsigned long size;
29 int is_userptr;
28}; 30};
29 31
30#define MAGIC_DC_MEM 0x0733ac61 32#define MAGIC_DC_MEM 0x0733ac61
@@ -108,6 +110,82 @@ static struct vm_operations_struct videobuf_vm_ops = {
108 .close = videobuf_vm_close, 110 .close = videobuf_vm_close,
109}; 111};
110 112
113/**
114 * videobuf_dma_contig_user_put() - reset pointer to user space buffer
115 * @mem: per-buffer private videobuf-dma-contig data
116 *
117 * This function resets the user space pointer
118 */
119static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
120{
121 mem->is_userptr = 0;
122 mem->dma_handle = 0;
123 mem->size = 0;
124}
125
126/**
127 * videobuf_dma_contig_user_get() - setup user space memory pointer
128 * @mem: per-buffer private videobuf-dma-contig data
129 * @vb: video buffer to map
130 *
131 * This function validates and sets up a pointer to user space memory.
132 * Only physically contiguous pfn-mapped memory is accepted.
133 *
134 * Returns 0 if successful.
135 */
136static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
137 struct videobuf_buffer *vb)
138{
139 struct mm_struct *mm = current->mm;
140 struct vm_area_struct *vma;
141 unsigned long prev_pfn, this_pfn;
142 unsigned long pages_done, user_address;
143 int ret;
144
145 mem->size = PAGE_ALIGN(vb->size);
146 mem->is_userptr = 0;
147 ret = -EINVAL;
148
149 down_read(&mm->mmap_sem);
150
151 vma = find_vma(mm, vb->baddr);
152 if (!vma)
153 goto out_up;
154
155 if ((vb->baddr + mem->size) > vma->vm_end)
156 goto out_up;
157
158 pages_done = 0;
159 prev_pfn = 0; /* kill warning */
160 user_address = vb->baddr;
161
162 while (pages_done < (mem->size >> PAGE_SHIFT)) {
163 ret = follow_pfn(vma, user_address, &this_pfn);
164 if (ret)
165 break;
166
167 if (pages_done == 0)
168 mem->dma_handle = this_pfn << PAGE_SHIFT;
169 else if (this_pfn != (prev_pfn + 1))
170 ret = -EFAULT;
171
172 if (ret)
173 break;
174
175 prev_pfn = this_pfn;
176 user_address += PAGE_SIZE;
177 pages_done++;
178 }
179
180 if (!ret)
181 mem->is_userptr = 1;
182
183 out_up:
184 up_read(&current->mm->mmap_sem);
185
186 return ret;
187}
188
111static void *__videobuf_alloc(size_t size) 189static void *__videobuf_alloc(size_t size)
112{ 190{
113 struct videobuf_dma_contig_memory *mem; 191 struct videobuf_dma_contig_memory *mem;
@@ -154,12 +232,11 @@ static int __videobuf_iolock(struct videobuf_queue *q,
154 case V4L2_MEMORY_USERPTR: 232 case V4L2_MEMORY_USERPTR:
155 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__); 233 dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
156 234
157 /* The only USERPTR currently supported is the one needed for 235 /* handle pointer from user space */
158 read() method.
159 */
160 if (vb->baddr) 236 if (vb->baddr)
161 return -EINVAL; 237 return videobuf_dma_contig_user_get(mem, vb);
162 238
239 /* allocate memory for the read() method */
163 mem->size = PAGE_ALIGN(vb->size); 240 mem->size = PAGE_ALIGN(vb->size);
164 mem->vaddr = dma_alloc_coherent(q->dev, mem->size, 241 mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
165 &mem->dma_handle, GFP_KERNEL); 242 &mem->dma_handle, GFP_KERNEL);
@@ -400,7 +477,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
400 So, it should free memory only if the memory were allocated for 477 So, it should free memory only if the memory were allocated for
401 read() operation. 478 read() operation.
402 */ 479 */
403 if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr) 480 if (buf->memory != V4L2_MEMORY_USERPTR)
404 return; 481 return;
405 482
406 if (!mem) 483 if (!mem)
@@ -408,6 +485,13 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
408 485
409 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); 486 MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
410 487
488 /* handle user space pointer case */
489 if (buf->baddr) {
490 videobuf_dma_contig_user_put(mem);
491 return;
492 }
493
494 /* read() method */
411 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle); 495 dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
412 mem->vaddr = NULL; 496 mem->vaddr = NULL;
413} 497}
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index bbefe77c67a9..3ce2920e2bf3 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -302,7 +302,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
302 pnode = uv_node_to_pnode(nid); 302 pnode = uv_node_to_pnode(nid);
303 if (bid < 0 || gru_base[bid]) 303 if (bid < 0 || gru_base[bid])
304 continue; 304 continue;
305 page = alloc_pages_node(nid, GFP_KERNEL, order); 305 page = alloc_pages_exact_node(nid, GFP_KERNEL, order);
306 if (!page) 306 if (!page)
307 goto fail; 307 goto fail;
308 gru_base[bid] = page_address(page); 308 gru_base[bid] = page_address(page);
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 9172fcdee4e2..c76677afda1b 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -232,7 +232,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
232 mq->mmr_blade = uv_cpu_to_blade_id(cpu); 232 mq->mmr_blade = uv_cpu_to_blade_id(cpu);
233 233
234 nid = cpu_to_node(cpu); 234 nid = cpu_to_node(cpu);
235 page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE, 235 page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
236 pg_order); 236 pg_order);
237 if (page == NULL) { 237 if (page == NULL) {
238 dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d " 238 dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 1703b20cad5d..6095f8daecd7 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -915,12 +915,9 @@ static int ds_ioctl(struct inode * inode, struct file * file,
915 err = -EPERM; 915 err = -EPERM;
916 goto free_out; 916 goto free_out;
917 } else { 917 } else {
918 static int printed = 0; 918 printk_once(KERN_WARNING
919 if (!printed) { 919 "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
920 printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n"); 920 printk_once(KERN_WARNING "MTD handling any more.\n");
921 printk(KERN_WARNING "MTD handling any more.\n");
922 printed++;
923 }
924 } 921 }
925 err = -EINVAL; 922 err = -EINVAL;
926 goto free_out; 923 goto free_out;
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index f4573a96af24..a32ccb44065e 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -711,12 +711,12 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev)
711 return 0; 711 return 0;
712 } 712 }
713 713
714 pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL); 714 pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
715 if (!pinfo->gpios) 715 if (!pinfo->gpios)
716 return -ENOMEM; 716 return -ENOMEM;
717 memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios)); 717 memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
718 718
719 pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags), 719 pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
720 GFP_KERNEL); 720 GFP_KERNEL);
721 if (!pinfo->alow_flags) { 721 if (!pinfo->alow_flags) {
722 ret = -ENOMEM; 722 ret = -ENOMEM;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 2b5a691064b7..932ffdbf86d9 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2104,6 +2104,7 @@ config FB_MB862XX_LIME
2104 bool "Lime GDC" 2104 bool "Lime GDC"
2105 depends on FB_MB862XX 2105 depends on FB_MB862XX
2106 depends on OF && !FB_MB862XX_PCI_GDC 2106 depends on OF && !FB_MB862XX_PCI_GDC
2107 depends on PPC
2107 select FB_FOREIGN_ENDIAN 2108 select FB_FOREIGN_ENDIAN
2108 select FB_LITTLE_ENDIAN 2109 select FB_LITTLE_ENDIAN
2109 ---help--- 2110 ---help---
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 6995fe1e86d4..0bcc59eb37fa 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -859,43 +859,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
859 return 0; 859 return 0;
860} 860}
861 861
862/*
863 * Note that we are entered with the kernel locked.
864 */
865static int
866acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
867{
868 unsigned long off, start;
869 u32 len;
870
871 off = vma->vm_pgoff << PAGE_SHIFT;
872
873 start = info->fix.smem_start;
874 len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
875 start &= PAGE_MASK;
876 if ((vma->vm_end - vma->vm_start + off) > len)
877 return -EINVAL;
878 off += start;
879 vma->vm_pgoff = off >> PAGE_SHIFT;
880
881 /* This is an IO map - tell maydump to skip this VMA */
882 vma->vm_flags |= VM_IO;
883
884 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
885
886 /*
887 * Don't alter the page protection flags; we want to keep the area
888 * cached for better performance. This does mean that we may miss
889 * some updates to the screen occasionally, but process switches
890 * should cause the caches and buffers to be flushed often enough.
891 */
892 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
893 vma->vm_end - vma->vm_start,
894 vma->vm_page_prot))
895 return -EAGAIN;
896 return 0;
897}
898
899static struct fb_ops acornfb_ops = { 862static struct fb_ops acornfb_ops = {
900 .owner = THIS_MODULE, 863 .owner = THIS_MODULE,
901 .fb_check_var = acornfb_check_var, 864 .fb_check_var = acornfb_check_var,
@@ -905,7 +868,6 @@ static struct fb_ops acornfb_ops = {
905 .fb_fillrect = cfb_fillrect, 868 .fb_fillrect = cfb_fillrect,
906 .fb_copyarea = cfb_copyarea, 869 .fb_copyarea = cfb_copyarea,
907 .fb_imageblit = cfb_imageblit, 870 .fb_imageblit = cfb_imageblit,
908 .fb_mmap = acornfb_mmap,
909}; 871};
910 872
911/* 873/*
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index 2fb63f6ea2f1..5afd64482f55 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -345,7 +345,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
345 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel); 345 dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
346 dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz); 346 dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
347 347
348 if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) { 348 if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
349 dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock)); 349 dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
350 return -EINVAL; 350 return -EINVAL;
351 } 351 }
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 97a1f095f327..515cf1978d19 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -213,7 +213,6 @@ static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
213 PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | 213 PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb |
214 PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | 214 PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb |
215 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | 215 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
216 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
217 PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF); 216 PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
218 OUTPLL(pllPIXCLKS_CNTL, tmp); 217 OUTPLL(pllPIXCLKS_CNTL, tmp);
219 218
@@ -395,7 +394,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
395 PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb | 394 PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb |
396 PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb | 395 PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb |
397 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb | 396 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
398 PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb); 397 PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb);
399 OUTPLL(pllPIXCLKS_CNTL, tmp); 398 OUTPLL(pllPIXCLKS_CNTL, tmp);
400 399
401 tmp = INPLL(pllMCLK_MISC); 400 tmp = INPLL(pllMCLK_MISC);
diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c
index 37e60b1d2ed9..e49ae5edcc00 100644
--- a/drivers/video/bf54x-lq043fb.c
+++ b/drivers/video/bf54x-lq043fb.c
@@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user)
323 bfin_write_EPPI0_CONTROL(0); 323 bfin_write_EPPI0_CONTROL(0);
324 SSYNC(); 324 SSYNC();
325 disable_dma(CH_EPPI0); 325 disable_dma(CH_EPPI0);
326 memset(fbi->fb_buffer, 0, info->fix.smem_len);
327 } 326 }
328 327
329 spin_unlock(&fbi->lock); 328 spin_unlock(&fbi->lock);
@@ -530,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
530 return IRQ_HANDLED; 529 return IRQ_HANDLED;
531} 530}
532 531
533static int __init bfin_bf54x_probe(struct platform_device *pdev) 532static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
534{ 533{
535 struct bfin_bf54xfb_info *info; 534 struct bfin_bf54xfb_info *info;
536 struct fb_info *fbinfo; 535 struct fb_info *fbinfo;
@@ -626,14 +625,12 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
626 goto out3; 625 goto out3;
627 } 626 }
628 627
629 memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
630
631 fbinfo->screen_base = (void *)info->fb_buffer; 628 fbinfo->screen_base = (void *)info->fb_buffer;
632 fbinfo->fix.smem_start = (int)info->fb_buffer; 629 fbinfo->fix.smem_start = (int)info->fb_buffer;
633 630
634 fbinfo->fbops = &bfin_bf54x_fb_ops; 631 fbinfo->fbops = &bfin_bf54x_fb_ops;
635 632
636 fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL); 633 fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
637 if (!fbinfo->pseudo_palette) { 634 if (!fbinfo->pseudo_palette) {
638 printk(KERN_ERR DRIVER_NAME 635 printk(KERN_ERR DRIVER_NAME
639 "Fail to allocate pseudo_palette\n"); 636 "Fail to allocate pseudo_palette\n");
@@ -642,8 +639,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
642 goto out4; 639 goto out4;
643 } 640 }
644 641
645 memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16);
646
647 if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) 642 if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0)
648 < 0) { 643 < 0) {
649 printk(KERN_ERR DRIVER_NAME 644 printk(KERN_ERR DRIVER_NAME
@@ -712,7 +707,7 @@ out1:
712 return ret; 707 return ret;
713} 708}
714 709
715static int bfin_bf54x_remove(struct platform_device *pdev) 710static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
716{ 711{
717 712
718 struct fb_info *fbinfo = platform_get_drvdata(pdev); 713 struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -781,7 +776,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev)
781 776
782static struct platform_driver bfin_bf54x_driver = { 777static struct platform_driver bfin_bf54x_driver = {
783 .probe = bfin_bf54x_probe, 778 .probe = bfin_bf54x_probe,
784 .remove = bfin_bf54x_remove, 779 .remove = __devexit_p(bfin_bf54x_remove),
785 .suspend = bfin_bf54x_suspend, 780 .suspend = bfin_bf54x_suspend,
786 .resume = bfin_bf54x_resume, 781 .resume = bfin_bf54x_resume,
787 .driver = { 782 .driver = {
@@ -790,7 +785,7 @@ static struct platform_driver bfin_bf54x_driver = {
790 }, 785 },
791}; 786};
792 787
793static int __devinit bfin_bf54x_driver_init(void) 788static int __init bfin_bf54x_driver_init(void)
794{ 789{
795 return platform_driver_register(&bfin_bf54x_driver); 790 return platform_driver_register(&bfin_bf54x_driver);
796} 791}
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 90cfddabf1f7..5cc36cfbf07b 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user)
242 SSYNC(); 242 SSYNC();
243 disable_dma(CH_PPI); 243 disable_dma(CH_PPI);
244 bfin_t350mcqb_stop_timers(); 244 bfin_t350mcqb_stop_timers();
245 memset(fbi->fb_buffer, 0, info->fix.smem_len);
246 } 245 }
247 246
248 spin_unlock(&fbi->lock); 247 spin_unlock(&fbi->lock);
@@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
527 goto out3; 526 goto out3;
528 } 527 }
529 528
530 memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
531
532 fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; 529 fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
533 fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; 530 fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
534 531
@@ -602,7 +599,7 @@ out1:
602 return ret; 599 return ret;
603} 600}
604 601
605static int bfin_t350mcqb_remove(struct platform_device *pdev) 602static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
606{ 603{
607 604
608 struct fb_info *fbinfo = platform_get_drvdata(pdev); 605 struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -637,9 +634,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev)
637#ifdef CONFIG_PM 634#ifdef CONFIG_PM
638static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) 635static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state)
639{ 636{
640 struct fb_info *fbinfo = platform_get_drvdata(pdev);
641 struct bfin_t350mcqbfb_info *info = fbinfo->par;
642
643 bfin_t350mcqb_disable_ppi(); 637 bfin_t350mcqb_disable_ppi();
644 disable_dma(CH_PPI); 638 disable_dma(CH_PPI);
645 bfin_write_PPI_STATUS(0xFFFF); 639 bfin_write_PPI_STATUS(0xFFFF);
@@ -649,9 +643,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat
649 643
650static int bfin_t350mcqb_resume(struct platform_device *pdev) 644static int bfin_t350mcqb_resume(struct platform_device *pdev)
651{ 645{
652 struct fb_info *fbinfo = platform_get_drvdata(pdev);
653 struct bfin_t350mcqbfb_info *info = fbinfo->par;
654
655 enable_dma(CH_PPI); 646 enable_dma(CH_PPI);
656 bfin_t350mcqb_enable_ppi(); 647 bfin_t350mcqb_enable_ppi();
657 648
@@ -664,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev)
664 655
665static struct platform_driver bfin_t350mcqb_driver = { 656static struct platform_driver bfin_t350mcqb_driver = {
666 .probe = bfin_t350mcqb_probe, 657 .probe = bfin_t350mcqb_probe,
667 .remove = bfin_t350mcqb_remove, 658 .remove = __devexit_p(bfin_t350mcqb_remove),
668 .suspend = bfin_t350mcqb_suspend, 659 .suspend = bfin_t350mcqb_suspend,
669 .resume = bfin_t350mcqb_resume, 660 .resume = bfin_t350mcqb_resume,
670 .driver = { 661 .driver = {
@@ -673,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = {
673 }, 664 },
674}; 665};
675 666
676static int __devinit bfin_t350mcqb_driver_init(void) 667static int __init bfin_t350mcqb_driver_init(void)
677{ 668{
678 return platform_driver_register(&bfin_t350mcqb_driver); 669 return platform_driver_register(&bfin_t350mcqb_driver);
679} 670}
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index c7ff3c1a266a..0c02f8ec4bf3 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_bas
562 if (ret < 0) 562 if (ret < 0)
563 goto err_free_fb; 563 goto err_free_fb;
564 564
565 if (fb_mode > ARRAY_SIZE(carmine_modedb)) 565 if (fb_mode >= ARRAY_SIZE(carmine_modedb))
566 fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; 566 fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
567 567
568 par->cur_mode = par->new_mode = ~0; 568 par->cur_mode = par->new_mode = ~0;
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 777389c40988..57b9d276497e 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -414,7 +414,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
414 } 414 }
415 415
416 pci_set_drvdata(dp, p); 416 pci_set_drvdata(dp, p);
417 p->device = &dp->dev;
418 417
419 init_chips(p, addr); 418 init_chips(p, addr);
420 419
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 8dea2bc92705..eb12182b2059 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev)
280 info->pseudo_palette = info->par; 280 info->pseudo_palette = info->par;
281 info->par = NULL; 281 info->par = NULL;
282 282
283 info->aperture_base = efifb_fix.smem_start;
284 info->aperture_size = size_total;
285
283 info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len); 286 info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
284 if (!info->screen_base) { 287 if (!info->screen_base) {
285 printk(KERN_ERR "efifb: abort, cannot ioremap video memory " 288 printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
@@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev)
337 info->fbops = &efifb_ops; 340 info->fbops = &efifb_ops;
338 info->var = efifb_defined; 341 info->var = efifb_defined;
339 info->fix = efifb_fix; 342 info->fix = efifb_fix;
340 info->flags = FBINFO_FLAG_DEFAULT; 343 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
341 344
342 if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) { 345 if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
343 printk(KERN_ERR "efifb: cannot allocate colormap\n"); 346 printk(KERN_ERR "efifb: cannot allocate colormap\n");
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index d412a1ddc12f..f8a09bf8d0cd 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi)
1462 return 0; 1462 return 0;
1463} 1463}
1464 1464
1465static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
1466{
1467 /* is the generic aperture base the same as the HW one */
1468 if (gen->aperture_base == hw->aperture_base)
1469 return true;
1470 /* is the generic aperture base inside the hw base->hw base+size */
1471 if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size)
1472 return true;
1473 return false;
1474}
1465/** 1475/**
1466 * register_framebuffer - registers a frame buffer device 1476 * register_framebuffer - registers a frame buffer device
1467 * @fb_info: frame buffer info structure 1477 * @fb_info: frame buffer info structure
@@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info)
1485 if (fb_check_foreignness(fb_info)) 1495 if (fb_check_foreignness(fb_info))
1486 return -ENOSYS; 1496 return -ENOSYS;
1487 1497
1498 /* check all firmware fbs and kick off if the base addr overlaps */
1499 for (i = 0 ; i < FB_MAX; i++) {
1500 if (!registered_fb[i])
1501 continue;
1502
1503 if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
1504 if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
1505 printk(KERN_ERR "fb: conflicting fb hw usage "
1506 "%s vs %s - removing generic driver\n",
1507 fb_info->fix.id,
1508 registered_fb[i]->fix.id);
1509 unregister_framebuffer(registered_fb[i]);
1510 break;
1511 }
1512 }
1513 }
1514
1488 num_registered_fb++; 1515 num_registered_fb++;
1489 for (i = 0 ; i < FB_MAX; i++) 1516 for (i = 0 ; i < FB_MAX; i++)
1490 if (!registered_fb[i]) 1517 if (!registered_fb[i])
@@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info)
1586 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1613 device_destroy(fb_class, MKDEV(FB_MAJOR, i));
1587 event.info = fb_info; 1614 event.info = fb_info;
1588 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1615 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
1616
1617 /* this may free fb info */
1618 if (fb_info->fbops->fb_destroy)
1619 fb_info->fbops->fb_destroy(fb_info);
1589done: 1620done:
1590 return ret; 1621 return ret;
1591} 1622}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 3a81060137a2..15d200109446 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -395,17 +395,16 @@ int __init igafb_init(void)
395 /* We leak a reference here but as it cannot be unloaded this is 395 /* We leak a reference here but as it cannot be unloaded this is
396 fine. If you write unload code remember to free it in unload */ 396 fine. If you write unload code remember to free it in unload */
397 397
398 size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16; 398 size = sizeof(struct iga_par) + sizeof(u32)*16;
399 399
400 info = kzalloc(size, GFP_ATOMIC); 400 info = framebuffer_alloc(size, &pdev->dev);
401 if (!info) { 401 if (!info) {
402 printk("igafb_init: can't alloc fb_info\n"); 402 printk("igafb_init: can't alloc fb_info\n");
403 pci_dev_put(pdev); 403 pci_dev_put(pdev);
404 return -ENOMEM; 404 return -ENOMEM;
405 } 405 }
406 406
407 par = (struct iga_par *) (info + 1); 407 par = info->par;
408
409 408
410 if ((addr = pdev->resource[0].start) == 0) { 409 if ((addr = pdev->resource[0].start) == 0) {
411 printk("igafb_init: no memory start\n"); 410 printk("igafb_init: no memory start\n");
@@ -526,7 +525,6 @@ int __init igafb_init(void)
526 info->var = default_var; 525 info->var = default_var;
527 info->fix = igafb_fix; 526 info->fix = igafb_fix;
528 info->pseudo_palette = (void *)(par + 1); 527 info->pseudo_palette = (void *)(par + 1);
529 info->device = &pdev->dev;
530 528
531 if (!iga_init(info, par)) { 529 if (!iga_init(info, par)) {
532 iounmap((void *)par->io_base); 530 iounmap((void *)par->io_base);
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index ace14fe02fc4..0cafd642fbc0 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -1365,6 +1365,11 @@ static int intelfb_set_par(struct fb_info *info)
1365 DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres, 1365 DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
1366 info->var.yres, info->var.bits_per_pixel); 1366 info->var.yres, info->var.bits_per_pixel);
1367 1367
1368 /*
1369 * Disable VCO prior to timing register change.
1370 */
1371 OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE);
1372
1368 intelfb_blank(FB_BLANK_POWERDOWN, info); 1373 intelfb_blank(FB_BLANK_POWERDOWN, info);
1369 1374
1370 if (ACCEL(dinfo, info)) 1375 if (ACCEL(dinfo, info))
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index b91251d1fe41..3b437813584c 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -37,22 +37,24 @@ extra-y += $(call logo-cfiles,_clut224,ppm)
37# Gray 256 37# Gray 256
38extra-y += $(call logo-cfiles,_gray256,pgm) 38extra-y += $(call logo-cfiles,_gray256,pgm)
39 39
40pnmtologo := scripts/pnmtologo
41
40# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..." 42# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
41quiet_cmd_logo = LOGO $@ 43quiet_cmd_logo = LOGO $@
42 cmd_logo = scripts/pnmtologo \ 44 cmd_logo = $(pnmtologo) \
43 -t $(patsubst $*_%,%,$(notdir $(basename $<))) \ 45 -t $(patsubst $*_%,%,$(notdir $(basename $<))) \
44 -n $(notdir $(basename $<)) -o $@ $< 46 -n $(notdir $(basename $<)) -o $@ $<
45 47
46$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE 48$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE
47 $(call if_changed,logo) 49 $(call if_changed,logo)
48 50
49$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE 51$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE
50 $(call if_changed,logo) 52 $(call if_changed,logo)
51 53
52$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE 54$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE
53 $(call if_changed,logo) 55 $(call if_changed,logo)
54 56
55$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE 57$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE
56 $(call if_changed,logo) 58 $(call if_changed,logo)
57 59
58# Files generated that shall be removed upon make clean 60# Files generated that shall be removed upon make clean
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 2e85a2b52d05..ea7a8ccc830c 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -21,21 +21,6 @@
21#include <asm/bootinfo.h> 21#include <asm/bootinfo.h>
22#endif 22#endif
23 23
24extern const struct linux_logo logo_linux_mono;
25extern const struct linux_logo logo_linux_vga16;
26extern const struct linux_logo logo_linux_clut224;
27extern const struct linux_logo logo_blackfin_vga16;
28extern const struct linux_logo logo_blackfin_clut224;
29extern const struct linux_logo logo_dec_clut224;
30extern const struct linux_logo logo_mac_clut224;
31extern const struct linux_logo logo_parisc_clut224;
32extern const struct linux_logo logo_sgi_clut224;
33extern const struct linux_logo logo_sun_clut224;
34extern const struct linux_logo logo_superh_mono;
35extern const struct linux_logo logo_superh_vga16;
36extern const struct linux_logo logo_superh_clut224;
37extern const struct linux_logo logo_m32r_clut224;
38
39static int nologo; 24static int nologo;
40module_param(nologo, bool, 0); 25module_param(nologo, bool, 0);
41MODULE_PARM_DESC(nologo, "Disables startup logo"); 26MODULE_PARM_DESC(nologo, "Disables startup logo");
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index fb64234a3825..a28e3cfbbf70 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -19,7 +19,7 @@
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/pci.h> 21#include <linux/pci.h>
22#if defined(CONFIG_PPC_OF) 22#if defined(CONFIG_OF)
23#include <linux/of_platform.h> 23#include <linux/of_platform.h>
24#endif 24#endif
25#include "mb862xxfb.h" 25#include "mb862xxfb.h"
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 16186240c5f2..34e4e7995169 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -264,6 +264,14 @@ static const struct fb_videomode modedb[] = {
264 /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ 264 /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
265 NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, 265 NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
266 0, FB_VMODE_NONINTERLACED 266 0, FB_VMODE_NONINTERLACED
267 }, {
268 /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
269 NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5,
270 0, FB_VMODE_INTERLACED
271 }, {
272 /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
273 NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5,
274 0, FB_VMODE_INTERLACED
267 }, 275 },
268}; 276};
269 277
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index e1d9eeb1aeaf..4d8c54c23dd7 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -378,7 +378,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
378 struct fb_fix_screeninfo *fix; 378 struct fb_fix_screeninfo *fix;
379 struct fb_var_screeninfo *var; 379 struct fb_var_screeninfo *var;
380 struct fb_info *info; 380 struct fb_info *info;
381 int size;
382 381
383 if (!request_mem_region(res_start, res_size, "offb")) 382 if (!request_mem_region(res_start, res_size, "offb"))
384 return; 383 return;
@@ -393,15 +392,12 @@ static void __init offb_init_fb(const char *name, const char *full_name,
393 return; 392 return;
394 } 393 }
395 394
396 size = sizeof(struct fb_info) + sizeof(u32) * 16; 395 info = framebuffer_alloc(sizeof(u32) * 16, NULL);
397
398 info = kmalloc(size, GFP_ATOMIC);
399 396
400 if (info == 0) { 397 if (info == 0) {
401 release_mem_region(res_start, res_size); 398 release_mem_region(res_start, res_size);
402 return; 399 return;
403 } 400 }
404 memset(info, 0, size);
405 401
406 fix = &info->fix; 402 fix = &info->fix;
407 var = &info->var; 403 var = &info->var;
@@ -497,7 +493,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
497 iounmap(par->cmap_adr); 493 iounmap(par->cmap_adr);
498 par->cmap_adr = NULL; 494 par->cmap_adr = NULL;
499 iounmap(info->screen_base); 495 iounmap(info->screen_base);
500 kfree(info); 496 framebuffer_release(info);
501 release_mem_region(res_start, res_size); 497 release_mem_region(res_start, res_size);
502 return; 498 return;
503 } 499 }
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index c6dd924976a4..36436ee6c1a4 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -1748,7 +1748,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev)
1748 pci_set_drvdata(pdev, NULL); 1748 pci_set_drvdata(pdev, NULL);
1749 fb_dealloc_cmap(&info->cmap); 1749 fb_dealloc_cmap(&info->cmap);
1750 kfree(info->pixmap.addr); 1750 kfree(info->pixmap.addr);
1751 kfree(info); 1751 framebuffer_release(info);
1752} 1752}
1753 1753
1754static struct pci_device_id pm2fb_id_table[] = { 1754static struct pci_device_id pm2fb_id_table[] = {
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 0726aecf3b7e..0deb0a8867b7 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -2,6 +2,7 @@
2 * 2 *
3 * (c) 2004 Simtec Electronics 3 * (c) 2004 Simtec Electronics
4 * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org> 4 * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
5 * (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
5 * 6 *
6 * Driver for Epson S1D13xxx series framebuffer chips 7 * Driver for Epson S1D13xxx series framebuffer chips
7 * 8 *
@@ -10,18 +11,10 @@
10 * linux/drivers/video/epson1355fb.c 11 * linux/drivers/video/epson1355fb.c
11 * linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson) 12 * linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
12 * 13 *
13 * Note, currently only tested on S1D13806 with 16bit CRT.
14 * As such, this driver might still contain some hardcoded bits relating to
15 * S1D13806.
16 * Making it work on other S1D13XXX chips should merely be a matter of adding
17 * a few switch()s, some missing glue here and there maybe, and split header
18 * files.
19 *
20 * TODO: - handle dual screen display (CRT and LCD at the same time). 14 * TODO: - handle dual screen display (CRT and LCD at the same time).
21 * - check_var(), mode change, etc. 15 * - check_var(), mode change, etc.
22 * - PM untested. 16 * - probably not SMP safe :)
23 * - Accelerated interfaces. 17 * - support all bitblt operations on all cards
24 * - Probably not SMP safe :)
25 * 18 *
26 * This file is subject to the terms and conditions of the GNU General Public 19 * This file is subject to the terms and conditions of the GNU General Public
27 * License. See the file COPYING in the main directory of this archive for 20 * License. See the file COPYING in the main directory of this archive for
@@ -31,19 +24,24 @@
31#include <linux/module.h> 24#include <linux/module.h>
32#include <linux/platform_device.h> 25#include <linux/platform_device.h>
33#include <linux/delay.h> 26#include <linux/delay.h>
34
35#include <linux/types.h> 27#include <linux/types.h>
36#include <linux/errno.h> 28#include <linux/errno.h>
37#include <linux/mm.h> 29#include <linux/mm.h>
38#include <linux/mman.h> 30#include <linux/mman.h>
39#include <linux/fb.h> 31#include <linux/fb.h>
32#include <linux/spinlock_types.h>
33#include <linux/spinlock.h>
40 34
41#include <asm/io.h> 35#include <asm/io.h>
42 36
43#include <video/s1d13xxxfb.h> 37#include <video/s1d13xxxfb.h>
44 38
45#define PFX "s1d13xxxfb: " 39#define PFX "s1d13xxxfb: "
40#define BLIT "s1d13xxxfb_bitblt: "
46 41
42/*
43 * set this to enable debugging on general functions
44 */
47#if 0 45#if 0
48#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0) 46#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
49#else 47#else
@@ -51,7 +49,21 @@
51#endif 49#endif
52 50
53/* 51/*
54 * List of card production ids 52 * set this to enable debugging on 2D acceleration
53 */
54#if 0
55#define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0)
56#else
57#define dbg_blit(fmt, args...) do { } while (0)
58#endif
59
60/*
61 * we make sure only one bitblt operation is running
62 */
63static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock);
64
65/*
66 * list of card production ids
55 */ 67 */
56static const int s1d13xxxfb_prod_ids[] = { 68static const int s1d13xxxfb_prod_ids[] = {
57 S1D13505_PROD_ID, 69 S1D13505_PROD_ID,
@@ -69,7 +81,7 @@ static const char *s1d13xxxfb_prod_names[] = {
69}; 81};
70 82
71/* 83/*
72 * Here we define the default struct fb_fix_screeninfo 84 * here we define the default struct fb_fix_screeninfo
73 */ 85 */
74static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = { 86static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
75 .id = S1D_FBID, 87 .id = S1D_FBID,
@@ -145,8 +157,10 @@ crt_enable(struct s1d13xxxfb_par *par, int enable)
145 s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode); 157 s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
146} 158}
147 159
148/* framebuffer control routines */
149 160
161/*************************************************************
162 framebuffer control functions
163 *************************************************************/
150static inline void 164static inline void
151s1d13xxxfb_setup_pseudocolour(struct fb_info *info) 165s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
152{ 166{
@@ -242,13 +256,13 @@ s1d13xxxfb_set_par(struct fb_info *info)
242} 256}
243 257
244/** 258/**
245 * s1d13xxxfb_setcolreg - sets a color register. 259 * s1d13xxxfb_setcolreg - sets a color register.
246 * @regno: Which register in the CLUT we are programming 260 * @regno: Which register in the CLUT we are programming
247 * @red: The red value which can be up to 16 bits wide 261 * @red: The red value which can be up to 16 bits wide
248 * @green: The green value which can be up to 16 bits wide 262 * @green: The green value which can be up to 16 bits wide
249 * @blue: The blue value which can be up to 16 bits wide. 263 * @blue: The blue value which can be up to 16 bits wide.
250 * @transp: If supported the alpha value which can be up to 16 bits wide. 264 * @transp: If supported the alpha value which can be up to 16 bits wide.
251 * @info: frame buffer info structure 265 * @info: frame buffer info structure
252 * 266 *
253 * Returns negative errno on error, or zero on success. 267 * Returns negative errno on error, or zero on success.
254 */ 268 */
@@ -351,15 +365,15 @@ s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
351} 365}
352 366
353/** 367/**
354 * s1d13xxxfb_pan_display - Pans the display. 368 * s1d13xxxfb_pan_display - Pans the display.
355 * @var: frame buffer variable screen structure 369 * @var: frame buffer variable screen structure
356 * @info: frame buffer structure that represents a single frame buffer 370 * @info: frame buffer structure that represents a single frame buffer
357 * 371 *
358 * Pan (or wrap, depending on the `vmode' field) the display using the 372 * Pan (or wrap, depending on the `vmode' field) the display using the
359 * `yoffset' field of the `var' structure (`xoffset' not yet supported). 373 * `yoffset' field of the `var' structure (`xoffset' not yet supported).
360 * If the values don't fit, return -EINVAL. 374 * If the values don't fit, return -EINVAL.
361 * 375 *
362 * Returns negative errno on error, or zero on success. 376 * Returns negative errno on error, or zero on success.
363 */ 377 */
364static int 378static int
365s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 379s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -390,8 +404,259 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
390 return 0; 404 return 0;
391} 405}
392 406
393/* framebuffer information structures */ 407/************************************************************
408 functions to handle bitblt acceleration
409 ************************************************************/
410
411/**
412 * bltbit_wait_bitset - waits for change in register value
413 * @info : framebuffer structure
414 * @bit : value expected in register
415 * @timeout : ...
416 *
417 * waits until value changes INTO bit
418 */
419static u8
420bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout)
421{
422 while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) {
423 udelay(10);
424 if (!--timeout) {
425 dbg_blit("wait_bitset timeout\n");
426 break;
427 }
428 }
429
430 return timeout;
431}
432
433/**
434 * bltbit_wait_bitclear - waits for change in register value
435 * @info : frambuffer structure
436 * @bit : value currently in register
437 * @timeout : ...
438 *
439 * waits until value changes FROM bit
440 *
441 */
442static u8
443bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
444{
445 while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) {
446 udelay(10);
447 if (!--timeout) {
448 dbg_blit("wait_bitclear timeout\n");
449 break;
450 }
451 }
452
453 return timeout;
454}
455
456/**
457 * bltbit_fifo_status - checks the current status of the fifo
458 * @info : framebuffer structure
459 *
460 * returns number of free words in buffer
461 */
462static u8
463bltbit_fifo_status(struct fb_info *info)
464{
465 u8 status;
394 466
467 status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0);
468
469 /* its empty so room for 16 words */
470 if (status & BBLT_FIFO_EMPTY)
471 return 16;
472
473 /* its full so we dont want to add */
474 if (status & BBLT_FIFO_FULL)
475 return 0;
476
477 /* its atleast half full but we can add one atleast */
478 if (status & BBLT_FIFO_NOT_FULL)
479 return 1;
480
481 return 0;
482}
483
484/*
485 * s1d13xxxfb_bitblt_copyarea - accelerated copyarea function
486 * @info : framebuffer structure
487 * @area : fb_copyarea structure
488 *
489 * supports (atleast) S1D13506
490 *
491 */
492static void
493s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area)
494{
495 u32 dst, src;
496 u32 stride;
497 u16 reverse = 0;
498 u16 sx = area->sx, sy = area->sy;
499 u16 dx = area->dx, dy = area->dy;
500 u16 width = area->width, height = area->height;
501 u16 bpp;
502
503 spin_lock(&s1d13xxxfb_bitblt_lock);
504
505 /* bytes per xres line */
506 bpp = (info->var.bits_per_pixel >> 3);
507 stride = bpp * info->var.xres;
508
509 /* reverse, calculate the last pixel in rectangle */
510 if ((dy > sy) || ((dy == sy) && (dx >= sx))) {
511 dst = (((dy + height - 1) * stride) + (bpp * (dx + width - 1)));
512 src = (((sy + height - 1) * stride) + (bpp * (sx + width - 1)));
513 reverse = 1;
514 /* not reverse, calculate the first pixel in rectangle */
515 } else { /* (y * xres) + (bpp * x) */
516 dst = (dy * stride) + (bpp * dx);
517 src = (sy * stride) + (bpp * sx);
518 }
519
520 /* set source adress */
521 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff));
522 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff);
523 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff);
524
525 /* set destination adress */
526 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff));
527 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff);
528 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff);
529
530 /* program height and width */
531 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, (width & 0xff) - 1);
532 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (width >> 8));
533
534 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, (height & 0xff) - 1);
535 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (height >> 8));
536
537 /* negative direction ROP */
538 if (reverse == 1) {
539 dbg_blit("(copyarea) negative rop\n");
540 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x03);
541 } else /* positive direction ROP */ {
542 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x02);
543 dbg_blit("(copyarea) positive rop\n");
544 }
545
546 /* set for rectangel mode and not linear */
547 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
548
549 /* setup the bpp 1 = 16bpp, 0 = 8bpp*/
550 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (bpp >> 1));
551
552 /* set words per xres */
553 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (stride >> 1) & 0xff);
554 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (stride >> 9));
555
556 dbg_blit("(copyarea) dx=%d, dy=%d\n", dx, dy);
557 dbg_blit("(copyarea) sx=%d, sy=%d\n", sx, sy);
558 dbg_blit("(copyarea) width=%d, height=%d\n", width - 1, height - 1);
559 dbg_blit("(copyarea) stride=%d\n", stride);
560 dbg_blit("(copyarea) bpp=%d=0x0%d, mem_offset1=%d, mem_offset2=%d\n", bpp, (bpp >> 1),
561 (stride >> 1) & 0xff, stride >> 9);
562
563 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CC_EXP, 0x0c);
564
565 /* initialize the engine */
566 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
567
568 /* wait to complete */
569 bltbit_wait_bitclear(info, 0x80, 8000);
570
571 spin_unlock(&s1d13xxxfb_bitblt_lock);
572}
573
574/**
575 *
576 * s1d13xxxfb_bitblt_solidfill - accelerated solidfill function
577 * @info : framebuffer structure
578 * @rect : fb_fillrect structure
579 *
580 * supports (atleast 13506)
581 *
582 **/
583static void
584s1d13xxxfb_bitblt_solidfill(struct fb_info *info, const struct fb_fillrect *rect)
585{
586 u32 screen_stride, dest;
587 u32 fg;
588 u16 bpp = (info->var.bits_per_pixel >> 3);
589
590 /* grab spinlock */
591 spin_lock(&s1d13xxxfb_bitblt_lock);
592
593 /* bytes per x width */
594 screen_stride = (bpp * info->var.xres);
595
596 /* bytes to starting point */
597 dest = ((rect->dy * screen_stride) + (bpp * rect->dx));
598
599 dbg_blit("(solidfill) dx=%d, dy=%d, stride=%d, dest=%d\n"
600 "(solidfill) : rect_width=%d, rect_height=%d\n",
601 rect->dx, rect->dy, screen_stride, dest,
602 rect->width - 1, rect->height - 1);
603
604 dbg_blit("(solidfill) : xres=%d, yres=%d, bpp=%d\n",
605 info->var.xres, info->var.yres,
606 info->var.bits_per_pixel);
607 dbg_blit("(solidfill) : rop=%d\n", rect->rop);
608
609 /* We split the destination into the three registers */
610 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dest & 0x00ff));
611 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, ((dest >> 8) & 0x00ff));
612 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, ((dest >> 16) & 0x00ff));
613
614 /* give information regarding rectangel width */
615 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, ((rect->width) & 0x00ff) - 1);
616 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (rect->width >> 8));
617
618 /* give information regarding rectangel height */
619 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, ((rect->height) & 0x00ff) - 1);
620 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (rect->height >> 8));
621
622 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
623 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
624 fg = ((u32 *)info->pseudo_palette)[rect->color];
625 dbg_blit("(solidfill) truecolor/directcolor\n");
626 dbg_blit("(solidfill) pseudo_palette[%d] = %d\n", rect->color, fg);
627 } else {
628 fg = rect->color;
629 dbg_blit("(solidfill) color = %d\n", rect->color);
630 }
631
632 /* set foreground color */
633 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff));
634 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff);
635
636 /* set rectangual region of memory (rectangle and not linear) */
637 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
638
639 /* set operation mode SOLID_FILL */
640 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL);
641
642 /* set bits per pixel (1 = 16bpp, 0 = 8bpp) */
643 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4));
644
645 /* set the memory offset for the bblt in word sizes */
646 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff);
647 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9));
648
649 /* and away we go.... */
650 s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
651
652 /* wait until its done */
653 bltbit_wait_bitclear(info, 0x80, 8000);
654
655 /* let others play */
656 spin_unlock(&s1d13xxxfb_bitblt_lock);
657}
658
659/* framebuffer information structures */
395static struct fb_ops s1d13xxxfb_fbops = { 660static struct fb_ops s1d13xxxfb_fbops = {
396 .owner = THIS_MODULE, 661 .owner = THIS_MODULE,
397 .fb_set_par = s1d13xxxfb_set_par, 662 .fb_set_par = s1d13xxxfb_set_par,
@@ -400,7 +665,7 @@ static struct fb_ops s1d13xxxfb_fbops = {
400 665
401 .fb_pan_display = s1d13xxxfb_pan_display, 666 .fb_pan_display = s1d13xxxfb_pan_display,
402 667
403 /* to be replaced by any acceleration we can */ 668 /* gets replaced at chip detection time */
404 .fb_fillrect = cfb_fillrect, 669 .fb_fillrect = cfb_fillrect,
405 .fb_copyarea = cfb_copyarea, 670 .fb_copyarea = cfb_copyarea,
406 .fb_imageblit = cfb_imageblit, 671 .fb_imageblit = cfb_imageblit,
@@ -412,9 +677,9 @@ static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
412}; 677};
413 678
414/** 679/**
415 * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to 680 * s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
416 * hardware setup. 681 * hardware setup.
417 * @info: frame buffer structure 682 * @info: frame buffer structure
418 * 683 *
419 * We setup the framebuffer structures according to the current 684 * We setup the framebuffer structures according to the current
420 * hardware setup. On some machines, the BIOS will have filled 685 * hardware setup. On some machines, the BIOS will have filled
@@ -569,7 +834,6 @@ s1d13xxxfb_probe(struct platform_device *pdev)
569 if (pdata && pdata->platform_init_video) 834 if (pdata && pdata->platform_init_video)
570 pdata->platform_init_video(); 835 pdata->platform_init_video();
571 836
572
573 if (pdev->num_resources != 2) { 837 if (pdev->num_resources != 2) {
574 dev_err(&pdev->dev, "invalid num_resources: %i\n", 838 dev_err(&pdev->dev, "invalid num_resources: %i\n",
575 pdev->num_resources); 839 pdev->num_resources);
@@ -655,16 +919,27 @@ s1d13xxxfb_probe(struct platform_device *pdev)
655 919
656 info->fix = s1d13xxxfb_fix; 920 info->fix = s1d13xxxfb_fix;
657 info->fix.mmio_start = pdev->resource[1].start; 921 info->fix.mmio_start = pdev->resource[1].start;
658 info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1; 922 info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1;
659 info->fix.smem_start = pdev->resource[0].start; 923 info->fix.smem_start = pdev->resource[0].start;
660 info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1; 924 info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1;
661 925
662 printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n", 926 printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
663 default_par->regs, info->fix.smem_len / 1024, info->screen_base); 927 default_par->regs, info->fix.smem_len / 1024, info->screen_base);
664 928
665 info->par = default_par; 929 info->par = default_par;
666 info->fbops = &s1d13xxxfb_fbops;
667 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; 930 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
931 info->fbops = &s1d13xxxfb_fbops;
932
933 switch(prod_id) {
934 case S1D13506_PROD_ID: /* activate acceleration */
935 s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill;
936 s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea;
937 info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
938 FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
939 break;
940 default:
941 break;
942 }
668 943
669 /* perform "manual" chip initialization, if needed */ 944 /* perform "manual" chip initialization, if needed */
670 if (pdata && pdata->initregs) 945 if (pdata && pdata->initregs)
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index d3a568e6b169..43680e545427 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -358,9 +358,16 @@ static int s3c_fb_set_par(struct fb_info *info)
358 writel(data, regs + VIDOSD_B(win_no)); 358 writel(data, regs + VIDOSD_B(win_no));
359 359
360 data = var->xres * var->yres; 360 data = var->xres * var->yres;
361
362 u32 osdc_data = 0;
363
364 osdc_data = VIDISD14C_ALPHA1_R(0xf) |
365 VIDISD14C_ALPHA1_G(0xf) |
366 VIDISD14C_ALPHA1_B(0xf);
367
361 if (s3c_fb_has_osd_d(win_no)) { 368 if (s3c_fb_has_osd_d(win_no)) {
362 writel(data, regs + VIDOSD_D(win_no)); 369 writel(data, regs + VIDOSD_D(win_no));
363 writel(0, regs + VIDOSD_C(win_no)); 370 writel(osdc_data, regs + VIDOSD_C(win_no));
364 } else 371 } else
365 writel(data, regs + VIDOSD_C(win_no)); 372 writel(data, regs + VIDOSD_C(win_no));
366 373
@@ -409,8 +416,12 @@ static int s3c_fb_set_par(struct fb_info *info)
409 data |= WINCON1_BPPMODE_19BPP_A1666; 416 data |= WINCON1_BPPMODE_19BPP_A1666;
410 else 417 else
411 data |= WINCON1_BPPMODE_18BPP_666; 418 data |= WINCON1_BPPMODE_18BPP_666;
412 } else if (var->transp.length != 0) 419 } else if (var->transp.length == 1)
413 data |= WINCON1_BPPMODE_25BPP_A1888; 420 data |= WINCON1_BPPMODE_25BPP_A1888
421 | WINCON1_BLD_PIX;
422 else if (var->transp.length == 4)
423 data |= WINCON1_BPPMODE_28BPP_A4888
424 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
414 else 425 else
415 data |= WINCON0_BPPMODE_24BPP_888; 426 data |= WINCON0_BPPMODE_24BPP_888;
416 427
@@ -418,6 +429,20 @@ static int s3c_fb_set_par(struct fb_info *info)
418 break; 429 break;
419 } 430 }
420 431
432 /* It has no color key control register for window0 */
433 if (win_no > 0) {
434 u32 keycon0_data = 0, keycon1_data = 0;
435
436 keycon0_data = ~(WxKEYCON0_KEYBL_EN |
437 WxKEYCON0_KEYEN_F |
438 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
439
440 keycon1_data = WxKEYCON1_COLVAL(0xffffff);
441
442 writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
443 writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
444 }
445
421 writel(data, regs + WINCON(win_no)); 446 writel(data, regs + WINCON(win_no));
422 writel(0x0, regs + WINxMAP(win_no)); 447 writel(0x0, regs + WINxMAP(win_no));
423 448
@@ -700,9 +725,12 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
700 */ 725 */
701static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win) 726static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
702{ 727{
703 fb_dealloc_cmap(&win->fbinfo->cmap); 728 if (win->fbinfo) {
704 unregister_framebuffer(win->fbinfo); 729 unregister_framebuffer(win->fbinfo);
705 s3c_fb_free_memory(sfb, win); 730 fb_dealloc_cmap(&win->fbinfo->cmap);
731 s3c_fb_free_memory(sfb, win);
732 framebuffer_release(win->fbinfo);
733 }
706} 734}
707 735
708/** 736/**
@@ -753,7 +781,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
753 ret = s3c_fb_alloc_memory(sfb, win); 781 ret = s3c_fb_alloc_memory(sfb, win);
754 if (ret) { 782 if (ret) {
755 dev_err(sfb->dev, "failed to allocate display memory\n"); 783 dev_err(sfb->dev, "failed to allocate display memory\n");
756 goto err_framebuffer; 784 return ret;
757 } 785 }
758 786
759 /* setup the r/b/g positions for the window's palette */ 787 /* setup the r/b/g positions for the window's palette */
@@ -776,7 +804,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
776 ret = s3c_fb_check_var(&fbinfo->var, fbinfo); 804 ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
777 if (ret < 0) { 805 if (ret < 0) {
778 dev_err(sfb->dev, "check_var failed on initial video params\n"); 806 dev_err(sfb->dev, "check_var failed on initial video params\n");
779 goto err_alloc_mem; 807 return ret;
780 } 808 }
781 809
782 /* create initial colour map */ 810 /* create initial colour map */
@@ -796,20 +824,13 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
796 ret = register_framebuffer(fbinfo); 824 ret = register_framebuffer(fbinfo);
797 if (ret < 0) { 825 if (ret < 0) {
798 dev_err(sfb->dev, "failed to register framebuffer\n"); 826 dev_err(sfb->dev, "failed to register framebuffer\n");
799 goto err_alloc_mem; 827 return ret;
800 } 828 }
801 829
802 *res = win; 830 *res = win;
803 dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id); 831 dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
804 832
805 return 0; 833 return 0;
806
807err_alloc_mem:
808 s3c_fb_free_memory(sfb, win);
809
810err_framebuffer:
811 unregister_framebuffer(fbinfo);
812 return ret;
813} 834}
814 835
815/** 836/**
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index b0b4513ba537..7da0027e2409 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -24,6 +24,7 @@
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/clk.h> 26#include <linux/clk.h>
27#include <linux/cpufreq.h>
27 28
28#include <asm/io.h> 29#include <asm/io.h>
29#include <asm/div64.h> 30#include <asm/div64.h>
@@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info)
89static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi, 90static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
90 unsigned long pixclk) 91 unsigned long pixclk)
91{ 92{
92 unsigned long clk = clk_get_rate(fbi->clk); 93 unsigned long clk = fbi->clk_rate;
93 unsigned long long div; 94 unsigned long long div;
94 95
95 /* pixclk is in picoseconds, our clock is in Hz 96 /* pixclk is in picoseconds, our clock is in Hz
@@ -758,6 +759,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
758 return IRQ_HANDLED; 759 return IRQ_HANDLED;
759} 760}
760 761
762#ifdef CONFIG_CPU_FREQ
763
764static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
765 unsigned long val, void *data)
766{
767 struct cpufreq_freqs *freqs = data;
768 struct s3c2410fb_info *info;
769 struct fb_info *fbinfo;
770 long delta_f;
771
772 info = container_of(nb, struct s3c2410fb_info, freq_transition);
773 fbinfo = platform_get_drvdata(to_platform_device(info->dev));
774
775 /* work out change, <0 for speed-up */
776 delta_f = info->clk_rate - clk_get_rate(info->clk);
777
778 if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
779 (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
780 info->clk_rate = clk_get_rate(info->clk);
781 s3c2410fb_activate_var(fbinfo);
782 }
783
784 return 0;
785}
786
787static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
788{
789 info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
790
791 return cpufreq_register_notifier(&info->freq_transition,
792 CPUFREQ_TRANSITION_NOTIFIER);
793}
794
795static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
796{
797 cpufreq_unregister_notifier(&info->freq_transition,
798 CPUFREQ_TRANSITION_NOTIFIER);
799}
800
801#else
802static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
803{
804 return 0;
805}
806
807static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
808{
809}
810#endif
811
812
761static char driver_name[] = "s3c2410fb"; 813static char driver_name[] = "s3c2410fb";
762 814
763static int __init s3c24xxfb_probe(struct platform_device *pdev, 815static int __init s3c24xxfb_probe(struct platform_device *pdev,
@@ -875,6 +927,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
875 927
876 msleep(1); 928 msleep(1);
877 929
930 info->clk_rate = clk_get_rate(info->clk);
931
878 /* find maximum required memory size for display */ 932 /* find maximum required memory size for display */
879 for (i = 0; i < mach_info->num_displays; i++) { 933 for (i = 0; i < mach_info->num_displays; i++) {
880 unsigned long smem_len = mach_info->displays[i].xres; 934 unsigned long smem_len = mach_info->displays[i].xres;
@@ -904,11 +958,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
904 958
905 s3c2410fb_check_var(&fbinfo->var, fbinfo); 959 s3c2410fb_check_var(&fbinfo->var, fbinfo);
906 960
961 ret = s3c2410fb_cpufreq_register(info);
962 if (ret < 0) {
963 dev_err(&pdev->dev, "Failed to register cpufreq\n");
964 goto free_video_memory;
965 }
966
907 ret = register_framebuffer(fbinfo); 967 ret = register_framebuffer(fbinfo);
908 if (ret < 0) { 968 if (ret < 0) {
909 printk(KERN_ERR "Failed to register framebuffer device: %d\n", 969 printk(KERN_ERR "Failed to register framebuffer device: %d\n",
910 ret); 970 ret);
911 goto free_video_memory; 971 goto free_cpufreq;
912 } 972 }
913 973
914 /* create device files */ 974 /* create device files */
@@ -922,6 +982,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
922 982
923 return 0; 983 return 0;
924 984
985 free_cpufreq:
986 s3c2410fb_cpufreq_deregister(info);
925free_video_memory: 987free_video_memory:
926 s3c2410fb_unmap_video_memory(fbinfo); 988 s3c2410fb_unmap_video_memory(fbinfo);
927release_clock: 989release_clock:
@@ -961,6 +1023,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
961 int irq; 1023 int irq;
962 1024
963 unregister_framebuffer(fbinfo); 1025 unregister_framebuffer(fbinfo);
1026 s3c2410fb_cpufreq_deregister(info);
964 1027
965 s3c2410fb_lcd_enable(info, 0); 1028 s3c2410fb_lcd_enable(info, 0);
966 msleep(1); 1029 msleep(1);
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index 9a6ba3e9d1b8..47a17bd23011 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -29,8 +29,13 @@ struct s3c2410fb_info {
29 enum s3c_drv_type drv_type; 29 enum s3c_drv_type drv_type;
30 struct s3c2410fb_hw regs; 30 struct s3c2410fb_hw regs;
31 31
32 unsigned long clk_rate;
32 unsigned int palette_ready; 33 unsigned int palette_ready;
33 34
35#ifdef CONFIG_CPU_FREQ
36 struct notifier_block freq_transition;
37#endif
38
34 /* keep these registers in case we need to re-write palette */ 39 /* keep these registers in case we need to re-write palette */
35 u32 palette_buffer[256]; 40 u32 palette_buffer[256];
36 u32 pseudo_pal[16]; 41 u32 pseudo_pal[16];
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 7e17ee95a97a..7072d19080d5 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -5928,7 +5928,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
5928 if(pci_enable_device(pdev)) { 5928 if(pci_enable_device(pdev)) {
5929 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge); 5929 if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
5930 pci_set_drvdata(pdev, NULL); 5930 pci_set_drvdata(pdev, NULL);
5931 kfree(sis_fb_info); 5931 framebuffer_release(sis_fb_info);
5932 return -EIO; 5932 return -EIO;
5933 } 5933 }
5934 } 5934 }
@@ -6134,7 +6134,7 @@ error_3: vfree(ivideo->bios_abase);
6134 pci_set_drvdata(pdev, NULL); 6134 pci_set_drvdata(pdev, NULL);
6135 if(!ivideo->sisvga_enabled) 6135 if(!ivideo->sisvga_enabled)
6136 pci_disable_device(pdev); 6136 pci_disable_device(pdev);
6137 kfree(sis_fb_info); 6137 framebuffer_release(sis_fb_info);
6138 return ret; 6138 return ret;
6139 } 6139 }
6140 6140
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index eabaad765aeb..eec9dcb7f599 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -1380,7 +1380,7 @@ stifb_cleanup(void)
1380 if (info->screen_base) 1380 if (info->screen_base)
1381 iounmap(info->screen_base); 1381 iounmap(info->screen_base);
1382 fb_dealloc_cmap(&info->cmap); 1382 fb_dealloc_cmap(&info->cmap);
1383 kfree(info); 1383 framebuffer_release(info);
1384 } 1384 }
1385 sti->info = NULL; 1385 sti->info = NULL;
1386 } 1386 }
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 643afbfe8277..45b883598bf0 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -116,17 +116,16 @@ struct tcx_par {
116 u32 flags; 116 u32 flags;
117#define TCX_FLAG_BLANKED 0x00000001 117#define TCX_FLAG_BLANKED 0x00000001
118 118
119 unsigned long physbase;
120 unsigned long which_io; 119 unsigned long which_io;
121 unsigned long fbsize;
122 120
123 struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; 121 struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES];
124 int lowdepth; 122 int lowdepth;
125}; 123};
126 124
127/* Reset control plane so that WID is 8-bit plane. */ 125/* Reset control plane so that WID is 8-bit plane. */
128static void __tcx_set_control_plane(struct tcx_par *par) 126static void __tcx_set_control_plane(struct fb_info *info)
129{ 127{
128 struct tcx_par *par = info->par;
130 u32 __iomem *p, *pend; 129 u32 __iomem *p, *pend;
131 130
132 if (par->lowdepth) 131 if (par->lowdepth)
@@ -135,7 +134,7 @@ static void __tcx_set_control_plane(struct tcx_par *par)
135 p = par->cplane; 134 p = par->cplane;
136 if (p == NULL) 135 if (p == NULL)
137 return; 136 return;
138 for (pend = p + par->fbsize; p < pend; p++) { 137 for (pend = p + info->fix.smem_len; p < pend; p++) {
139 u32 tmp = sbus_readl(p); 138 u32 tmp = sbus_readl(p);
140 139
141 tmp &= 0xffffff; 140 tmp &= 0xffffff;
@@ -149,7 +148,7 @@ static void tcx_reset(struct fb_info *info)
149 unsigned long flags; 148 unsigned long flags;
150 149
151 spin_lock_irqsave(&par->lock, flags); 150 spin_lock_irqsave(&par->lock, flags);
152 __tcx_set_control_plane(par); 151 __tcx_set_control_plane(info);
153 spin_unlock_irqrestore(&par->lock, flags); 152 spin_unlock_irqrestore(&par->lock, flags);
154} 153}
155 154
@@ -304,7 +303,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
304 struct tcx_par *par = (struct tcx_par *)info->par; 303 struct tcx_par *par = (struct tcx_par *)info->par;
305 304
306 return sbusfb_mmap_helper(par->mmap_map, 305 return sbusfb_mmap_helper(par->mmap_map,
307 par->physbase, par->fbsize, 306 info->fix.smem_start, info->fix.smem_len,
308 par->which_io, vma); 307 par->which_io, vma);
309} 308}
310 309
@@ -316,7 +315,7 @@ static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
316 return sbusfb_ioctl_helper(cmd, arg, info, 315 return sbusfb_ioctl_helper(cmd, arg, info,
317 FBTYPE_TCXCOLOR, 316 FBTYPE_TCXCOLOR,
318 (par->lowdepth ? 8 : 24), 317 (par->lowdepth ? 8 : 24),
319 par->fbsize); 318 info->fix.smem_len);
320} 319}
321 320
322/* 321/*
@@ -358,10 +357,10 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
358 par->bt, sizeof(struct bt_regs)); 357 par->bt, sizeof(struct bt_regs));
359 if (par->cplane) 358 if (par->cplane)
360 of_iounmap(&op->resource[4], 359 of_iounmap(&op->resource[4],
361 par->cplane, par->fbsize * sizeof(u32)); 360 par->cplane, info->fix.smem_len * sizeof(u32));
362 if (info->screen_base) 361 if (info->screen_base)
363 of_iounmap(&op->resource[0], 362 of_iounmap(&op->resource[0],
364 info->screen_base, par->fbsize); 363 info->screen_base, info->fix.smem_len);
365} 364}
366 365
367static int __devinit tcx_probe(struct of_device *op, 366static int __devinit tcx_probe(struct of_device *op,
@@ -391,7 +390,7 @@ static int __devinit tcx_probe(struct of_device *op,
391 390
392 linebytes = of_getintprop_default(dp, "linebytes", 391 linebytes = of_getintprop_default(dp, "linebytes",
393 info->var.xres); 392 info->var.xres);
394 par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); 393 info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
395 394
396 par->tec = of_ioremap(&op->resource[7], 0, 395 par->tec = of_ioremap(&op->resource[7], 0,
397 sizeof(struct tcx_tec), "tcx tec"); 396 sizeof(struct tcx_tec), "tcx tec");
@@ -400,7 +399,7 @@ static int __devinit tcx_probe(struct of_device *op,
400 par->bt = of_ioremap(&op->resource[8], 0, 399 par->bt = of_ioremap(&op->resource[8], 0,
401 sizeof(struct bt_regs), "tcx dac"); 400 sizeof(struct bt_regs), "tcx dac");
402 info->screen_base = of_ioremap(&op->resource[0], 0, 401 info->screen_base = of_ioremap(&op->resource[0], 0,
403 par->fbsize, "tcx ram"); 402 info->fix.smem_len, "tcx ram");
404 if (!par->tec || !par->thc || 403 if (!par->tec || !par->thc ||
405 !par->bt || !info->screen_base) 404 !par->bt || !info->screen_base)
406 goto out_unmap_regs; 405 goto out_unmap_regs;
@@ -408,7 +407,7 @@ static int __devinit tcx_probe(struct of_device *op,
408 memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map)); 407 memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map));
409 if (!par->lowdepth) { 408 if (!par->lowdepth) {
410 par->cplane = of_ioremap(&op->resource[4], 0, 409 par->cplane = of_ioremap(&op->resource[4], 0,
411 par->fbsize * sizeof(u32), 410 info->fix.smem_len * sizeof(u32),
412 "tcx cplane"); 411 "tcx cplane");
413 if (!par->cplane) 412 if (!par->cplane)
414 goto out_unmap_regs; 413 goto out_unmap_regs;
@@ -419,7 +418,7 @@ static int __devinit tcx_probe(struct of_device *op,
419 par->mmap_map[6].size = SBUS_MMAP_EMPTY; 418 par->mmap_map[6].size = SBUS_MMAP_EMPTY;
420 } 419 }
421 420
422 par->physbase = op->resource[0].start; 421 info->fix.smem_start = op->resource[0].start;
423 par->which_io = op->resource[0].flags & IORESOURCE_BITS; 422 par->which_io = op->resource[0].flags & IORESOURCE_BITS;
424 423
425 for (i = 0; i < TCX_MMAP_ENTRIES; i++) { 424 for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
@@ -473,7 +472,7 @@ static int __devinit tcx_probe(struct of_device *op,
473 printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n", 472 printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n",
474 dp->full_name, 473 dp->full_name,
475 par->which_io, 474 par->which_io,
476 par->physbase, 475 info->fix.smem_start,
477 par->lowdepth ? "8-bit only" : "24-bit depth"); 476 par->lowdepth ? "8-bit only" : "24-bit depth");
478 477
479 return 0; 478 return 0;
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index d6856f43d241..bd37ee1f6a25 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -174,8 +174,17 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
174 return err; 174 return err;
175} 175}
176 176
177static void vesafb_destroy(struct fb_info *info)
178{
179 if (info->screen_base)
180 iounmap(info->screen_base);
181 release_mem_region(info->aperture_base, info->aperture_size);
182 framebuffer_release(info);
183}
184
177static struct fb_ops vesafb_ops = { 185static struct fb_ops vesafb_ops = {
178 .owner = THIS_MODULE, 186 .owner = THIS_MODULE,
187 .fb_destroy = vesafb_destroy,
179 .fb_setcolreg = vesafb_setcolreg, 188 .fb_setcolreg = vesafb_setcolreg,
180 .fb_pan_display = vesafb_pan_display, 189 .fb_pan_display = vesafb_pan_display,
181 .fb_fillrect = cfb_fillrect, 190 .fb_fillrect = cfb_fillrect,
@@ -286,6 +295,10 @@ static int __init vesafb_probe(struct platform_device *dev)
286 info->pseudo_palette = info->par; 295 info->pseudo_palette = info->par;
287 info->par = NULL; 296 info->par = NULL;
288 297
298 /* set vesafb aperture size for generic probing */
299 info->aperture_base = screen_info.lfb_base;
300 info->aperture_size = size_total;
301
289 info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len); 302 info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
290 if (!info->screen_base) { 303 if (!info->screen_base) {
291 printk(KERN_ERR 304 printk(KERN_ERR
@@ -437,7 +450,7 @@ static int __init vesafb_probe(struct platform_device *dev)
437 info->fbops = &vesafb_ops; 450 info->fbops = &vesafb_ops;
438 info->var = vesafb_defined; 451 info->var = vesafb_defined;
439 info->fix = vesafb_fix; 452 info->fix = vesafb_fix;
440 info->flags = FBINFO_FLAG_DEFAULT | 453 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
441 (ypan ? FBINFO_HWACCEL_YPAN : 0); 454 (ypan ? FBINFO_HWACCEL_YPAN : 0);
442 455
443 if (!ypan) 456 if (!ypan)
diff --git a/drivers/vlynq/Kconfig b/drivers/vlynq/Kconfig
new file mode 100644
index 000000000000..f6542211db48
--- /dev/null
+++ b/drivers/vlynq/Kconfig
@@ -0,0 +1,20 @@
1menu "TI VLYNQ"
2
3config VLYNQ
4 bool "TI VLYNQ bus support"
5 depends on AR7 && EXPERIMENTAL
6 help
7 Support for Texas Instruments(R) VLYNQ bus.
8 The VLYNQ bus is a high-speed, serial and packetized
9 data bus which allows external peripherals of a SoC
10 to appear into the system's main memory.
11
12 If unsure, say N
13
14config VLYNQ_DEBUG
15 bool "VLYNQ bus debug"
16 depends on VLYNQ && KERNEL_DEBUG
17 help
18 Turn on VLYNQ bus debugging.
19
20endmenu
diff --git a/drivers/vlynq/Makefile b/drivers/vlynq/Makefile
new file mode 100644
index 000000000000..b3f61149b599
--- /dev/null
+++ b/drivers/vlynq/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for kernel vlynq drivers
3#
4
5obj-$(CONFIG_VLYNQ) += vlynq.o
diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c
new file mode 100644
index 000000000000..7335433b067b
--- /dev/null
+++ b/drivers/vlynq/vlynq.c
@@ -0,0 +1,814 @@
1/*
2 * Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Parts of the VLYNQ specification can be found here:
19 * http://www.ti.com/litv/pdf/sprue36a
20 */
21
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/string.h>
26#include <linux/device.h>
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/platform_device.h>
30#include <linux/interrupt.h>
31#include <linux/device.h>
32#include <linux/delay.h>
33#include <linux/io.h>
34
35#include <linux/vlynq.h>
36
37#define VLYNQ_CTRL_PM_ENABLE 0x80000000
38#define VLYNQ_CTRL_CLOCK_INT 0x00008000
39#define VLYNQ_CTRL_CLOCK_DIV(x) (((x) & 7) << 16)
40#define VLYNQ_CTRL_INT_LOCAL 0x00004000
41#define VLYNQ_CTRL_INT_ENABLE 0x00002000
42#define VLYNQ_CTRL_INT_VECTOR(x) (((x) & 0x1f) << 8)
43#define VLYNQ_CTRL_INT2CFG 0x00000080
44#define VLYNQ_CTRL_RESET 0x00000001
45
46#define VLYNQ_CTRL_CLOCK_MASK (0x7 << 16)
47
48#define VLYNQ_INT_OFFSET 0x00000014
49#define VLYNQ_REMOTE_OFFSET 0x00000080
50
51#define VLYNQ_STATUS_LINK 0x00000001
52#define VLYNQ_STATUS_LERROR 0x00000080
53#define VLYNQ_STATUS_RERROR 0x00000100
54
55#define VINT_ENABLE 0x00000100
56#define VINT_TYPE_EDGE 0x00000080
57#define VINT_LEVEL_LOW 0x00000040
58#define VINT_VECTOR(x) ((x) & 0x1f)
59#define VINT_OFFSET(irq) (8 * ((irq) % 4))
60
61#define VLYNQ_AUTONEGO_V2 0x00010000
62
63struct vlynq_regs {
64 u32 revision;
65 u32 control;
66 u32 status;
67 u32 int_prio;
68 u32 int_status;
69 u32 int_pending;
70 u32 int_ptr;
71 u32 tx_offset;
72 struct vlynq_mapping rx_mapping[4];
73 u32 chip;
74 u32 autonego;
75 u32 unused[6];
76 u32 int_device[8];
77};
78
79#ifdef VLYNQ_DEBUG
80static void vlynq_dump_regs(struct vlynq_device *dev)
81{
82 int i;
83
84 printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n",
85 dev->local, dev->remote);
86 for (i = 0; i < 32; i++) {
87 printk(KERN_DEBUG "VLYNQ: local %d: %08x\n",
88 i + 1, ((u32 *)dev->local)[i]);
89 printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n",
90 i + 1, ((u32 *)dev->remote)[i]);
91 }
92}
93
94static void vlynq_dump_mem(u32 *base, int count)
95{
96 int i;
97
98 for (i = 0; i < (count + 3) / 4; i++) {
99 if (i % 4 == 0)
100 printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4);
101 printk(KERN_DEBUG " 0x%08x", *(base + i));
102 }
103 printk(KERN_DEBUG "\n");
104}
105#endif
106
107/* Check the VLYNQ link status with a given device */
108static int vlynq_linked(struct vlynq_device *dev)
109{
110 int i;
111
112 for (i = 0; i < 100; i++)
113 if (readl(&dev->local->status) & VLYNQ_STATUS_LINK)
114 return 1;
115 else
116 cpu_relax();
117
118 return 0;
119}
120
121static void vlynq_reset(struct vlynq_device *dev)
122{
123 writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
124 &dev->local->control);
125
126 /* Wait for the devices to finish resetting */
127 msleep(5);
128
129 /* Remove reset bit */
130 writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
131 &dev->local->control);
132
133 /* Give some time for the devices to settle */
134 msleep(5);
135}
136
137static void vlynq_irq_unmask(unsigned int irq)
138{
139 u32 val;
140 struct vlynq_device *dev = get_irq_chip_data(irq);
141 int virq;
142
143 BUG_ON(!dev);
144 virq = irq - dev->irq_start;
145 val = readl(&dev->remote->int_device[virq >> 2]);
146 val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq);
147 writel(val, &dev->remote->int_device[virq >> 2]);
148}
149
150static void vlynq_irq_mask(unsigned int irq)
151{
152 u32 val;
153 struct vlynq_device *dev = get_irq_chip_data(irq);
154 int virq;
155
156 BUG_ON(!dev);
157 virq = irq - dev->irq_start;
158 val = readl(&dev->remote->int_device[virq >> 2]);
159 val &= ~(VINT_ENABLE << VINT_OFFSET(virq));
160 writel(val, &dev->remote->int_device[virq >> 2]);
161}
162
163static int vlynq_irq_type(unsigned int irq, unsigned int flow_type)
164{
165 u32 val;
166 struct vlynq_device *dev = get_irq_chip_data(irq);
167 int virq;
168
169 BUG_ON(!dev);
170 virq = irq - dev->irq_start;
171 val = readl(&dev->remote->int_device[virq >> 2]);
172 switch (flow_type & IRQ_TYPE_SENSE_MASK) {
173 case IRQ_TYPE_EDGE_RISING:
174 case IRQ_TYPE_EDGE_FALLING:
175 case IRQ_TYPE_EDGE_BOTH:
176 val |= VINT_TYPE_EDGE << VINT_OFFSET(virq);
177 val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
178 break;
179 case IRQ_TYPE_LEVEL_HIGH:
180 val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
181 val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
182 break;
183 case IRQ_TYPE_LEVEL_LOW:
184 val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
185 val |= VINT_LEVEL_LOW << VINT_OFFSET(virq);
186 break;
187 default:
188 return -EINVAL;
189 }
190 writel(val, &dev->remote->int_device[virq >> 2]);
191 return 0;
192}
193
194static void vlynq_local_ack(unsigned int irq)
195{
196 struct vlynq_device *dev = get_irq_chip_data(irq);
197
198 u32 status = readl(&dev->local->status);
199
200 pr_debug("%s: local status: 0x%08x\n",
201 dev_name(&dev->dev), status);
202 writel(status, &dev->local->status);
203}
204
205static void vlynq_remote_ack(unsigned int irq)
206{
207 struct vlynq_device *dev = get_irq_chip_data(irq);
208
209 u32 status = readl(&dev->remote->status);
210
211 pr_debug("%s: remote status: 0x%08x\n",
212 dev_name(&dev->dev), status);
213 writel(status, &dev->remote->status);
214}
215
216static irqreturn_t vlynq_irq(int irq, void *dev_id)
217{
218 struct vlynq_device *dev = dev_id;
219 u32 status;
220 int virq = 0;
221
222 status = readl(&dev->local->int_status);
223 writel(status, &dev->local->int_status);
224
225 if (unlikely(!status))
226 spurious_interrupt();
227
228 while (status) {
229 if (status & 1)
230 do_IRQ(dev->irq_start + virq);
231 status >>= 1;
232 virq++;
233 }
234
235 return IRQ_HANDLED;
236}
237
238static struct irq_chip vlynq_irq_chip = {
239 .name = "vlynq",
240 .unmask = vlynq_irq_unmask,
241 .mask = vlynq_irq_mask,
242 .set_type = vlynq_irq_type,
243};
244
245static struct irq_chip vlynq_local_chip = {
246 .name = "vlynq local error",
247 .unmask = vlynq_irq_unmask,
248 .mask = vlynq_irq_mask,
249 .ack = vlynq_local_ack,
250};
251
252static struct irq_chip vlynq_remote_chip = {
253 .name = "vlynq local error",
254 .unmask = vlynq_irq_unmask,
255 .mask = vlynq_irq_mask,
256 .ack = vlynq_remote_ack,
257};
258
259static int vlynq_setup_irq(struct vlynq_device *dev)
260{
261 u32 val;
262 int i, virq;
263
264 if (dev->local_irq == dev->remote_irq) {
265 printk(KERN_ERR
266 "%s: local vlynq irq should be different from remote\n",
267 dev_name(&dev->dev));
268 return -EINVAL;
269 }
270
271 /* Clear local and remote error bits */
272 writel(readl(&dev->local->status), &dev->local->status);
273 writel(readl(&dev->remote->status), &dev->remote->status);
274
275 /* Now setup interrupts */
276 val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq);
277 val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL |
278 VLYNQ_CTRL_INT2CFG;
279 val |= readl(&dev->local->control);
280 writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr);
281 writel(val, &dev->local->control);
282
283 val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq);
284 val |= VLYNQ_CTRL_INT_ENABLE;
285 val |= readl(&dev->remote->control);
286 writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr);
287 writel(val, &dev->remote->int_ptr);
288 writel(val, &dev->remote->control);
289
290 for (i = dev->irq_start; i <= dev->irq_end; i++) {
291 virq = i - dev->irq_start;
292 if (virq == dev->local_irq) {
293 set_irq_chip_and_handler(i, &vlynq_local_chip,
294 handle_level_irq);
295 set_irq_chip_data(i, dev);
296 } else if (virq == dev->remote_irq) {
297 set_irq_chip_and_handler(i, &vlynq_remote_chip,
298 handle_level_irq);
299 set_irq_chip_data(i, dev);
300 } else {
301 set_irq_chip_and_handler(i, &vlynq_irq_chip,
302 handle_simple_irq);
303 set_irq_chip_data(i, dev);
304 writel(0, &dev->remote->int_device[virq >> 2]);
305 }
306 }
307
308 if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) {
309 printk(KERN_ERR "%s: request_irq failed\n",
310 dev_name(&dev->dev));
311 return -EAGAIN;
312 }
313
314 return 0;
315}
316
317static void vlynq_device_release(struct device *dev)
318{
319 struct vlynq_device *vdev = to_vlynq_device(dev);
320 kfree(vdev);
321}
322
323static int vlynq_device_match(struct device *dev,
324 struct device_driver *drv)
325{
326 struct vlynq_device *vdev = to_vlynq_device(dev);
327 struct vlynq_driver *vdrv = to_vlynq_driver(drv);
328 struct vlynq_device_id *ids = vdrv->id_table;
329
330 while (ids->id) {
331 if (ids->id == vdev->dev_id) {
332 vdev->divisor = ids->divisor;
333 vlynq_set_drvdata(vdev, ids);
334 printk(KERN_INFO "Driver found for VLYNQ "
335 "device: %08x\n", vdev->dev_id);
336 return 1;
337 }
338 printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver"
339 " for VLYNQ device: %08x\n", ids->id, vdev->dev_id);
340 ids++;
341 }
342 return 0;
343}
344
345static int vlynq_device_probe(struct device *dev)
346{
347 struct vlynq_device *vdev = to_vlynq_device(dev);
348 struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
349 struct vlynq_device_id *id = vlynq_get_drvdata(vdev);
350 int result = -ENODEV;
351
352 if (drv->probe)
353 result = drv->probe(vdev, id);
354 if (result)
355 put_device(dev);
356 return result;
357}
358
359static int vlynq_device_remove(struct device *dev)
360{
361 struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
362
363 if (drv->remove)
364 drv->remove(to_vlynq_device(dev));
365
366 return 0;
367}
368
369int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner)
370{
371 driver->driver.name = driver->name;
372 driver->driver.bus = &vlynq_bus_type;
373 return driver_register(&driver->driver);
374}
375EXPORT_SYMBOL(__vlynq_register_driver);
376
377void vlynq_unregister_driver(struct vlynq_driver *driver)
378{
379 driver_unregister(&driver->driver);
380}
381EXPORT_SYMBOL(vlynq_unregister_driver);
382
383/*
384 * A VLYNQ remote device can clock the VLYNQ bus master
385 * using a dedicated clock line. In that case, both the
386 * remove device and the bus master should have the same
387 * serial clock dividers configured. Iterate through the
388 * 8 possible dividers until we actually link with the
389 * device.
390 */
391static int __vlynq_try_remote(struct vlynq_device *dev)
392{
393 int i;
394
395 vlynq_reset(dev);
396 for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
397 i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
398 dev->dev_id ? i++ : i--) {
399
400 if (!vlynq_linked(dev))
401 break;
402
403 writel((readl(&dev->remote->control) &
404 ~VLYNQ_CTRL_CLOCK_MASK) |
405 VLYNQ_CTRL_CLOCK_INT |
406 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
407 &dev->remote->control);
408 writel((readl(&dev->local->control)
409 & ~(VLYNQ_CTRL_CLOCK_INT |
410 VLYNQ_CTRL_CLOCK_MASK)) |
411 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
412 &dev->local->control);
413
414 if (vlynq_linked(dev)) {
415 printk(KERN_DEBUG
416 "%s: using remote clock divisor %d\n",
417 dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
418 dev->divisor = i;
419 return 0;
420 } else {
421 vlynq_reset(dev);
422 }
423 }
424
425 return -ENODEV;
426}
427
428/*
429 * A VLYNQ remote device can be clocked by the VLYNQ bus
430 * master using a dedicated clock line. In that case, only
431 * the bus master configures the serial clock divider.
432 * Iterate through the 8 possible dividers until we
433 * actually get a link with the device.
434 */
435static int __vlynq_try_local(struct vlynq_device *dev)
436{
437 int i;
438
439 vlynq_reset(dev);
440
441 for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
442 i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
443 dev->dev_id ? i++ : i--) {
444
445 writel((readl(&dev->local->control) &
446 ~VLYNQ_CTRL_CLOCK_MASK) |
447 VLYNQ_CTRL_CLOCK_INT |
448 VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
449 &dev->local->control);
450
451 if (vlynq_linked(dev)) {
452 printk(KERN_DEBUG
453 "%s: using local clock divisor %d\n",
454 dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
455 dev->divisor = i;
456 return 0;
457 } else {
458 vlynq_reset(dev);
459 }
460 }
461
462 return -ENODEV;
463}
464
465/*
466 * When using external clocking method, serial clock
467 * is supplied by an external oscillator, therefore we
468 * should mask the local clock bit in the clock control
469 * register for both the bus master and the remote device.
470 */
471static int __vlynq_try_external(struct vlynq_device *dev)
472{
473 vlynq_reset(dev);
474 if (!vlynq_linked(dev))
475 return -ENODEV;
476
477 writel((readl(&dev->remote->control) &
478 ~VLYNQ_CTRL_CLOCK_INT),
479 &dev->remote->control);
480
481 writel((readl(&dev->local->control) &
482 ~VLYNQ_CTRL_CLOCK_INT),
483 &dev->local->control);
484
485 if (vlynq_linked(dev)) {
486 printk(KERN_DEBUG "%s: using external clock\n",
487 dev_name(&dev->dev));
488 dev->divisor = vlynq_div_external;
489 return 0;
490 }
491
492 return -ENODEV;
493}
494
495static int __vlynq_enable_device(struct vlynq_device *dev)
496{
497 int result;
498 struct plat_vlynq_ops *ops = dev->dev.platform_data;
499
500 result = ops->on(dev);
501 if (result)
502 return result;
503
504 switch (dev->divisor) {
505 case vlynq_div_external:
506 case vlynq_div_auto:
507 /* When the device is brought from reset it should have clock
508 * generation negotiated by hardware.
509 * Check which device is generating clocks and perform setup
510 * accordingly */
511 if (vlynq_linked(dev) && readl(&dev->remote->control) &
512 VLYNQ_CTRL_CLOCK_INT) {
513 if (!__vlynq_try_remote(dev) ||
514 !__vlynq_try_local(dev) ||
515 !__vlynq_try_external(dev))
516 return 0;
517 } else {
518 if (!__vlynq_try_external(dev) ||
519 !__vlynq_try_local(dev) ||
520 !__vlynq_try_remote(dev))
521 return 0;
522 }
523 break;
524 case vlynq_ldiv1:
525 case vlynq_ldiv2:
526 case vlynq_ldiv3:
527 case vlynq_ldiv4:
528 case vlynq_ldiv5:
529 case vlynq_ldiv6:
530 case vlynq_ldiv7:
531 case vlynq_ldiv8:
532 writel(VLYNQ_CTRL_CLOCK_INT |
533 VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
534 vlynq_ldiv1), &dev->local->control);
535 writel(0, &dev->remote->control);
536 if (vlynq_linked(dev)) {
537 printk(KERN_DEBUG
538 "%s: using local clock divisor %d\n",
539 dev_name(&dev->dev),
540 dev->divisor - vlynq_ldiv1 + 1);
541 return 0;
542 }
543 break;
544 case vlynq_rdiv1:
545 case vlynq_rdiv2:
546 case vlynq_rdiv3:
547 case vlynq_rdiv4:
548 case vlynq_rdiv5:
549 case vlynq_rdiv6:
550 case vlynq_rdiv7:
551 case vlynq_rdiv8:
552 writel(0, &dev->local->control);
553 writel(VLYNQ_CTRL_CLOCK_INT |
554 VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
555 vlynq_rdiv1), &dev->remote->control);
556 if (vlynq_linked(dev)) {
557 printk(KERN_DEBUG
558 "%s: using remote clock divisor %d\n",
559 dev_name(&dev->dev),
560 dev->divisor - vlynq_rdiv1 + 1);
561 return 0;
562 }
563 break;
564 }
565
566 ops->off(dev);
567 return -ENODEV;
568}
569
570int vlynq_enable_device(struct vlynq_device *dev)
571{
572 struct plat_vlynq_ops *ops = dev->dev.platform_data;
573 int result = -ENODEV;
574
575 result = __vlynq_enable_device(dev);
576 if (result)
577 return result;
578
579 result = vlynq_setup_irq(dev);
580 if (result)
581 ops->off(dev);
582
583 dev->enabled = !result;
584 return result;
585}
586EXPORT_SYMBOL(vlynq_enable_device);
587
588
589void vlynq_disable_device(struct vlynq_device *dev)
590{
591 struct plat_vlynq_ops *ops = dev->dev.platform_data;
592
593 dev->enabled = 0;
594 free_irq(dev->irq, dev);
595 ops->off(dev);
596}
597EXPORT_SYMBOL(vlynq_disable_device);
598
599int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
600 struct vlynq_mapping *mapping)
601{
602 int i;
603
604 if (!dev->enabled)
605 return -ENXIO;
606
607 writel(tx_offset, &dev->local->tx_offset);
608 for (i = 0; i < 4; i++) {
609 writel(mapping[i].offset, &dev->local->rx_mapping[i].offset);
610 writel(mapping[i].size, &dev->local->rx_mapping[i].size);
611 }
612 return 0;
613}
614EXPORT_SYMBOL(vlynq_set_local_mapping);
615
616int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
617 struct vlynq_mapping *mapping)
618{
619 int i;
620
621 if (!dev->enabled)
622 return -ENXIO;
623
624 writel(tx_offset, &dev->remote->tx_offset);
625 for (i = 0; i < 4; i++) {
626 writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset);
627 writel(mapping[i].size, &dev->remote->rx_mapping[i].size);
628 }
629 return 0;
630}
631EXPORT_SYMBOL(vlynq_set_remote_mapping);
632
633int vlynq_set_local_irq(struct vlynq_device *dev, int virq)
634{
635 int irq = dev->irq_start + virq;
636 if (dev->enabled)
637 return -EBUSY;
638
639 if ((irq < dev->irq_start) || (irq > dev->irq_end))
640 return -EINVAL;
641
642 if (virq == dev->remote_irq)
643 return -EINVAL;
644
645 dev->local_irq = virq;
646
647 return 0;
648}
649EXPORT_SYMBOL(vlynq_set_local_irq);
650
651int vlynq_set_remote_irq(struct vlynq_device *dev, int virq)
652{
653 int irq = dev->irq_start + virq;
654 if (dev->enabled)
655 return -EBUSY;
656
657 if ((irq < dev->irq_start) || (irq > dev->irq_end))
658 return -EINVAL;
659
660 if (virq == dev->local_irq)
661 return -EINVAL;
662
663 dev->remote_irq = virq;
664
665 return 0;
666}
667EXPORT_SYMBOL(vlynq_set_remote_irq);
668
669static int vlynq_probe(struct platform_device *pdev)
670{
671 struct vlynq_device *dev;
672 struct resource *regs_res, *mem_res, *irq_res;
673 int len, result;
674
675 regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
676 if (!regs_res)
677 return -ENODEV;
678
679 mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
680 if (!mem_res)
681 return -ENODEV;
682
683 irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq");
684 if (!irq_res)
685 return -ENODEV;
686
687 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
688 if (!dev) {
689 printk(KERN_ERR
690 "vlynq: failed to allocate device structure\n");
691 return -ENOMEM;
692 }
693
694 dev->id = pdev->id;
695 dev->dev.bus = &vlynq_bus_type;
696 dev->dev.parent = &pdev->dev;
697 dev_set_name(&dev->dev, "vlynq%d", dev->id);
698 dev->dev.platform_data = pdev->dev.platform_data;
699 dev->dev.release = vlynq_device_release;
700
701 dev->regs_start = regs_res->start;
702 dev->regs_end = regs_res->end;
703 dev->mem_start = mem_res->start;
704 dev->mem_end = mem_res->end;
705
706 len = regs_res->end - regs_res->start;
707 if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) {
708 printk(KERN_ERR "%s: Can't request vlynq registers\n",
709 dev_name(&dev->dev));
710 result = -ENXIO;
711 goto fail_request;
712 }
713
714 dev->local = ioremap(regs_res->start, len);
715 if (!dev->local) {
716 printk(KERN_ERR "%s: Can't remap vlynq registers\n",
717 dev_name(&dev->dev));
718 result = -ENXIO;
719 goto fail_remap;
720 }
721
722 dev->remote = (struct vlynq_regs *)((void *)dev->local +
723 VLYNQ_REMOTE_OFFSET);
724
725 dev->irq = platform_get_irq_byname(pdev, "irq");
726 dev->irq_start = irq_res->start;
727 dev->irq_end = irq_res->end;
728 dev->local_irq = dev->irq_end - dev->irq_start;
729 dev->remote_irq = dev->local_irq - 1;
730
731 if (device_register(&dev->dev))
732 goto fail_register;
733 platform_set_drvdata(pdev, dev);
734
735 printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
736 dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
737 (void *)dev->mem_start);
738
739 dev->dev_id = 0;
740 dev->divisor = vlynq_div_auto;
741 result = __vlynq_enable_device(dev);
742 if (result == 0) {
743 dev->dev_id = readl(&dev->remote->chip);
744 ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
745 }
746 if (dev->dev_id)
747 printk(KERN_INFO "Found a VLYNQ device: %08x\n", dev->dev_id);
748
749 return 0;
750
751fail_register:
752 iounmap(dev->local);
753fail_remap:
754fail_request:
755 release_mem_region(regs_res->start, len);
756 kfree(dev);
757 return result;
758}
759
760static int vlynq_remove(struct platform_device *pdev)
761{
762 struct vlynq_device *dev = platform_get_drvdata(pdev);
763
764 device_unregister(&dev->dev);
765 iounmap(dev->local);
766 release_mem_region(dev->regs_start, dev->regs_end - dev->regs_start);
767
768 kfree(dev);
769
770 return 0;
771}
772
773static struct platform_driver vlynq_platform_driver = {
774 .driver.name = "vlynq",
775 .probe = vlynq_probe,
776 .remove = __devexit_p(vlynq_remove),
777};
778
779struct bus_type vlynq_bus_type = {
780 .name = "vlynq",
781 .match = vlynq_device_match,
782 .probe = vlynq_device_probe,
783 .remove = vlynq_device_remove,
784};
785EXPORT_SYMBOL(vlynq_bus_type);
786
787static int __devinit vlynq_init(void)
788{
789 int res = 0;
790
791 res = bus_register(&vlynq_bus_type);
792 if (res)
793 goto fail_bus;
794
795 res = platform_driver_register(&vlynq_platform_driver);
796 if (res)
797 goto fail_platform;
798
799 return 0;
800
801fail_platform:
802 bus_unregister(&vlynq_bus_type);
803fail_bus:
804 return res;
805}
806
807static void __devexit vlynq_exit(void)
808{
809 platform_driver_unregister(&vlynq_platform_driver);
810 bus_unregister(&vlynq_bus_type);
811}
812
813module_init(vlynq_init);
814module_exit(vlynq_exit);