mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
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
This commit is contained in:
commit
517d08699b
247 changed files with 5666 additions and 2683 deletions
|
|
@ -104,6 +104,8 @@ source "drivers/auxdisplay/Kconfig"
|
|||
|
||||
source "drivers/uio/Kconfig"
|
||||
|
||||
source "drivers/vlynq/Kconfig"
|
||||
|
||||
source "drivers/xen/Kconfig"
|
||||
|
||||
source "drivers/staging/Kconfig"
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ obj-$(CONFIG_PPC_PS3) += ps3/
|
|||
obj-$(CONFIG_OF) += of/
|
||||
obj-$(CONFIG_SSB) += ssb/
|
||||
obj-$(CONFIG_VIRTIO) += virtio/
|
||||
obj-$(CONFIG_VLYNQ) += vlynq/
|
||||
obj-$(CONFIG_STAGING) += staging/
|
||||
obj-y += platform/
|
||||
obj-y += ieee802154/
|
||||
|
|
|
|||
|
|
@ -72,10 +72,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
|
|||
"Node %d Inactive(anon): %8lu kB\n"
|
||||
"Node %d Active(file): %8lu kB\n"
|
||||
"Node %d Inactive(file): %8lu kB\n"
|
||||
#ifdef CONFIG_UNEVICTABLE_LRU
|
||||
"Node %d Unevictable: %8lu kB\n"
|
||||
"Node %d Mlocked: %8lu kB\n"
|
||||
#endif
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
"Node %d HighTotal: %8lu kB\n"
|
||||
"Node %d HighFree: %8lu kB\n"
|
||||
|
|
@ -105,10 +103,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
|
|||
nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
|
||||
nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
|
||||
nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
|
||||
#ifdef CONFIG_UNEVICTABLE_LRU
|
||||
nid, K(node_page_state(nid, NR_UNEVICTABLE)),
|
||||
nid, K(node_page_state(nid, NR_MLOCK)),
|
||||
#endif
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
nid, K(i.totalhigh),
|
||||
nid, K(i.freehigh),
|
||||
|
|
|
|||
|
|
@ -171,8 +171,9 @@ int do_poke_blanked_console;
|
|||
int console_blanked;
|
||||
|
||||
static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
|
||||
static int blankinterval = 10*60*HZ;
|
||||
static int vesa_off_interval;
|
||||
static int blankinterval = 10*60;
|
||||
core_param(consoleblank, blankinterval, int, 0444);
|
||||
|
||||
static DECLARE_WORK(console_work, console_callback);
|
||||
|
||||
|
|
@ -1485,7 +1486,7 @@ static void setterm_command(struct vc_data *vc)
|
|||
update_attr(vc);
|
||||
break;
|
||||
case 9: /* set blanking interval */
|
||||
blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
|
||||
blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
|
||||
poke_blanked_console();
|
||||
break;
|
||||
case 10: /* set bell frequency in Hz */
|
||||
|
|
@ -2871,7 +2872,7 @@ static int __init con_init(void)
|
|||
|
||||
if (blankinterval) {
|
||||
blank_state = blank_normal_wait;
|
||||
mod_timer(&console_timer, jiffies + blankinterval);
|
||||
mod_timer(&console_timer, jiffies + (blankinterval * HZ));
|
||||
}
|
||||
|
||||
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
|
||||
|
|
@ -3677,7 +3678,7 @@ void do_unblank_screen(int leaving_gfx)
|
|||
return; /* but leave console_blanked != 0 */
|
||||
|
||||
if (blankinterval) {
|
||||
mod_timer(&console_timer, jiffies + blankinterval);
|
||||
mod_timer(&console_timer, jiffies + (blankinterval * HZ));
|
||||
blank_state = blank_normal_wait;
|
||||
}
|
||||
|
||||
|
|
@ -3711,7 +3712,7 @@ void unblank_screen(void)
|
|||
static void blank_screen_t(unsigned long dummy)
|
||||
{
|
||||
if (unlikely(!keventd_up())) {
|
||||
mod_timer(&console_timer, jiffies + blankinterval);
|
||||
mod_timer(&console_timer, jiffies + (blankinterval * HZ));
|
||||
return;
|
||||
}
|
||||
blank_timer_expired = 1;
|
||||
|
|
@ -3741,7 +3742,7 @@ void poke_blanked_console(void)
|
|||
if (console_blanked)
|
||||
unblank_screen();
|
||||
else if (blankinterval) {
|
||||
mod_timer(&console_timer, jiffies + blankinterval);
|
||||
mod_timer(&console_timer, jiffies + (blankinterval * HZ));
|
||||
blank_state = blank_normal_wait;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <linux/acpi_pmtmr.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
|
|||
|
|
@ -1140,6 +1140,11 @@ NON0301 "c't Universale Graphic Adapter"
|
|||
NON0401 "c't Universal Ethernet Adapter"
|
||||
NON0501 "c't Universal 16-Bit Sound Adapter"
|
||||
NON0601 "c't Universal 8-Bit Adapter"
|
||||
NPI0120 "Network Peripherals NP-EISA-1 FDDI Interface"
|
||||
NPI0221 "Network Peripherals NP-EISA-2 FDDI Interface"
|
||||
NPI0223 "Network Peripherals NP-EISA-2E Enhanced FDDI Interface"
|
||||
NPI0301 "Network Peripherals NP-EISA-3 FDDI Interface"
|
||||
NPI0303 "Network Peripherals NP-EISA-3E Enhanced FDDI Interface"
|
||||
NSS0011 "Newport Systems Solutions WNIC Adapter"
|
||||
NVL0701 "Novell NE3200 Bus Master Ethernet"
|
||||
NVL0702 "Novell NE3200T Bus Master Ethernet"
|
||||
|
|
|
|||
|
|
@ -31,8 +31,12 @@
|
|||
* information is necessary as for the resource tree.
|
||||
*/
|
||||
struct firmware_map_entry {
|
||||
resource_size_t start; /* start of the memory range */
|
||||
resource_size_t end; /* end of the memory range (incl.) */
|
||||
/*
|
||||
* start and end must be u64 rather than resource_size_t, because e820
|
||||
* resources can lie at addresses above 4G.
|
||||
*/
|
||||
u64 start; /* start of the memory range */
|
||||
u64 end; /* end of the memory range (incl.) */
|
||||
const char *type; /* type of the memory range */
|
||||
struct list_head list; /* entry for the linked list */
|
||||
struct kobject kobj; /* kobject for each entry */
|
||||
|
|
@ -101,7 +105,7 @@ static LIST_HEAD(map_entries);
|
|||
* Common implementation of firmware_map_add() and firmware_map_add_early()
|
||||
* which expects a pre-allocated struct firmware_map_entry.
|
||||
**/
|
||||
static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
|
||||
static int firmware_map_add_entry(u64 start, u64 end,
|
||||
const char *type,
|
||||
struct firmware_map_entry *entry)
|
||||
{
|
||||
|
|
@ -132,8 +136,7 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
|
|||
*
|
||||
* Returns 0 on success, or -ENOMEM if no memory could be allocated.
|
||||
**/
|
||||
int firmware_map_add(resource_size_t start, resource_size_t end,
|
||||
const char *type)
|
||||
int firmware_map_add(u64 start, u64 end, const char *type)
|
||||
{
|
||||
struct firmware_map_entry *entry;
|
||||
|
||||
|
|
@ -157,8 +160,7 @@ int firmware_map_add(resource_size_t start, resource_size_t end,
|
|||
*
|
||||
* Returns 0 on success, or -ENOMEM if no memory could be allocated.
|
||||
**/
|
||||
int __init firmware_map_add_early(resource_size_t start, resource_size_t end,
|
||||
const char *type)
|
||||
int __init firmware_map_add_early(u64 start, u64 end, const char *type)
|
||||
{
|
||||
struct firmware_map_entry *entry;
|
||||
|
||||
|
|
|
|||
|
|
@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
info->fbops = &intelfb_ops;
|
||||
|
||||
info->fix.line_length = fb->pitch;
|
||||
|
||||
/* setup aperture base/size for vesafb takeover */
|
||||
info->aperture_base = dev->mode_config.fb_base;
|
||||
if (IS_I9XX(dev))
|
||||
info->aperture_size = pci_resource_len(dev->pdev, 2);
|
||||
else
|
||||
info->aperture_size = pci_resource_len(dev->pdev, 0);
|
||||
|
||||
info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
|
||||
info->fix.smem_len = size;
|
||||
|
||||
|
|
|
|||
|
|
@ -950,6 +950,7 @@ config SENSORS_HDAPS
|
|||
config SENSORS_LIS3LV02D
|
||||
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
|
||||
depends on ACPI && INPUT
|
||||
select INPUT_POLLDEV
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
default n
|
||||
|
|
@ -977,6 +978,7 @@ config SENSORS_LIS3LV02D
|
|||
config SENSORS_LIS3_SPI
|
||||
tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
|
||||
depends on !ACPI && SPI_MASTER && INPUT
|
||||
select INPUT_POLLDEV
|
||||
default n
|
||||
help
|
||||
This driver provides support for the LIS3LV02Dx accelerometer connected
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/poll.h>
|
||||
|
|
@ -161,6 +158,7 @@ static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
|
|||
static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
|
||||
static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
|
||||
static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
|
||||
static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
|
||||
static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
|
||||
static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
|
||||
static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
|
||||
|
|
@ -194,13 +192,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
|||
AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
|
||||
AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
|
||||
AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
|
||||
AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
|
||||
AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
|
||||
AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
|
||||
AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
|
||||
AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
|
||||
AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
|
||||
AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
|
||||
AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted),
|
||||
AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
|
||||
AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
|
||||
AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
|
||||
/* Intel-based HP Pavilion dv5 */
|
||||
AXIS_DMI_MATCH2("HPDV5_I",
|
||||
PRODUCT_NAME, "HP Pavilion dv5",
|
||||
|
|
@ -216,7 +217,6 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
|||
{ NULL, }
|
||||
/* Laptop models without axis info (yet):
|
||||
* "NC6910" "HP Compaq 6910"
|
||||
* HP Compaq 8710x Notebook PC / Mobile Workstation
|
||||
* "NC2400" "HP Compaq nc2400"
|
||||
* "NX74x0" "HP Compaq nx74"
|
||||
* "NX6325" "HP Compaq nx6325"
|
||||
|
|
@ -324,7 +324,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
|
|||
flush_work(&hpled_led.work);
|
||||
led_classdev_unregister(&hpled_led.led_classdev);
|
||||
|
||||
return lis3lv02d_remove_fs();
|
||||
return lis3lv02d_remove_fs(&lis3_dev);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -338,13 +338,7 @@ static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
|
|||
|
||||
static int lis3lv02d_resume(struct acpi_device *device)
|
||||
{
|
||||
/* put back the device in the right state (ACPI might turn it on) */
|
||||
mutex_lock(&lis3_dev.lock);
|
||||
if (lis3_dev.usage > 0)
|
||||
lis3lv02d_poweron(&lis3_dev);
|
||||
else
|
||||
lis3lv02d_poweroff(&lis3_dev);
|
||||
mutex_unlock(&lis3_dev.lock);
|
||||
lis3lv02d_poweron(&lis3_dev);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/poll.h>
|
||||
|
|
@ -105,56 +103,39 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
|
|||
{
|
||||
int position[3];
|
||||
|
||||
position[0] = lis3_dev.read_data(lis3, OUTX);
|
||||
position[1] = lis3_dev.read_data(lis3, OUTY);
|
||||
position[2] = lis3_dev.read_data(lis3, OUTZ);
|
||||
position[0] = lis3->read_data(lis3, OUTX);
|
||||
position[1] = lis3->read_data(lis3, OUTY);
|
||||
position[2] = lis3->read_data(lis3, OUTZ);
|
||||
|
||||
*x = lis3lv02d_get_axis(lis3_dev.ac.x, position);
|
||||
*y = lis3lv02d_get_axis(lis3_dev.ac.y, position);
|
||||
*z = lis3lv02d_get_axis(lis3_dev.ac.z, position);
|
||||
*x = lis3lv02d_get_axis(lis3->ac.x, position);
|
||||
*y = lis3lv02d_get_axis(lis3->ac.y, position);
|
||||
*z = lis3lv02d_get_axis(lis3->ac.z, position);
|
||||
}
|
||||
|
||||
void lis3lv02d_poweroff(struct lis3lv02d *lis3)
|
||||
{
|
||||
lis3_dev.is_on = 0;
|
||||
/* disable X,Y,Z axis and power down */
|
||||
lis3->write(lis3, CTRL_REG1, 0x00);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
|
||||
|
||||
void lis3lv02d_poweron(struct lis3lv02d *lis3)
|
||||
{
|
||||
lis3_dev.is_on = 1;
|
||||
lis3_dev.init(lis3);
|
||||
u8 reg;
|
||||
|
||||
lis3->init(lis3);
|
||||
|
||||
/*
|
||||
* Common configuration
|
||||
* BDU: LSB and MSB values are not updated until both have been read.
|
||||
* So the value read will always be correct.
|
||||
*/
|
||||
lis3->read(lis3, CTRL_REG2, ®);
|
||||
reg |= CTRL2_BDU;
|
||||
lis3->write(lis3, CTRL_REG2, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
|
||||
|
||||
/*
|
||||
* To be called before starting to use the device. It makes sure that the
|
||||
* device will always be on until a call to lis3lv02d_decrease_use(). Not to be
|
||||
* used from interrupt context.
|
||||
*/
|
||||
static void lis3lv02d_increase_use(struct lis3lv02d *dev)
|
||||
{
|
||||
mutex_lock(&dev->lock);
|
||||
dev->usage++;
|
||||
if (dev->usage == 1) {
|
||||
if (!dev->is_on)
|
||||
lis3lv02d_poweron(dev);
|
||||
}
|
||||
mutex_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* To be called whenever a usage of the device is stopped.
|
||||
* It will make sure to turn off the device when there is not usage.
|
||||
*/
|
||||
static void lis3lv02d_decrease_use(struct lis3lv02d *dev)
|
||||
{
|
||||
mutex_lock(&dev->lock);
|
||||
dev->usage--;
|
||||
if (dev->usage == 0)
|
||||
lis3lv02d_poweroff(dev);
|
||||
mutex_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
|
||||
{
|
||||
|
|
@ -198,15 +179,12 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
|
|||
printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
lis3lv02d_increase_use(&lis3_dev);
|
||||
printk("lis3: registered interrupt %d\n", lis3_dev.irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
fasync_helper(-1, file, 0, &lis3_dev.async_queue);
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
free_irq(lis3_dev.irq, &lis3_dev);
|
||||
clear_bit(0, &lis3_dev.misc_opened); /* release the device */
|
||||
return 0;
|
||||
|
|
@ -290,46 +268,16 @@ static struct miscdevice lis3lv02d_misc_device = {
|
|||
.fops = &lis3lv02d_misc_fops,
|
||||
};
|
||||
|
||||
/**
|
||||
* lis3lv02d_joystick_kthread - Kthread polling function
|
||||
* @data: unused - here to conform to threadfn prototype
|
||||
*/
|
||||
static int lis3lv02d_joystick_kthread(void *data)
|
||||
static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
|
||||
{
|
||||
int x, y, z;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
|
||||
input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib);
|
||||
input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib);
|
||||
input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib);
|
||||
|
||||
input_sync(lis3_dev.idev);
|
||||
|
||||
try_to_freeze();
|
||||
msleep_interruptible(MDPS_POLL_INTERVAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
|
||||
input_report_abs(pidev->input, ABS_X, x - lis3_dev.xcalib);
|
||||
input_report_abs(pidev->input, ABS_Y, y - lis3_dev.ycalib);
|
||||
input_report_abs(pidev->input, ABS_Z, z - lis3_dev.zcalib);
|
||||
}
|
||||
|
||||
static int lis3lv02d_joystick_open(struct input_dev *input)
|
||||
{
|
||||
lis3lv02d_increase_use(&lis3_dev);
|
||||
lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
|
||||
if (IS_ERR(lis3_dev.kthread)) {
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
return PTR_ERR(lis3_dev.kthread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lis3lv02d_joystick_close(struct input_dev *input)
|
||||
{
|
||||
kthread_stop(lis3_dev.kthread);
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
}
|
||||
|
||||
static inline void lis3lv02d_calibrate_joystick(void)
|
||||
{
|
||||
|
|
@ -339,33 +287,36 @@ static inline void lis3lv02d_calibrate_joystick(void)
|
|||
|
||||
int lis3lv02d_joystick_enable(void)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
if (lis3_dev.idev)
|
||||
return -EINVAL;
|
||||
|
||||
lis3_dev.idev = input_allocate_device();
|
||||
lis3_dev.idev = input_allocate_polled_device();
|
||||
if (!lis3_dev.idev)
|
||||
return -ENOMEM;
|
||||
|
||||
lis3_dev.idev->poll = lis3lv02d_joystick_poll;
|
||||
lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
|
||||
input_dev = lis3_dev.idev->input;
|
||||
|
||||
lis3lv02d_calibrate_joystick();
|
||||
|
||||
lis3_dev.idev->name = "ST LIS3LV02DL Accelerometer";
|
||||
lis3_dev.idev->phys = DRIVER_NAME "/input0";
|
||||
lis3_dev.idev->id.bustype = BUS_HOST;
|
||||
lis3_dev.idev->id.vendor = 0;
|
||||
lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev;
|
||||
lis3_dev.idev->open = lis3lv02d_joystick_open;
|
||||
lis3_dev.idev->close = lis3lv02d_joystick_close;
|
||||
input_dev->name = "ST LIS3LV02DL Accelerometer";
|
||||
input_dev->phys = DRIVER_NAME "/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0;
|
||||
input_dev->dev.parent = &lis3_dev.pdev->dev;
|
||||
|
||||
set_bit(EV_ABS, lis3_dev.idev->evbit);
|
||||
input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
set_bit(EV_ABS, input_dev->evbit);
|
||||
input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
|
||||
|
||||
err = input_register_device(lis3_dev.idev);
|
||||
err = input_register_polled_device(lis3_dev.idev);
|
||||
if (err) {
|
||||
input_free_device(lis3_dev.idev);
|
||||
input_free_polled_device(lis3_dev.idev);
|
||||
lis3_dev.idev = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -378,8 +329,9 @@ void lis3lv02d_joystick_disable(void)
|
|||
if (!lis3_dev.idev)
|
||||
return;
|
||||
|
||||
misc_deregister(&lis3lv02d_misc_device);
|
||||
input_unregister_device(lis3_dev.idev);
|
||||
if (lis3_dev.irq)
|
||||
misc_deregister(&lis3lv02d_misc_device);
|
||||
input_unregister_polled_device(lis3_dev.idev);
|
||||
lis3_dev.idev = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
|
||||
|
|
@ -390,9 +342,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
|
|||
{
|
||||
int x, y, z;
|
||||
|
||||
lis3lv02d_increase_use(&lis3_dev);
|
||||
lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
|
||||
}
|
||||
|
||||
|
|
@ -406,9 +356,7 @@ static ssize_t lis3lv02d_calibrate_store(struct device *dev,
|
|||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
lis3lv02d_increase_use(&lis3_dev);
|
||||
lis3lv02d_calibrate_joystick();
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -420,9 +368,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
|
|||
u8 ctrl;
|
||||
int val;
|
||||
|
||||
lis3lv02d_increase_use(&lis3_dev);
|
||||
lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
|
||||
lis3lv02d_decrease_use(&lis3_dev);
|
||||
val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
|
||||
return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
|
||||
}
|
||||
|
|
@ -446,17 +392,17 @@ static struct attribute_group lis3lv02d_attribute_group = {
|
|||
|
||||
static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
|
||||
{
|
||||
lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
|
||||
if (IS_ERR(lis3_dev.pdev))
|
||||
return PTR_ERR(lis3_dev.pdev);
|
||||
lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
|
||||
if (IS_ERR(lis3->pdev))
|
||||
return PTR_ERR(lis3->pdev);
|
||||
|
||||
return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
|
||||
return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
|
||||
}
|
||||
|
||||
int lis3lv02d_remove_fs(void)
|
||||
int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
|
||||
{
|
||||
sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
|
||||
platform_device_unregister(lis3_dev.pdev);
|
||||
sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
|
||||
platform_device_unregister(lis3->pdev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
|
||||
|
|
@ -482,18 +428,35 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
|
|||
break;
|
||||
default:
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
": unknown sensor type 0x%X\n", lis3_dev.whoami);
|
||||
": unknown sensor type 0x%X\n", dev->whoami);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_init(&dev->lock);
|
||||
lis3lv02d_add_fs(dev);
|
||||
lis3lv02d_increase_use(dev);
|
||||
lis3lv02d_poweron(dev);
|
||||
|
||||
if (lis3lv02d_joystick_enable())
|
||||
printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
|
||||
|
||||
printk("lis3_init_device: irq %d\n", dev->irq);
|
||||
/* passing in platform specific data is purely optional and only
|
||||
* used by the SPI transport layer at the moment */
|
||||
if (dev->pdata) {
|
||||
struct lis3lv02d_platform_data *p = dev->pdata;
|
||||
|
||||
if (p->click_flags && (dev->whoami == LIS_SINGLE_ID)) {
|
||||
dev->write(dev, CLICK_CFG, p->click_flags);
|
||||
dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
|
||||
dev->write(dev, CLICK_LATENCY, p->click_latency);
|
||||
dev->write(dev, CLICK_WINDOW, p->click_window);
|
||||
dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
|
||||
dev->write(dev, CLICK_THSY_X,
|
||||
(p->click_thresh_x & 0xf) |
|
||||
(p->click_thresh_y << 4));
|
||||
}
|
||||
|
||||
if (p->irq_cfg)
|
||||
dev->write(dev, CTRL_REG3, p->irq_cfg);
|
||||
}
|
||||
|
||||
/* bail if we did not get an IRQ from the bus layer */
|
||||
if (!dev->irq) {
|
||||
|
|
@ -502,11 +465,9 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
printk("lis3: registering device\n");
|
||||
if (misc_register(&lis3lv02d_misc_device))
|
||||
printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
|
||||
out:
|
||||
lis3lv02d_decrease_use(dev);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input-polldev.h>
|
||||
|
||||
/*
|
||||
* The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
|
||||
|
|
@ -27,12 +29,14 @@
|
|||
* They can also be connected via I²C.
|
||||
*/
|
||||
|
||||
#include <linux/lis3lv02d.h>
|
||||
|
||||
/* 2-byte registers */
|
||||
#define LIS_DOUBLE_ID 0x3A /* LIS3LV02D[LQ] */
|
||||
/* 1-byte registers */
|
||||
#define LIS_SINGLE_ID 0x3B /* LIS[32]02DL and others */
|
||||
|
||||
enum lis3lv02d_reg {
|
||||
enum lis3_reg {
|
||||
WHO_AM_I = 0x0F,
|
||||
OFFSET_X = 0x16,
|
||||
OFFSET_Y = 0x17,
|
||||
|
|
@ -60,6 +64,19 @@ enum lis3lv02d_reg {
|
|||
FF_WU_THS_L = 0x34,
|
||||
FF_WU_THS_H = 0x35,
|
||||
FF_WU_DURATION = 0x36,
|
||||
};
|
||||
|
||||
enum lis302d_reg {
|
||||
CLICK_CFG = 0x38,
|
||||
CLICK_SRC = 0x39,
|
||||
CLICK_THSY_X = 0x3B,
|
||||
CLICK_THSZ = 0x3C,
|
||||
CLICK_TIMELIMIT = 0x3D,
|
||||
CLICK_LATENCY = 0x3E,
|
||||
CLICK_WINDOW = 0x3F,
|
||||
};
|
||||
|
||||
enum lis3lv02d_reg {
|
||||
DD_CFG = 0x38,
|
||||
DD_SRC = 0x39,
|
||||
DD_ACK = 0x3A,
|
||||
|
|
@ -169,22 +186,20 @@ struct lis3lv02d {
|
|||
s16 (*read_data) (struct lis3lv02d *lis3, int reg);
|
||||
int mdps_max_val;
|
||||
|
||||
struct input_dev *idev; /* input device */
|
||||
struct task_struct *kthread; /* kthread for input */
|
||||
struct mutex lock;
|
||||
struct input_polled_dev *idev; /* input device */
|
||||
struct platform_device *pdev; /* platform device */
|
||||
atomic_t count; /* interrupt count after last read */
|
||||
int xcalib; /* calibrated null value for x */
|
||||
int ycalib; /* calibrated null value for y */
|
||||
int zcalib; /* calibrated null value for z */
|
||||
unsigned char is_on; /* whether the device is on or off */
|
||||
unsigned char usage; /* usage counter */
|
||||
struct axis_conversion ac; /* hw -> logical axis */
|
||||
|
||||
u32 irq; /* IRQ number */
|
||||
struct fasync_struct *async_queue; /* queue for the misc device */
|
||||
wait_queue_head_t misc_wait; /* Wait queue for the misc device */
|
||||
unsigned long misc_opened; /* bit0: whether the device is open */
|
||||
|
||||
struct lis3lv02d_platform_data *pdata; /* for passing board config */
|
||||
};
|
||||
|
||||
int lis3lv02d_init_device(struct lis3lv02d *lis3);
|
||||
|
|
@ -192,6 +207,6 @@ int lis3lv02d_joystick_enable(void);
|
|||
void lis3lv02d_joystick_disable(void);
|
||||
void lis3lv02d_poweroff(struct lis3lv02d *lis3);
|
||||
void lis3lv02d_poweron(struct lis3lv02d *lis3);
|
||||
int lis3lv02d_remove_fs(void);
|
||||
int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
|
||||
|
||||
extern struct lis3lv02d lis3_dev;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
|
|||
lis3_dev.write = lis3_spi_write;
|
||||
lis3_dev.irq = spi->irq;
|
||||
lis3_dev.ac = lis3lv02d_axis_normal;
|
||||
lis3_dev.pdata = spi->dev.platform_data;
|
||||
spi_set_drvdata(spi, &lis3_dev);
|
||||
|
||||
ret = lis3lv02d_init_device(&lis3_dev);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/gameport.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <asm/timex.h>
|
||||
#include <linux/timex.h>
|
||||
|
||||
#define DRIVER_DESC "Analog joystick and gamepad driver"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/timex.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
|
||||
|
|
@ -25,6 +26,7 @@ struct videobuf_dma_contig_memory {
|
|||
void *vaddr;
|
||||
dma_addr_t dma_handle;
|
||||
unsigned long size;
|
||||
int is_userptr;
|
||||
};
|
||||
|
||||
#define MAGIC_DC_MEM 0x0733ac61
|
||||
|
|
@ -108,6 +110,82 @@ static struct vm_operations_struct videobuf_vm_ops = {
|
|||
.close = videobuf_vm_close,
|
||||
};
|
||||
|
||||
/**
|
||||
* videobuf_dma_contig_user_put() - reset pointer to user space buffer
|
||||
* @mem: per-buffer private videobuf-dma-contig data
|
||||
*
|
||||
* This function resets the user space pointer
|
||||
*/
|
||||
static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
|
||||
{
|
||||
mem->is_userptr = 0;
|
||||
mem->dma_handle = 0;
|
||||
mem->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* videobuf_dma_contig_user_get() - setup user space memory pointer
|
||||
* @mem: per-buffer private videobuf-dma-contig data
|
||||
* @vb: video buffer to map
|
||||
*
|
||||
* This function validates and sets up a pointer to user space memory.
|
||||
* Only physically contiguous pfn-mapped memory is accepted.
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
*/
|
||||
static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned long prev_pfn, this_pfn;
|
||||
unsigned long pages_done, user_address;
|
||||
int ret;
|
||||
|
||||
mem->size = PAGE_ALIGN(vb->size);
|
||||
mem->is_userptr = 0;
|
||||
ret = -EINVAL;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
|
||||
vma = find_vma(mm, vb->baddr);
|
||||
if (!vma)
|
||||
goto out_up;
|
||||
|
||||
if ((vb->baddr + mem->size) > vma->vm_end)
|
||||
goto out_up;
|
||||
|
||||
pages_done = 0;
|
||||
prev_pfn = 0; /* kill warning */
|
||||
user_address = vb->baddr;
|
||||
|
||||
while (pages_done < (mem->size >> PAGE_SHIFT)) {
|
||||
ret = follow_pfn(vma, user_address, &this_pfn);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (pages_done == 0)
|
||||
mem->dma_handle = this_pfn << PAGE_SHIFT;
|
||||
else if (this_pfn != (prev_pfn + 1))
|
||||
ret = -EFAULT;
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
prev_pfn = this_pfn;
|
||||
user_address += PAGE_SIZE;
|
||||
pages_done++;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
mem->is_userptr = 1;
|
||||
|
||||
out_up:
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *__videobuf_alloc(size_t size)
|
||||
{
|
||||
struct videobuf_dma_contig_memory *mem;
|
||||
|
|
@ -154,12 +232,11 @@ static int __videobuf_iolock(struct videobuf_queue *q,
|
|||
case V4L2_MEMORY_USERPTR:
|
||||
dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
|
||||
|
||||
/* The only USERPTR currently supported is the one needed for
|
||||
read() method.
|
||||
*/
|
||||
/* handle pointer from user space */
|
||||
if (vb->baddr)
|
||||
return -EINVAL;
|
||||
return videobuf_dma_contig_user_get(mem, vb);
|
||||
|
||||
/* allocate memory for the read() method */
|
||||
mem->size = PAGE_ALIGN(vb->size);
|
||||
mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
|
||||
&mem->dma_handle, GFP_KERNEL);
|
||||
|
|
@ -400,7 +477,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
|
|||
So, it should free memory only if the memory were allocated for
|
||||
read() operation.
|
||||
*/
|
||||
if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
|
||||
if (buf->memory != V4L2_MEMORY_USERPTR)
|
||||
return;
|
||||
|
||||
if (!mem)
|
||||
|
|
@ -408,6 +485,13 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
|
|||
|
||||
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
|
||||
|
||||
/* handle user space pointer case */
|
||||
if (buf->baddr) {
|
||||
videobuf_dma_contig_user_put(mem);
|
||||
return;
|
||||
}
|
||||
|
||||
/* read() method */
|
||||
dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
|
||||
mem->vaddr = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
|
|||
pnode = uv_node_to_pnode(nid);
|
||||
if (bid < 0 || gru_base[bid])
|
||||
continue;
|
||||
page = alloc_pages_node(nid, GFP_KERNEL, order);
|
||||
page = alloc_pages_exact_node(nid, GFP_KERNEL, order);
|
||||
if (!page)
|
||||
goto fail;
|
||||
gru_base[bid] = page_address(page);
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
|
|||
mq->mmr_blade = uv_cpu_to_blade_id(cpu);
|
||||
|
||||
nid = cpu_to_node(cpu);
|
||||
page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
|
||||
page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
|
||||
pg_order);
|
||||
if (page == NULL) {
|
||||
dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
|
||||
|
|
|
|||
|
|
@ -915,12 +915,9 @@ static int ds_ioctl(struct inode * inode, struct file * file,
|
|||
err = -EPERM;
|
||||
goto free_out;
|
||||
} else {
|
||||
static int printed = 0;
|
||||
if (!printed) {
|
||||
printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
|
||||
printk(KERN_WARNING "MTD handling any more.\n");
|
||||
printed++;
|
||||
}
|
||||
printk_once(KERN_WARNING
|
||||
"2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
|
||||
printk_once(KERN_WARNING "MTD handling any more.\n");
|
||||
}
|
||||
err = -EINVAL;
|
||||
goto free_out;
|
||||
|
|
|
|||
|
|
@ -711,12 +711,12 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
|
||||
pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
|
||||
if (!pinfo->gpios)
|
||||
return -ENOMEM;
|
||||
memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
|
||||
memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
|
||||
|
||||
pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
|
||||
pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
|
||||
GFP_KERNEL);
|
||||
if (!pinfo->alow_flags) {
|
||||
ret = -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -2104,6 +2104,7 @@ config FB_MB862XX_LIME
|
|||
bool "Lime GDC"
|
||||
depends on FB_MB862XX
|
||||
depends on OF && !FB_MB862XX_PCI_GDC
|
||||
depends on PPC
|
||||
select FB_FOREIGN_ENDIAN
|
||||
select FB_LITTLE_ENDIAN
|
||||
---help---
|
||||
|
|
|
|||
|
|
@ -859,43 +859,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we are entered with the kernel locked.
|
||||
*/
|
||||
static int
|
||||
acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long off, start;
|
||||
u32 len;
|
||||
|
||||
off = vma->vm_pgoff << PAGE_SHIFT;
|
||||
|
||||
start = info->fix.smem_start;
|
||||
len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
|
||||
start &= PAGE_MASK;
|
||||
if ((vma->vm_end - vma->vm_start + off) > len)
|
||||
return -EINVAL;
|
||||
off += start;
|
||||
vma->vm_pgoff = off >> PAGE_SHIFT;
|
||||
|
||||
/* This is an IO map - tell maydump to skip this VMA */
|
||||
vma->vm_flags |= VM_IO;
|
||||
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
/*
|
||||
* Don't alter the page protection flags; we want to keep the area
|
||||
* cached for better performance. This does mean that we may miss
|
||||
* some updates to the screen occasionally, but process switches
|
||||
* should cause the caches and buffers to be flushed often enough.
|
||||
*/
|
||||
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
|
||||
vma->vm_end - vma->vm_start,
|
||||
vma->vm_page_prot))
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fb_ops acornfb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_check_var = acornfb_check_var,
|
||||
|
|
@ -905,7 +868,6 @@ static struct fb_ops acornfb_ops = {
|
|||
.fb_fillrect = cfb_fillrect,
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = cfb_imageblit,
|
||||
.fb_mmap = acornfb_mmap,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
|
|||
dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
|
||||
dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
|
||||
|
||||
if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
|
||||
if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
|
||||
dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
|
|||
PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
|
||||
OUTPLL(pllPIXCLKS_CNTL, tmp);
|
||||
|
||||
|
|
@ -395,7 +394,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
|
|||
PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb |
|
||||
PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb);
|
||||
PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb);
|
||||
OUTPLL(pllPIXCLKS_CNTL, tmp);
|
||||
|
||||
tmp = INPLL(pllMCLK_MISC);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user)
|
|||
bfin_write_EPPI0_CONTROL(0);
|
||||
SSYNC();
|
||||
disable_dma(CH_EPPI0);
|
||||
memset(fbi->fb_buffer, 0, info->fix.smem_len);
|
||||
}
|
||||
|
||||
spin_unlock(&fbi->lock);
|
||||
|
|
@ -530,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __init bfin_bf54x_probe(struct platform_device *pdev)
|
||||
static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_bf54xfb_info *info;
|
||||
struct fb_info *fbinfo;
|
||||
|
|
@ -626,14 +625,12 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
|
|||
goto out3;
|
||||
}
|
||||
|
||||
memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
|
||||
|
||||
fbinfo->screen_base = (void *)info->fb_buffer;
|
||||
fbinfo->fix.smem_start = (int)info->fb_buffer;
|
||||
|
||||
fbinfo->fbops = &bfin_bf54x_fb_ops;
|
||||
|
||||
fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
|
||||
fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
|
||||
if (!fbinfo->pseudo_palette) {
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
"Fail to allocate pseudo_palette\n");
|
||||
|
|
@ -642,8 +639,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
|
|||
goto out4;
|
||||
}
|
||||
|
||||
memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16);
|
||||
|
||||
if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0)
|
||||
< 0) {
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
|
|
@ -712,7 +707,7 @@ out1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_bf54x_remove(struct platform_device *pdev)
|
||||
static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
struct fb_info *fbinfo = platform_get_drvdata(pdev);
|
||||
|
|
@ -781,7 +776,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver bfin_bf54x_driver = {
|
||||
.probe = bfin_bf54x_probe,
|
||||
.remove = bfin_bf54x_remove,
|
||||
.remove = __devexit_p(bfin_bf54x_remove),
|
||||
.suspend = bfin_bf54x_suspend,
|
||||
.resume = bfin_bf54x_resume,
|
||||
.driver = {
|
||||
|
|
@ -790,7 +785,7 @@ static struct platform_driver bfin_bf54x_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __devinit bfin_bf54x_driver_init(void)
|
||||
static int __init bfin_bf54x_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_bf54x_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user)
|
|||
SSYNC();
|
||||
disable_dma(CH_PPI);
|
||||
bfin_t350mcqb_stop_timers();
|
||||
memset(fbi->fb_buffer, 0, info->fix.smem_len);
|
||||
}
|
||||
|
||||
spin_unlock(&fbi->lock);
|
||||
|
|
@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
|
|||
goto out3;
|
||||
}
|
||||
|
||||
memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
|
||||
|
||||
fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
|
||||
fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
|
||||
|
||||
|
|
@ -602,7 +599,7 @@ out1:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_t350mcqb_remove(struct platform_device *pdev)
|
||||
static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
|
||||
{
|
||||
|
||||
struct fb_info *fbinfo = platform_get_drvdata(pdev);
|
||||
|
|
@ -637,9 +634,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev)
|
|||
#ifdef CONFIG_PM
|
||||
static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct fb_info *fbinfo = platform_get_drvdata(pdev);
|
||||
struct bfin_t350mcqbfb_info *info = fbinfo->par;
|
||||
|
||||
bfin_t350mcqb_disable_ppi();
|
||||
disable_dma(CH_PPI);
|
||||
bfin_write_PPI_STATUS(0xFFFF);
|
||||
|
|
@ -649,9 +643,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat
|
|||
|
||||
static int bfin_t350mcqb_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct fb_info *fbinfo = platform_get_drvdata(pdev);
|
||||
struct bfin_t350mcqbfb_info *info = fbinfo->par;
|
||||
|
||||
enable_dma(CH_PPI);
|
||||
bfin_t350mcqb_enable_ppi();
|
||||
|
||||
|
|
@ -664,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev)
|
|||
|
||||
static struct platform_driver bfin_t350mcqb_driver = {
|
||||
.probe = bfin_t350mcqb_probe,
|
||||
.remove = bfin_t350mcqb_remove,
|
||||
.remove = __devexit_p(bfin_t350mcqb_remove),
|
||||
.suspend = bfin_t350mcqb_suspend,
|
||||
.resume = bfin_t350mcqb_resume,
|
||||
.driver = {
|
||||
|
|
@ -673,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __devinit bfin_t350mcqb_driver_init(void)
|
||||
static int __init bfin_t350mcqb_driver_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_t350mcqb_driver);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_bas
|
|||
if (ret < 0)
|
||||
goto err_free_fb;
|
||||
|
||||
if (fb_mode > ARRAY_SIZE(carmine_modedb))
|
||||
if (fb_mode >= ARRAY_SIZE(carmine_modedb))
|
||||
fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
|
||||
|
||||
par->cur_mode = par->new_mode = ~0;
|
||||
|
|
|
|||
|
|
@ -414,7 +414,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
|
|||
}
|
||||
|
||||
pci_set_drvdata(dp, p);
|
||||
p->device = &dp->dev;
|
||||
|
||||
init_chips(p, addr);
|
||||
|
||||
|
|
|
|||
|
|
@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev)
|
|||
info->pseudo_palette = info->par;
|
||||
info->par = NULL;
|
||||
|
||||
info->aperture_base = efifb_fix.smem_start;
|
||||
info->aperture_size = size_total;
|
||||
|
||||
info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
|
||||
if (!info->screen_base) {
|
||||
printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
|
||||
|
|
@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev)
|
|||
info->fbops = &efifb_ops;
|
||||
info->var = efifb_defined;
|
||||
info->fix = efifb_fix;
|
||||
info->flags = FBINFO_FLAG_DEFAULT;
|
||||
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
|
||||
|
||||
if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
|
||||
printk(KERN_ERR "efifb: cannot allocate colormap\n");
|
||||
|
|
|
|||
|
|
@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
|
||||
{
|
||||
/* is the generic aperture base the same as the HW one */
|
||||
if (gen->aperture_base == hw->aperture_base)
|
||||
return true;
|
||||
/* is the generic aperture base inside the hw base->hw base+size */
|
||||
if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* register_framebuffer - registers a frame buffer device
|
||||
* @fb_info: frame buffer info structure
|
||||
|
|
@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info)
|
|||
if (fb_check_foreignness(fb_info))
|
||||
return -ENOSYS;
|
||||
|
||||
/* check all firmware fbs and kick off if the base addr overlaps */
|
||||
for (i = 0 ; i < FB_MAX; i++) {
|
||||
if (!registered_fb[i])
|
||||
continue;
|
||||
|
||||
if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
|
||||
if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
|
||||
printk(KERN_ERR "fb: conflicting fb hw usage "
|
||||
"%s vs %s - removing generic driver\n",
|
||||
fb_info->fix.id,
|
||||
registered_fb[i]->fix.id);
|
||||
unregister_framebuffer(registered_fb[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
num_registered_fb++;
|
||||
for (i = 0 ; i < FB_MAX; i++)
|
||||
if (!registered_fb[i])
|
||||
|
|
@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info)
|
|||
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
|
||||
event.info = fb_info;
|
||||
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
|
||||
|
||||
/* this may free fb info */
|
||||
if (fb_info->fbops->fb_destroy)
|
||||
fb_info->fbops->fb_destroy(fb_info);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,17 +395,16 @@ int __init igafb_init(void)
|
|||
/* We leak a reference here but as it cannot be unloaded this is
|
||||
fine. If you write unload code remember to free it in unload */
|
||||
|
||||
size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
|
||||
size = sizeof(struct iga_par) + sizeof(u32)*16;
|
||||
|
||||
info = kzalloc(size, GFP_ATOMIC);
|
||||
info = framebuffer_alloc(size, &pdev->dev);
|
||||
if (!info) {
|
||||
printk("igafb_init: can't alloc fb_info\n");
|
||||
pci_dev_put(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
par = (struct iga_par *) (info + 1);
|
||||
|
||||
par = info->par;
|
||||
|
||||
if ((addr = pdev->resource[0].start) == 0) {
|
||||
printk("igafb_init: no memory start\n");
|
||||
|
|
@ -526,7 +525,6 @@ int __init igafb_init(void)
|
|||
info->var = default_var;
|
||||
info->fix = igafb_fix;
|
||||
info->pseudo_palette = (void *)(par + 1);
|
||||
info->device = &pdev->dev;
|
||||
|
||||
if (!iga_init(info, par)) {
|
||||
iounmap((void *)par->io_base);
|
||||
|
|
|
|||
|
|
@ -1365,6 +1365,11 @@ static int intelfb_set_par(struct fb_info *info)
|
|||
DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
|
||||
info->var.yres, info->var.bits_per_pixel);
|
||||
|
||||
/*
|
||||
* Disable VCO prior to timing register change.
|
||||
*/
|
||||
OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE);
|
||||
|
||||
intelfb_blank(FB_BLANK_POWERDOWN, info);
|
||||
|
||||
if (ACCEL(dinfo, info))
|
||||
|
|
|
|||
|
|
@ -37,22 +37,24 @@ extra-y += $(call logo-cfiles,_clut224,ppm)
|
|||
# Gray 256
|
||||
extra-y += $(call logo-cfiles,_gray256,pgm)
|
||||
|
||||
pnmtologo := scripts/pnmtologo
|
||||
|
||||
# Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
|
||||
quiet_cmd_logo = LOGO $@
|
||||
cmd_logo = scripts/pnmtologo \
|
||||
cmd_logo = $(pnmtologo) \
|
||||
-t $(patsubst $*_%,%,$(notdir $(basename $<))) \
|
||||
-n $(notdir $(basename $<)) -o $@ $<
|
||||
|
||||
$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE
|
||||
$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE
|
||||
$(call if_changed,logo)
|
||||
|
||||
$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE
|
||||
$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE
|
||||
$(call if_changed,logo)
|
||||
|
||||
$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE
|
||||
$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE
|
||||
$(call if_changed,logo)
|
||||
|
||||
$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE
|
||||
$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE
|
||||
$(call if_changed,logo)
|
||||
|
||||
# Files generated that shall be removed upon make clean
|
||||
|
|
|
|||
|
|
@ -21,21 +21,6 @@
|
|||
#include <asm/bootinfo.h>
|
||||
#endif
|
||||
|
||||
extern const struct linux_logo logo_linux_mono;
|
||||
extern const struct linux_logo logo_linux_vga16;
|
||||
extern const struct linux_logo logo_linux_clut224;
|
||||
extern const struct linux_logo logo_blackfin_vga16;
|
||||
extern const struct linux_logo logo_blackfin_clut224;
|
||||
extern const struct linux_logo logo_dec_clut224;
|
||||
extern const struct linux_logo logo_mac_clut224;
|
||||
extern const struct linux_logo logo_parisc_clut224;
|
||||
extern const struct linux_logo logo_sgi_clut224;
|
||||
extern const struct linux_logo logo_sun_clut224;
|
||||
extern const struct linux_logo logo_superh_mono;
|
||||
extern const struct linux_logo logo_superh_vga16;
|
||||
extern const struct linux_logo logo_superh_clut224;
|
||||
extern const struct linux_logo logo_m32r_clut224;
|
||||
|
||||
static int nologo;
|
||||
module_param(nologo, bool, 0);
|
||||
MODULE_PARM_DESC(nologo, "Disables startup logo");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#if defined(CONFIG_PPC_OF)
|
||||
#if defined(CONFIG_OF)
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
#include "mb862xxfb.h"
|
||||
|
|
|
|||
|
|
@ -264,6 +264,14 @@ static const struct fb_videomode modedb[] = {
|
|||
/* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
|
||||
NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
|
||||
0, FB_VMODE_NONINTERLACED
|
||||
}, {
|
||||
/* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
|
||||
NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5,
|
||||
0, FB_VMODE_INTERLACED
|
||||
}, {
|
||||
/* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
|
||||
NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5,
|
||||
0, FB_VMODE_INTERLACED
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -378,7 +378,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
|
|||
struct fb_fix_screeninfo *fix;
|
||||
struct fb_var_screeninfo *var;
|
||||
struct fb_info *info;
|
||||
int size;
|
||||
|
||||
if (!request_mem_region(res_start, res_size, "offb"))
|
||||
return;
|
||||
|
|
@ -393,15 +392,12 @@ static void __init offb_init_fb(const char *name, const char *full_name,
|
|||
return;
|
||||
}
|
||||
|
||||
size = sizeof(struct fb_info) + sizeof(u32) * 16;
|
||||
|
||||
info = kmalloc(size, GFP_ATOMIC);
|
||||
info = framebuffer_alloc(sizeof(u32) * 16, NULL);
|
||||
|
||||
if (info == 0) {
|
||||
release_mem_region(res_start, res_size);
|
||||
return;
|
||||
}
|
||||
memset(info, 0, size);
|
||||
|
||||
fix = &info->fix;
|
||||
var = &info->var;
|
||||
|
|
@ -497,7 +493,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
|
|||
iounmap(par->cmap_adr);
|
||||
par->cmap_adr = NULL;
|
||||
iounmap(info->screen_base);
|
||||
kfree(info);
|
||||
framebuffer_release(info);
|
||||
release_mem_region(res_start, res_size);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1748,7 +1748,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev)
|
|||
pci_set_drvdata(pdev, NULL);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
kfree(info->pixmap.addr);
|
||||
kfree(info);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
static struct pci_device_id pm2fb_id_table[] = {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
*
|
||||
* (c) 2004 Simtec Electronics
|
||||
* (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
|
||||
* (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
|
||||
*
|
||||
* Driver for Epson S1D13xxx series framebuffer chips
|
||||
*
|
||||
|
|
@ -10,18 +11,10 @@
|
|||
* linux/drivers/video/epson1355fb.c
|
||||
* linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
|
||||
*
|
||||
* Note, currently only tested on S1D13806 with 16bit CRT.
|
||||
* As such, this driver might still contain some hardcoded bits relating to
|
||||
* S1D13806.
|
||||
* Making it work on other S1D13XXX chips should merely be a matter of adding
|
||||
* a few switch()s, some missing glue here and there maybe, and split header
|
||||
* files.
|
||||
*
|
||||
* TODO: - handle dual screen display (CRT and LCD at the same time).
|
||||
* - check_var(), mode change, etc.
|
||||
* - PM untested.
|
||||
* - Accelerated interfaces.
|
||||
* - Probably not SMP safe :)
|
||||
* - probably not SMP safe :)
|
||||
* - support all bitblt operations on all cards
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive for
|
||||
|
|
@ -31,19 +24,24 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mman.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <video/s1d13xxxfb.h>
|
||||
|
||||
#define PFX "s1d13xxxfb: "
|
||||
#define PFX "s1d13xxxfb: "
|
||||
#define BLIT "s1d13xxxfb_bitblt: "
|
||||
|
||||
/*
|
||||
* set this to enable debugging on general functions
|
||||
*/
|
||||
#if 0
|
||||
#define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
|
||||
#else
|
||||
|
|
@ -51,7 +49,21 @@
|
|||
#endif
|
||||
|
||||
/*
|
||||
* List of card production ids
|
||||
* set this to enable debugging on 2D acceleration
|
||||
*/
|
||||
#if 0
|
||||
#define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0)
|
||||
#else
|
||||
#define dbg_blit(fmt, args...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* we make sure only one bitblt operation is running
|
||||
*/
|
||||
static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock);
|
||||
|
||||
/*
|
||||
* list of card production ids
|
||||
*/
|
||||
static const int s1d13xxxfb_prod_ids[] = {
|
||||
S1D13505_PROD_ID,
|
||||
|
|
@ -69,7 +81,7 @@ static const char *s1d13xxxfb_prod_names[] = {
|
|||
};
|
||||
|
||||
/*
|
||||
* Here we define the default struct fb_fix_screeninfo
|
||||
* here we define the default struct fb_fix_screeninfo
|
||||
*/
|
||||
static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
|
||||
.id = S1D_FBID,
|
||||
|
|
@ -145,8 +157,10 @@ crt_enable(struct s1d13xxxfb_par *par, int enable)
|
|||
s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
|
||||
}
|
||||
|
||||
/* framebuffer control routines */
|
||||
|
||||
/*************************************************************
|
||||
framebuffer control functions
|
||||
*************************************************************/
|
||||
static inline void
|
||||
s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
|
||||
{
|
||||
|
|
@ -242,13 +256,13 @@ s1d13xxxfb_set_par(struct fb_info *info)
|
|||
}
|
||||
|
||||
/**
|
||||
* s1d13xxxfb_setcolreg - sets a color register.
|
||||
* @regno: Which register in the CLUT we are programming
|
||||
* @red: The red value which can be up to 16 bits wide
|
||||
* s1d13xxxfb_setcolreg - sets a color register.
|
||||
* @regno: Which register in the CLUT we are programming
|
||||
* @red: The red value which can be up to 16 bits wide
|
||||
* @green: The green value which can be up to 16 bits wide
|
||||
* @blue: The blue value which can be up to 16 bits wide.
|
||||
* @transp: If supported the alpha value which can be up to 16 bits wide.
|
||||
* @info: frame buffer info structure
|
||||
* @info: frame buffer info structure
|
||||
*
|
||||
* Returns negative errno on error, or zero on success.
|
||||
*/
|
||||
|
|
@ -351,15 +365,15 @@ s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
|
|||
}
|
||||
|
||||
/**
|
||||
* s1d13xxxfb_pan_display - Pans the display.
|
||||
* @var: frame buffer variable screen structure
|
||||
* @info: frame buffer structure that represents a single frame buffer
|
||||
* s1d13xxxfb_pan_display - Pans the display.
|
||||
* @var: frame buffer variable screen structure
|
||||
* @info: frame buffer structure that represents a single frame buffer
|
||||
*
|
||||
* Pan (or wrap, depending on the `vmode' field) the display using the
|
||||
* `yoffset' field of the `var' structure (`xoffset' not yet supported).
|
||||
* If the values don't fit, return -EINVAL.
|
||||
* `yoffset' field of the `var' structure (`xoffset' not yet supported).
|
||||
* If the values don't fit, return -EINVAL.
|
||||
*
|
||||
* Returns negative errno on error, or zero on success.
|
||||
* Returns negative errno on error, or zero on success.
|
||||
*/
|
||||
static int
|
||||
s1d13xxxfb_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)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* framebuffer information structures */
|
||||
/************************************************************
|
||||
functions to handle bitblt acceleration
|
||||
************************************************************/
|
||||
|
||||
/**
|
||||
* bltbit_wait_bitset - waits for change in register value
|
||||
* @info : framebuffer structure
|
||||
* @bit : value expected in register
|
||||
* @timeout : ...
|
||||
*
|
||||
* waits until value changes INTO bit
|
||||
*/
|
||||
static u8
|
||||
bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout)
|
||||
{
|
||||
while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) {
|
||||
udelay(10);
|
||||
if (!--timeout) {
|
||||
dbg_blit("wait_bitset timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* bltbit_wait_bitclear - waits for change in register value
|
||||
* @info : frambuffer structure
|
||||
* @bit : value currently in register
|
||||
* @timeout : ...
|
||||
*
|
||||
* waits until value changes FROM bit
|
||||
*
|
||||
*/
|
||||
static u8
|
||||
bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
|
||||
{
|
||||
while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) {
|
||||
udelay(10);
|
||||
if (!--timeout) {
|
||||
dbg_blit("wait_bitclear timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* bltbit_fifo_status - checks the current status of the fifo
|
||||
* @info : framebuffer structure
|
||||
*
|
||||
* returns number of free words in buffer
|
||||
*/
|
||||
static u8
|
||||
bltbit_fifo_status(struct fb_info *info)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0);
|
||||
|
||||
/* its empty so room for 16 words */
|
||||
if (status & BBLT_FIFO_EMPTY)
|
||||
return 16;
|
||||
|
||||
/* its full so we dont want to add */
|
||||
if (status & BBLT_FIFO_FULL)
|
||||
return 0;
|
||||
|
||||
/* its atleast half full but we can add one atleast */
|
||||
if (status & BBLT_FIFO_NOT_FULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* s1d13xxxfb_bitblt_copyarea - accelerated copyarea function
|
||||
* @info : framebuffer structure
|
||||
* @area : fb_copyarea structure
|
||||
*
|
||||
* supports (atleast) S1D13506
|
||||
*
|
||||
*/
|
||||
static void
|
||||
s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area)
|
||||
{
|
||||
u32 dst, src;
|
||||
u32 stride;
|
||||
u16 reverse = 0;
|
||||
u16 sx = area->sx, sy = area->sy;
|
||||
u16 dx = area->dx, dy = area->dy;
|
||||
u16 width = area->width, height = area->height;
|
||||
u16 bpp;
|
||||
|
||||
spin_lock(&s1d13xxxfb_bitblt_lock);
|
||||
|
||||
/* bytes per xres line */
|
||||
bpp = (info->var.bits_per_pixel >> 3);
|
||||
stride = bpp * info->var.xres;
|
||||
|
||||
/* reverse, calculate the last pixel in rectangle */
|
||||
if ((dy > sy) || ((dy == sy) && (dx >= sx))) {
|
||||
dst = (((dy + height - 1) * stride) + (bpp * (dx + width - 1)));
|
||||
src = (((sy + height - 1) * stride) + (bpp * (sx + width - 1)));
|
||||
reverse = 1;
|
||||
/* not reverse, calculate the first pixel in rectangle */
|
||||
} else { /* (y * xres) + (bpp * x) */
|
||||
dst = (dy * stride) + (bpp * dx);
|
||||
src = (sy * stride) + (bpp * sx);
|
||||
}
|
||||
|
||||
/* set source adress */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff));
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff);
|
||||
|
||||
/* set destination adress */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff));
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff);
|
||||
|
||||
/* program height and width */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, (width & 0xff) - 1);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (width >> 8));
|
||||
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, (height & 0xff) - 1);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (height >> 8));
|
||||
|
||||
/* negative direction ROP */
|
||||
if (reverse == 1) {
|
||||
dbg_blit("(copyarea) negative rop\n");
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x03);
|
||||
} else /* positive direction ROP */ {
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x02);
|
||||
dbg_blit("(copyarea) positive rop\n");
|
||||
}
|
||||
|
||||
/* set for rectangel mode and not linear */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
|
||||
|
||||
/* setup the bpp 1 = 16bpp, 0 = 8bpp*/
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (bpp >> 1));
|
||||
|
||||
/* set words per xres */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (stride >> 1) & 0xff);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (stride >> 9));
|
||||
|
||||
dbg_blit("(copyarea) dx=%d, dy=%d\n", dx, dy);
|
||||
dbg_blit("(copyarea) sx=%d, sy=%d\n", sx, sy);
|
||||
dbg_blit("(copyarea) width=%d, height=%d\n", width - 1, height - 1);
|
||||
dbg_blit("(copyarea) stride=%d\n", stride);
|
||||
dbg_blit("(copyarea) bpp=%d=0x0%d, mem_offset1=%d, mem_offset2=%d\n", bpp, (bpp >> 1),
|
||||
(stride >> 1) & 0xff, stride >> 9);
|
||||
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CC_EXP, 0x0c);
|
||||
|
||||
/* initialize the engine */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
|
||||
|
||||
/* wait to complete */
|
||||
bltbit_wait_bitclear(info, 0x80, 8000);
|
||||
|
||||
spin_unlock(&s1d13xxxfb_bitblt_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* s1d13xxxfb_bitblt_solidfill - accelerated solidfill function
|
||||
* @info : framebuffer structure
|
||||
* @rect : fb_fillrect structure
|
||||
*
|
||||
* supports (atleast 13506)
|
||||
*
|
||||
**/
|
||||
static void
|
||||
s1d13xxxfb_bitblt_solidfill(struct fb_info *info, const struct fb_fillrect *rect)
|
||||
{
|
||||
u32 screen_stride, dest;
|
||||
u32 fg;
|
||||
u16 bpp = (info->var.bits_per_pixel >> 3);
|
||||
|
||||
/* grab spinlock */
|
||||
spin_lock(&s1d13xxxfb_bitblt_lock);
|
||||
|
||||
/* bytes per x width */
|
||||
screen_stride = (bpp * info->var.xres);
|
||||
|
||||
/* bytes to starting point */
|
||||
dest = ((rect->dy * screen_stride) + (bpp * rect->dx));
|
||||
|
||||
dbg_blit("(solidfill) dx=%d, dy=%d, stride=%d, dest=%d\n"
|
||||
"(solidfill) : rect_width=%d, rect_height=%d\n",
|
||||
rect->dx, rect->dy, screen_stride, dest,
|
||||
rect->width - 1, rect->height - 1);
|
||||
|
||||
dbg_blit("(solidfill) : xres=%d, yres=%d, bpp=%d\n",
|
||||
info->var.xres, info->var.yres,
|
||||
info->var.bits_per_pixel);
|
||||
dbg_blit("(solidfill) : rop=%d\n", rect->rop);
|
||||
|
||||
/* We split the destination into the three registers */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dest & 0x00ff));
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, ((dest >> 8) & 0x00ff));
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, ((dest >> 16) & 0x00ff));
|
||||
|
||||
/* give information regarding rectangel width */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, ((rect->width) & 0x00ff) - 1);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (rect->width >> 8));
|
||||
|
||||
/* give information regarding rectangel height */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, ((rect->height) & 0x00ff) - 1);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (rect->height >> 8));
|
||||
|
||||
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
|
||||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
|
||||
fg = ((u32 *)info->pseudo_palette)[rect->color];
|
||||
dbg_blit("(solidfill) truecolor/directcolor\n");
|
||||
dbg_blit("(solidfill) pseudo_palette[%d] = %d\n", rect->color, fg);
|
||||
} else {
|
||||
fg = rect->color;
|
||||
dbg_blit("(solidfill) color = %d\n", rect->color);
|
||||
}
|
||||
|
||||
/* set foreground color */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff));
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff);
|
||||
|
||||
/* set rectangual region of memory (rectangle and not linear) */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
|
||||
|
||||
/* set operation mode SOLID_FILL */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL);
|
||||
|
||||
/* set bits per pixel (1 = 16bpp, 0 = 8bpp) */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4));
|
||||
|
||||
/* set the memory offset for the bblt in word sizes */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff);
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9));
|
||||
|
||||
/* and away we go.... */
|
||||
s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
|
||||
|
||||
/* wait until its done */
|
||||
bltbit_wait_bitclear(info, 0x80, 8000);
|
||||
|
||||
/* let others play */
|
||||
spin_unlock(&s1d13xxxfb_bitblt_lock);
|
||||
}
|
||||
|
||||
/* framebuffer information structures */
|
||||
static struct fb_ops s1d13xxxfb_fbops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_set_par = s1d13xxxfb_set_par,
|
||||
|
|
@ -400,7 +665,7 @@ static struct fb_ops s1d13xxxfb_fbops = {
|
|||
|
||||
.fb_pan_display = s1d13xxxfb_pan_display,
|
||||
|
||||
/* to be replaced by any acceleration we can */
|
||||
/* gets replaced at chip detection time */
|
||||
.fb_fillrect = cfb_fillrect,
|
||||
.fb_copyarea = cfb_copyarea,
|
||||
.fb_imageblit = cfb_imageblit,
|
||||
|
|
@ -412,9 +677,9 @@ static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
|
|||
};
|
||||
|
||||
/**
|
||||
* s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
|
||||
* s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
|
||||
* hardware setup.
|
||||
* @info: frame buffer structure
|
||||
* @info: frame buffer structure
|
||||
*
|
||||
* We setup the framebuffer structures according to the current
|
||||
* hardware setup. On some machines, the BIOS will have filled
|
||||
|
|
@ -569,7 +834,6 @@ s1d13xxxfb_probe(struct platform_device *pdev)
|
|||
if (pdata && pdata->platform_init_video)
|
||||
pdata->platform_init_video();
|
||||
|
||||
|
||||
if (pdev->num_resources != 2) {
|
||||
dev_err(&pdev->dev, "invalid num_resources: %i\n",
|
||||
pdev->num_resources);
|
||||
|
|
@ -655,16 +919,27 @@ s1d13xxxfb_probe(struct platform_device *pdev)
|
|||
|
||||
info->fix = s1d13xxxfb_fix;
|
||||
info->fix.mmio_start = pdev->resource[1].start;
|
||||
info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1;
|
||||
info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1;
|
||||
info->fix.smem_start = pdev->resource[0].start;
|
||||
info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1;
|
||||
info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1;
|
||||
|
||||
printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
|
||||
default_par->regs, info->fix.smem_len / 1024, info->screen_base);
|
||||
|
||||
info->par = default_par;
|
||||
info->fbops = &s1d13xxxfb_fbops;
|
||||
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
|
||||
info->fbops = &s1d13xxxfb_fbops;
|
||||
|
||||
switch(prod_id) {
|
||||
case S1D13506_PROD_ID: /* activate acceleration */
|
||||
s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill;
|
||||
s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea;
|
||||
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
|
||||
FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* perform "manual" chip initialization, if needed */
|
||||
if (pdata && pdata->initregs)
|
||||
|
|
|
|||
|
|
@ -358,9 +358,16 @@ static int s3c_fb_set_par(struct fb_info *info)
|
|||
writel(data, regs + VIDOSD_B(win_no));
|
||||
|
||||
data = var->xres * var->yres;
|
||||
|
||||
u32 osdc_data = 0;
|
||||
|
||||
osdc_data = VIDISD14C_ALPHA1_R(0xf) |
|
||||
VIDISD14C_ALPHA1_G(0xf) |
|
||||
VIDISD14C_ALPHA1_B(0xf);
|
||||
|
||||
if (s3c_fb_has_osd_d(win_no)) {
|
||||
writel(data, regs + VIDOSD_D(win_no));
|
||||
writel(0, regs + VIDOSD_C(win_no));
|
||||
writel(osdc_data, regs + VIDOSD_C(win_no));
|
||||
} else
|
||||
writel(data, regs + VIDOSD_C(win_no));
|
||||
|
||||
|
|
@ -409,8 +416,12 @@ static int s3c_fb_set_par(struct fb_info *info)
|
|||
data |= WINCON1_BPPMODE_19BPP_A1666;
|
||||
else
|
||||
data |= WINCON1_BPPMODE_18BPP_666;
|
||||
} else if (var->transp.length != 0)
|
||||
data |= WINCON1_BPPMODE_25BPP_A1888;
|
||||
} else if (var->transp.length == 1)
|
||||
data |= WINCON1_BPPMODE_25BPP_A1888
|
||||
| WINCON1_BLD_PIX;
|
||||
else if (var->transp.length == 4)
|
||||
data |= WINCON1_BPPMODE_28BPP_A4888
|
||||
| WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
|
||||
else
|
||||
data |= WINCON0_BPPMODE_24BPP_888;
|
||||
|
||||
|
|
@ -418,6 +429,20 @@ static int s3c_fb_set_par(struct fb_info *info)
|
|||
break;
|
||||
}
|
||||
|
||||
/* It has no color key control register for window0 */
|
||||
if (win_no > 0) {
|
||||
u32 keycon0_data = 0, keycon1_data = 0;
|
||||
|
||||
keycon0_data = ~(WxKEYCON0_KEYBL_EN |
|
||||
WxKEYCON0_KEYEN_F |
|
||||
WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
|
||||
|
||||
keycon1_data = WxKEYCON1_COLVAL(0xffffff);
|
||||
|
||||
writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
|
||||
writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
|
||||
}
|
||||
|
||||
writel(data, regs + WINCON(win_no));
|
||||
writel(0x0, regs + WINxMAP(win_no));
|
||||
|
||||
|
|
@ -700,9 +725,12 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
|
|||
*/
|
||||
static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
|
||||
{
|
||||
fb_dealloc_cmap(&win->fbinfo->cmap);
|
||||
unregister_framebuffer(win->fbinfo);
|
||||
s3c_fb_free_memory(sfb, win);
|
||||
if (win->fbinfo) {
|
||||
unregister_framebuffer(win->fbinfo);
|
||||
fb_dealloc_cmap(&win->fbinfo->cmap);
|
||||
s3c_fb_free_memory(sfb, win);
|
||||
framebuffer_release(win->fbinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -753,7 +781,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
|
|||
ret = s3c_fb_alloc_memory(sfb, win);
|
||||
if (ret) {
|
||||
dev_err(sfb->dev, "failed to allocate display memory\n");
|
||||
goto err_framebuffer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 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,
|
|||
ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
|
||||
if (ret < 0) {
|
||||
dev_err(sfb->dev, "check_var failed on initial video params\n");
|
||||
goto err_alloc_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* create initial colour map */
|
||||
|
|
@ -796,20 +824,13 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
|
|||
ret = register_framebuffer(fbinfo);
|
||||
if (ret < 0) {
|
||||
dev_err(sfb->dev, "failed to register framebuffer\n");
|
||||
goto err_alloc_mem;
|
||||
return ret;
|
||||
}
|
||||
|
||||
*res = win;
|
||||
dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
|
||||
|
||||
return 0;
|
||||
|
||||
err_alloc_mem:
|
||||
s3c_fb_free_memory(sfb, win);
|
||||
|
||||
err_framebuffer:
|
||||
unregister_framebuffer(fbinfo);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/div64.h>
|
||||
|
|
@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info)
|
|||
static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
|
||||
unsigned long pixclk)
|
||||
{
|
||||
unsigned long clk = clk_get_rate(fbi->clk);
|
||||
unsigned long clk = fbi->clk_rate;
|
||||
unsigned long long div;
|
||||
|
||||
/* pixclk is in picoseconds, our clock is in Hz
|
||||
|
|
@ -758,6 +759,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
|
||||
static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long val, void *data)
|
||||
{
|
||||
struct cpufreq_freqs *freqs = data;
|
||||
struct s3c2410fb_info *info;
|
||||
struct fb_info *fbinfo;
|
||||
long delta_f;
|
||||
|
||||
info = container_of(nb, struct s3c2410fb_info, freq_transition);
|
||||
fbinfo = platform_get_drvdata(to_platform_device(info->dev));
|
||||
|
||||
/* work out change, <0 for speed-up */
|
||||
delta_f = info->clk_rate - clk_get_rate(info->clk);
|
||||
|
||||
if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
|
||||
(val == CPUFREQ_PRECHANGE && delta_f < 0)) {
|
||||
info->clk_rate = clk_get_rate(info->clk);
|
||||
s3c2410fb_activate_var(fbinfo);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
|
||||
{
|
||||
info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
|
||||
|
||||
return cpufreq_register_notifier(&info->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
|
||||
{
|
||||
cpufreq_unregister_notifier(&info->freq_transition,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static char driver_name[] = "s3c2410fb";
|
||||
|
||||
static int __init s3c24xxfb_probe(struct platform_device *pdev,
|
||||
|
|
@ -875,6 +927,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
|
|||
|
||||
msleep(1);
|
||||
|
||||
info->clk_rate = clk_get_rate(info->clk);
|
||||
|
||||
/* find maximum required memory size for display */
|
||||
for (i = 0; i < mach_info->num_displays; i++) {
|
||||
unsigned long smem_len = mach_info->displays[i].xres;
|
||||
|
|
@ -904,11 +958,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
|
|||
|
||||
s3c2410fb_check_var(&fbinfo->var, fbinfo);
|
||||
|
||||
ret = s3c2410fb_cpufreq_register(info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to register cpufreq\n");
|
||||
goto free_video_memory;
|
||||
}
|
||||
|
||||
ret = register_framebuffer(fbinfo);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "Failed to register framebuffer device: %d\n",
|
||||
ret);
|
||||
goto free_video_memory;
|
||||
goto free_cpufreq;
|
||||
}
|
||||
|
||||
/* create device files */
|
||||
|
|
@ -922,6 +982,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
|
|||
|
||||
return 0;
|
||||
|
||||
free_cpufreq:
|
||||
s3c2410fb_cpufreq_deregister(info);
|
||||
free_video_memory:
|
||||
s3c2410fb_unmap_video_memory(fbinfo);
|
||||
release_clock:
|
||||
|
|
@ -961,6 +1023,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
|
|||
int irq;
|
||||
|
||||
unregister_framebuffer(fbinfo);
|
||||
s3c2410fb_cpufreq_deregister(info);
|
||||
|
||||
s3c2410fb_lcd_enable(info, 0);
|
||||
msleep(1);
|
||||
|
|
|
|||
|
|
@ -29,8 +29,13 @@ struct s3c2410fb_info {
|
|||
enum s3c_drv_type drv_type;
|
||||
struct s3c2410fb_hw regs;
|
||||
|
||||
unsigned long clk_rate;
|
||||
unsigned int palette_ready;
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
struct notifier_block freq_transition;
|
||||
#endif
|
||||
|
||||
/* keep these registers in case we need to re-write palette */
|
||||
u32 palette_buffer[256];
|
||||
u32 pseudo_pal[16];
|
||||
|
|
|
|||
|
|
@ -5928,7 +5928,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if(pci_enable_device(pdev)) {
|
||||
if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(sis_fb_info);
|
||||
framebuffer_release(sis_fb_info);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
|
@ -6134,7 +6134,7 @@ error_3: vfree(ivideo->bios_abase);
|
|||
pci_set_drvdata(pdev, NULL);
|
||||
if(!ivideo->sisvga_enabled)
|
||||
pci_disable_device(pdev);
|
||||
kfree(sis_fb_info);
|
||||
framebuffer_release(sis_fb_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1380,7 +1380,7 @@ stifb_cleanup(void)
|
|||
if (info->screen_base)
|
||||
iounmap(info->screen_base);
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
kfree(info);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
sti->info = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,17 +116,16 @@ struct tcx_par {
|
|||
u32 flags;
|
||||
#define TCX_FLAG_BLANKED 0x00000001
|
||||
|
||||
unsigned long physbase;
|
||||
unsigned long which_io;
|
||||
unsigned long fbsize;
|
||||
|
||||
struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES];
|
||||
int lowdepth;
|
||||
};
|
||||
|
||||
/* Reset control plane so that WID is 8-bit plane. */
|
||||
static void __tcx_set_control_plane(struct tcx_par *par)
|
||||
static void __tcx_set_control_plane(struct fb_info *info)
|
||||
{
|
||||
struct tcx_par *par = info->par;
|
||||
u32 __iomem *p, *pend;
|
||||
|
||||
if (par->lowdepth)
|
||||
|
|
@ -135,7 +134,7 @@ static void __tcx_set_control_plane(struct tcx_par *par)
|
|||
p = par->cplane;
|
||||
if (p == NULL)
|
||||
return;
|
||||
for (pend = p + par->fbsize; p < pend; p++) {
|
||||
for (pend = p + info->fix.smem_len; p < pend; p++) {
|
||||
u32 tmp = sbus_readl(p);
|
||||
|
||||
tmp &= 0xffffff;
|
||||
|
|
@ -149,7 +148,7 @@ static void tcx_reset(struct fb_info *info)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&par->lock, flags);
|
||||
__tcx_set_control_plane(par);
|
||||
__tcx_set_control_plane(info);
|
||||
spin_unlock_irqrestore(&par->lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -304,7 +303,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
|
|||
struct tcx_par *par = (struct tcx_par *)info->par;
|
||||
|
||||
return sbusfb_mmap_helper(par->mmap_map,
|
||||
par->physbase, par->fbsize,
|
||||
info->fix.smem_start, info->fix.smem_len,
|
||||
par->which_io, vma);
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +315,7 @@ static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
|
|||
return sbusfb_ioctl_helper(cmd, arg, info,
|
||||
FBTYPE_TCXCOLOR,
|
||||
(par->lowdepth ? 8 : 24),
|
||||
par->fbsize);
|
||||
info->fix.smem_len);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -358,10 +357,10 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
|
|||
par->bt, sizeof(struct bt_regs));
|
||||
if (par->cplane)
|
||||
of_iounmap(&op->resource[4],
|
||||
par->cplane, par->fbsize * sizeof(u32));
|
||||
par->cplane, info->fix.smem_len * sizeof(u32));
|
||||
if (info->screen_base)
|
||||
of_iounmap(&op->resource[0],
|
||||
info->screen_base, par->fbsize);
|
||||
info->screen_base, info->fix.smem_len);
|
||||
}
|
||||
|
||||
static int __devinit tcx_probe(struct of_device *op,
|
||||
|
|
@ -391,7 +390,7 @@ static int __devinit tcx_probe(struct of_device *op,
|
|||
|
||||
linebytes = of_getintprop_default(dp, "linebytes",
|
||||
info->var.xres);
|
||||
par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
|
||||
info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
|
||||
|
||||
par->tec = of_ioremap(&op->resource[7], 0,
|
||||
sizeof(struct tcx_tec), "tcx tec");
|
||||
|
|
@ -400,7 +399,7 @@ static int __devinit tcx_probe(struct of_device *op,
|
|||
par->bt = of_ioremap(&op->resource[8], 0,
|
||||
sizeof(struct bt_regs), "tcx dac");
|
||||
info->screen_base = of_ioremap(&op->resource[0], 0,
|
||||
par->fbsize, "tcx ram");
|
||||
info->fix.smem_len, "tcx ram");
|
||||
if (!par->tec || !par->thc ||
|
||||
!par->bt || !info->screen_base)
|
||||
goto out_unmap_regs;
|
||||
|
|
@ -408,7 +407,7 @@ static int __devinit tcx_probe(struct of_device *op,
|
|||
memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map));
|
||||
if (!par->lowdepth) {
|
||||
par->cplane = of_ioremap(&op->resource[4], 0,
|
||||
par->fbsize * sizeof(u32),
|
||||
info->fix.smem_len * sizeof(u32),
|
||||
"tcx cplane");
|
||||
if (!par->cplane)
|
||||
goto out_unmap_regs;
|
||||
|
|
@ -419,7 +418,7 @@ static int __devinit tcx_probe(struct of_device *op,
|
|||
par->mmap_map[6].size = SBUS_MMAP_EMPTY;
|
||||
}
|
||||
|
||||
par->physbase = op->resource[0].start;
|
||||
info->fix.smem_start = op->resource[0].start;
|
||||
par->which_io = op->resource[0].flags & IORESOURCE_BITS;
|
||||
|
||||
for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
|
||||
|
|
@ -473,7 +472,7 @@ static int __devinit tcx_probe(struct of_device *op,
|
|||
printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n",
|
||||
dp->full_name,
|
||||
par->which_io,
|
||||
par->physbase,
|
||||
info->fix.smem_start,
|
||||
par->lowdepth ? "8-bit only" : "24-bit depth");
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -174,8 +174,17 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
|
|||
return err;
|
||||
}
|
||||
|
||||
static void vesafb_destroy(struct fb_info *info)
|
||||
{
|
||||
if (info->screen_base)
|
||||
iounmap(info->screen_base);
|
||||
release_mem_region(info->aperture_base, info->aperture_size);
|
||||
framebuffer_release(info);
|
||||
}
|
||||
|
||||
static struct fb_ops vesafb_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.fb_destroy = vesafb_destroy,
|
||||
.fb_setcolreg = vesafb_setcolreg,
|
||||
.fb_pan_display = vesafb_pan_display,
|
||||
.fb_fillrect = cfb_fillrect,
|
||||
|
|
@ -286,6 +295,10 @@ static int __init vesafb_probe(struct platform_device *dev)
|
|||
info->pseudo_palette = info->par;
|
||||
info->par = NULL;
|
||||
|
||||
/* set vesafb aperture size for generic probing */
|
||||
info->aperture_base = screen_info.lfb_base;
|
||||
info->aperture_size = size_total;
|
||||
|
||||
info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
|
||||
if (!info->screen_base) {
|
||||
printk(KERN_ERR
|
||||
|
|
@ -437,7 +450,7 @@ static int __init vesafb_probe(struct platform_device *dev)
|
|||
info->fbops = &vesafb_ops;
|
||||
info->var = vesafb_defined;
|
||||
info->fix = vesafb_fix;
|
||||
info->flags = FBINFO_FLAG_DEFAULT |
|
||||
info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
|
||||
(ypan ? FBINFO_HWACCEL_YPAN : 0);
|
||||
|
||||
if (!ypan)
|
||||
|
|
|
|||
20
drivers/vlynq/Kconfig
Normal file
20
drivers/vlynq/Kconfig
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
menu "TI VLYNQ"
|
||||
|
||||
config VLYNQ
|
||||
bool "TI VLYNQ bus support"
|
||||
depends on AR7 && EXPERIMENTAL
|
||||
help
|
||||
Support for Texas Instruments(R) VLYNQ bus.
|
||||
The VLYNQ bus is a high-speed, serial and packetized
|
||||
data bus which allows external peripherals of a SoC
|
||||
to appear into the system's main memory.
|
||||
|
||||
If unsure, say N
|
||||
|
||||
config VLYNQ_DEBUG
|
||||
bool "VLYNQ bus debug"
|
||||
depends on VLYNQ && KERNEL_DEBUG
|
||||
help
|
||||
Turn on VLYNQ bus debugging.
|
||||
|
||||
endmenu
|
||||
5
drivers/vlynq/Makefile
Normal file
5
drivers/vlynq/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for kernel vlynq drivers
|
||||
#
|
||||
|
||||
obj-$(CONFIG_VLYNQ) += vlynq.o
|
||||
814
drivers/vlynq/vlynq.c
Normal file
814
drivers/vlynq/vlynq.c
Normal file
|
|
@ -0,0 +1,814 @@
|
|||
/*
|
||||
* Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Parts of the VLYNQ specification can be found here:
|
||||
* http://www.ti.com/litv/pdf/sprue36a
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <linux/vlynq.h>
|
||||
|
||||
#define VLYNQ_CTRL_PM_ENABLE 0x80000000
|
||||
#define VLYNQ_CTRL_CLOCK_INT 0x00008000
|
||||
#define VLYNQ_CTRL_CLOCK_DIV(x) (((x) & 7) << 16)
|
||||
#define VLYNQ_CTRL_INT_LOCAL 0x00004000
|
||||
#define VLYNQ_CTRL_INT_ENABLE 0x00002000
|
||||
#define VLYNQ_CTRL_INT_VECTOR(x) (((x) & 0x1f) << 8)
|
||||
#define VLYNQ_CTRL_INT2CFG 0x00000080
|
||||
#define VLYNQ_CTRL_RESET 0x00000001
|
||||
|
||||
#define VLYNQ_CTRL_CLOCK_MASK (0x7 << 16)
|
||||
|
||||
#define VLYNQ_INT_OFFSET 0x00000014
|
||||
#define VLYNQ_REMOTE_OFFSET 0x00000080
|
||||
|
||||
#define VLYNQ_STATUS_LINK 0x00000001
|
||||
#define VLYNQ_STATUS_LERROR 0x00000080
|
||||
#define VLYNQ_STATUS_RERROR 0x00000100
|
||||
|
||||
#define VINT_ENABLE 0x00000100
|
||||
#define VINT_TYPE_EDGE 0x00000080
|
||||
#define VINT_LEVEL_LOW 0x00000040
|
||||
#define VINT_VECTOR(x) ((x) & 0x1f)
|
||||
#define VINT_OFFSET(irq) (8 * ((irq) % 4))
|
||||
|
||||
#define VLYNQ_AUTONEGO_V2 0x00010000
|
||||
|
||||
struct vlynq_regs {
|
||||
u32 revision;
|
||||
u32 control;
|
||||
u32 status;
|
||||
u32 int_prio;
|
||||
u32 int_status;
|
||||
u32 int_pending;
|
||||
u32 int_ptr;
|
||||
u32 tx_offset;
|
||||
struct vlynq_mapping rx_mapping[4];
|
||||
u32 chip;
|
||||
u32 autonego;
|
||||
u32 unused[6];
|
||||
u32 int_device[8];
|
||||
};
|
||||
|
||||
#ifdef VLYNQ_DEBUG
|
||||
static void vlynq_dump_regs(struct vlynq_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n",
|
||||
dev->local, dev->remote);
|
||||
for (i = 0; i < 32; i++) {
|
||||
printk(KERN_DEBUG "VLYNQ: local %d: %08x\n",
|
||||
i + 1, ((u32 *)dev->local)[i]);
|
||||
printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n",
|
||||
i + 1, ((u32 *)dev->remote)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void vlynq_dump_mem(u32 *base, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (count + 3) / 4; i++) {
|
||||
if (i % 4 == 0)
|
||||
printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4);
|
||||
printk(KERN_DEBUG " 0x%08x", *(base + i));
|
||||
}
|
||||
printk(KERN_DEBUG "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check the VLYNQ link status with a given device */
|
||||
static int vlynq_linked(struct vlynq_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 100; i++)
|
||||
if (readl(&dev->local->status) & VLYNQ_STATUS_LINK)
|
||||
return 1;
|
||||
else
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlynq_reset(struct vlynq_device *dev)
|
||||
{
|
||||
writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
|
||||
&dev->local->control);
|
||||
|
||||
/* Wait for the devices to finish resetting */
|
||||
msleep(5);
|
||||
|
||||
/* Remove reset bit */
|
||||
writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
|
||||
&dev->local->control);
|
||||
|
||||
/* Give some time for the devices to settle */
|
||||
msleep(5);
|
||||
}
|
||||
|
||||
static void vlynq_irq_unmask(unsigned int irq)
|
||||
{
|
||||
u32 val;
|
||||
struct vlynq_device *dev = get_irq_chip_data(irq);
|
||||
int virq;
|
||||
|
||||
BUG_ON(!dev);
|
||||
virq = irq - dev->irq_start;
|
||||
val = readl(&dev->remote->int_device[virq >> 2]);
|
||||
val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq);
|
||||
writel(val, &dev->remote->int_device[virq >> 2]);
|
||||
}
|
||||
|
||||
static void vlynq_irq_mask(unsigned int irq)
|
||||
{
|
||||
u32 val;
|
||||
struct vlynq_device *dev = get_irq_chip_data(irq);
|
||||
int virq;
|
||||
|
||||
BUG_ON(!dev);
|
||||
virq = irq - dev->irq_start;
|
||||
val = readl(&dev->remote->int_device[virq >> 2]);
|
||||
val &= ~(VINT_ENABLE << VINT_OFFSET(virq));
|
||||
writel(val, &dev->remote->int_device[virq >> 2]);
|
||||
}
|
||||
|
||||
static int vlynq_irq_type(unsigned int irq, unsigned int flow_type)
|
||||
{
|
||||
u32 val;
|
||||
struct vlynq_device *dev = get_irq_chip_data(irq);
|
||||
int virq;
|
||||
|
||||
BUG_ON(!dev);
|
||||
virq = irq - dev->irq_start;
|
||||
val = readl(&dev->remote->int_device[virq >> 2]);
|
||||
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
val |= VINT_TYPE_EDGE << VINT_OFFSET(virq);
|
||||
val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
|
||||
val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
|
||||
val |= VINT_LEVEL_LOW << VINT_OFFSET(virq);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
writel(val, &dev->remote->int_device[virq >> 2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlynq_local_ack(unsigned int irq)
|
||||
{
|
||||
struct vlynq_device *dev = get_irq_chip_data(irq);
|
||||
|
||||
u32 status = readl(&dev->local->status);
|
||||
|
||||
pr_debug("%s: local status: 0x%08x\n",
|
||||
dev_name(&dev->dev), status);
|
||||
writel(status, &dev->local->status);
|
||||
}
|
||||
|
||||
static void vlynq_remote_ack(unsigned int irq)
|
||||
{
|
||||
struct vlynq_device *dev = get_irq_chip_data(irq);
|
||||
|
||||
u32 status = readl(&dev->remote->status);
|
||||
|
||||
pr_debug("%s: remote status: 0x%08x\n",
|
||||
dev_name(&dev->dev), status);
|
||||
writel(status, &dev->remote->status);
|
||||
}
|
||||
|
||||
static irqreturn_t vlynq_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct vlynq_device *dev = dev_id;
|
||||
u32 status;
|
||||
int virq = 0;
|
||||
|
||||
status = readl(&dev->local->int_status);
|
||||
writel(status, &dev->local->int_status);
|
||||
|
||||
if (unlikely(!status))
|
||||
spurious_interrupt();
|
||||
|
||||
while (status) {
|
||||
if (status & 1)
|
||||
do_IRQ(dev->irq_start + virq);
|
||||
status >>= 1;
|
||||
virq++;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct irq_chip vlynq_irq_chip = {
|
||||
.name = "vlynq",
|
||||
.unmask = vlynq_irq_unmask,
|
||||
.mask = vlynq_irq_mask,
|
||||
.set_type = vlynq_irq_type,
|
||||
};
|
||||
|
||||
static struct irq_chip vlynq_local_chip = {
|
||||
.name = "vlynq local error",
|
||||
.unmask = vlynq_irq_unmask,
|
||||
.mask = vlynq_irq_mask,
|
||||
.ack = vlynq_local_ack,
|
||||
};
|
||||
|
||||
static struct irq_chip vlynq_remote_chip = {
|
||||
.name = "vlynq local error",
|
||||
.unmask = vlynq_irq_unmask,
|
||||
.mask = vlynq_irq_mask,
|
||||
.ack = vlynq_remote_ack,
|
||||
};
|
||||
|
||||
static int vlynq_setup_irq(struct vlynq_device *dev)
|
||||
{
|
||||
u32 val;
|
||||
int i, virq;
|
||||
|
||||
if (dev->local_irq == dev->remote_irq) {
|
||||
printk(KERN_ERR
|
||||
"%s: local vlynq irq should be different from remote\n",
|
||||
dev_name(&dev->dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Clear local and remote error bits */
|
||||
writel(readl(&dev->local->status), &dev->local->status);
|
||||
writel(readl(&dev->remote->status), &dev->remote->status);
|
||||
|
||||
/* Now setup interrupts */
|
||||
val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq);
|
||||
val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL |
|
||||
VLYNQ_CTRL_INT2CFG;
|
||||
val |= readl(&dev->local->control);
|
||||
writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr);
|
||||
writel(val, &dev->local->control);
|
||||
|
||||
val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq);
|
||||
val |= VLYNQ_CTRL_INT_ENABLE;
|
||||
val |= readl(&dev->remote->control);
|
||||
writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr);
|
||||
writel(val, &dev->remote->int_ptr);
|
||||
writel(val, &dev->remote->control);
|
||||
|
||||
for (i = dev->irq_start; i <= dev->irq_end; i++) {
|
||||
virq = i - dev->irq_start;
|
||||
if (virq == dev->local_irq) {
|
||||
set_irq_chip_and_handler(i, &vlynq_local_chip,
|
||||
handle_level_irq);
|
||||
set_irq_chip_data(i, dev);
|
||||
} else if (virq == dev->remote_irq) {
|
||||
set_irq_chip_and_handler(i, &vlynq_remote_chip,
|
||||
handle_level_irq);
|
||||
set_irq_chip_data(i, dev);
|
||||
} else {
|
||||
set_irq_chip_and_handler(i, &vlynq_irq_chip,
|
||||
handle_simple_irq);
|
||||
set_irq_chip_data(i, dev);
|
||||
writel(0, &dev->remote->int_device[virq >> 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) {
|
||||
printk(KERN_ERR "%s: request_irq failed\n",
|
||||
dev_name(&dev->dev));
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vlynq_device_release(struct device *dev)
|
||||
{
|
||||
struct vlynq_device *vdev = to_vlynq_device(dev);
|
||||
kfree(vdev);
|
||||
}
|
||||
|
||||
static int vlynq_device_match(struct device *dev,
|
||||
struct device_driver *drv)
|
||||
{
|
||||
struct vlynq_device *vdev = to_vlynq_device(dev);
|
||||
struct vlynq_driver *vdrv = to_vlynq_driver(drv);
|
||||
struct vlynq_device_id *ids = vdrv->id_table;
|
||||
|
||||
while (ids->id) {
|
||||
if (ids->id == vdev->dev_id) {
|
||||
vdev->divisor = ids->divisor;
|
||||
vlynq_set_drvdata(vdev, ids);
|
||||
printk(KERN_INFO "Driver found for VLYNQ "
|
||||
"device: %08x\n", vdev->dev_id);
|
||||
return 1;
|
||||
}
|
||||
printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver"
|
||||
" for VLYNQ device: %08x\n", ids->id, vdev->dev_id);
|
||||
ids++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vlynq_device_probe(struct device *dev)
|
||||
{
|
||||
struct vlynq_device *vdev = to_vlynq_device(dev);
|
||||
struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
|
||||
struct vlynq_device_id *id = vlynq_get_drvdata(vdev);
|
||||
int result = -ENODEV;
|
||||
|
||||
if (drv->probe)
|
||||
result = drv->probe(vdev, id);
|
||||
if (result)
|
||||
put_device(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int vlynq_device_remove(struct device *dev)
|
||||
{
|
||||
struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
|
||||
|
||||
if (drv->remove)
|
||||
drv->remove(to_vlynq_device(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner)
|
||||
{
|
||||
driver->driver.name = driver->name;
|
||||
driver->driver.bus = &vlynq_bus_type;
|
||||
return driver_register(&driver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(__vlynq_register_driver);
|
||||
|
||||
void vlynq_unregister_driver(struct vlynq_driver *driver)
|
||||
{
|
||||
driver_unregister(&driver->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_unregister_driver);
|
||||
|
||||
/*
|
||||
* A VLYNQ remote device can clock the VLYNQ bus master
|
||||
* using a dedicated clock line. In that case, both the
|
||||
* remove device and the bus master should have the same
|
||||
* serial clock dividers configured. Iterate through the
|
||||
* 8 possible dividers until we actually link with the
|
||||
* device.
|
||||
*/
|
||||
static int __vlynq_try_remote(struct vlynq_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
vlynq_reset(dev);
|
||||
for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
|
||||
i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
|
||||
dev->dev_id ? i++ : i--) {
|
||||
|
||||
if (!vlynq_linked(dev))
|
||||
break;
|
||||
|
||||
writel((readl(&dev->remote->control) &
|
||||
~VLYNQ_CTRL_CLOCK_MASK) |
|
||||
VLYNQ_CTRL_CLOCK_INT |
|
||||
VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
|
||||
&dev->remote->control);
|
||||
writel((readl(&dev->local->control)
|
||||
& ~(VLYNQ_CTRL_CLOCK_INT |
|
||||
VLYNQ_CTRL_CLOCK_MASK)) |
|
||||
VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
|
||||
&dev->local->control);
|
||||
|
||||
if (vlynq_linked(dev)) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: using remote clock divisor %d\n",
|
||||
dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
|
||||
dev->divisor = i;
|
||||
return 0;
|
||||
} else {
|
||||
vlynq_reset(dev);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* A VLYNQ remote device can be clocked by the VLYNQ bus
|
||||
* master using a dedicated clock line. In that case, only
|
||||
* the bus master configures the serial clock divider.
|
||||
* Iterate through the 8 possible dividers until we
|
||||
* actually get a link with the device.
|
||||
*/
|
||||
static int __vlynq_try_local(struct vlynq_device *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
vlynq_reset(dev);
|
||||
|
||||
for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
|
||||
i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
|
||||
dev->dev_id ? i++ : i--) {
|
||||
|
||||
writel((readl(&dev->local->control) &
|
||||
~VLYNQ_CTRL_CLOCK_MASK) |
|
||||
VLYNQ_CTRL_CLOCK_INT |
|
||||
VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
|
||||
&dev->local->control);
|
||||
|
||||
if (vlynq_linked(dev)) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: using local clock divisor %d\n",
|
||||
dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
|
||||
dev->divisor = i;
|
||||
return 0;
|
||||
} else {
|
||||
vlynq_reset(dev);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* When using external clocking method, serial clock
|
||||
* is supplied by an external oscillator, therefore we
|
||||
* should mask the local clock bit in the clock control
|
||||
* register for both the bus master and the remote device.
|
||||
*/
|
||||
static int __vlynq_try_external(struct vlynq_device *dev)
|
||||
{
|
||||
vlynq_reset(dev);
|
||||
if (!vlynq_linked(dev))
|
||||
return -ENODEV;
|
||||
|
||||
writel((readl(&dev->remote->control) &
|
||||
~VLYNQ_CTRL_CLOCK_INT),
|
||||
&dev->remote->control);
|
||||
|
||||
writel((readl(&dev->local->control) &
|
||||
~VLYNQ_CTRL_CLOCK_INT),
|
||||
&dev->local->control);
|
||||
|
||||
if (vlynq_linked(dev)) {
|
||||
printk(KERN_DEBUG "%s: using external clock\n",
|
||||
dev_name(&dev->dev));
|
||||
dev->divisor = vlynq_div_external;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int __vlynq_enable_device(struct vlynq_device *dev)
|
||||
{
|
||||
int result;
|
||||
struct plat_vlynq_ops *ops = dev->dev.platform_data;
|
||||
|
||||
result = ops->on(dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
switch (dev->divisor) {
|
||||
case vlynq_div_external:
|
||||
case vlynq_div_auto:
|
||||
/* When the device is brought from reset it should have clock
|
||||
* generation negotiated by hardware.
|
||||
* Check which device is generating clocks and perform setup
|
||||
* accordingly */
|
||||
if (vlynq_linked(dev) && readl(&dev->remote->control) &
|
||||
VLYNQ_CTRL_CLOCK_INT) {
|
||||
if (!__vlynq_try_remote(dev) ||
|
||||
!__vlynq_try_local(dev) ||
|
||||
!__vlynq_try_external(dev))
|
||||
return 0;
|
||||
} else {
|
||||
if (!__vlynq_try_external(dev) ||
|
||||
!__vlynq_try_local(dev) ||
|
||||
!__vlynq_try_remote(dev))
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case vlynq_ldiv1:
|
||||
case vlynq_ldiv2:
|
||||
case vlynq_ldiv3:
|
||||
case vlynq_ldiv4:
|
||||
case vlynq_ldiv5:
|
||||
case vlynq_ldiv6:
|
||||
case vlynq_ldiv7:
|
||||
case vlynq_ldiv8:
|
||||
writel(VLYNQ_CTRL_CLOCK_INT |
|
||||
VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
|
||||
vlynq_ldiv1), &dev->local->control);
|
||||
writel(0, &dev->remote->control);
|
||||
if (vlynq_linked(dev)) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: using local clock divisor %d\n",
|
||||
dev_name(&dev->dev),
|
||||
dev->divisor - vlynq_ldiv1 + 1);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case vlynq_rdiv1:
|
||||
case vlynq_rdiv2:
|
||||
case vlynq_rdiv3:
|
||||
case vlynq_rdiv4:
|
||||
case vlynq_rdiv5:
|
||||
case vlynq_rdiv6:
|
||||
case vlynq_rdiv7:
|
||||
case vlynq_rdiv8:
|
||||
writel(0, &dev->local->control);
|
||||
writel(VLYNQ_CTRL_CLOCK_INT |
|
||||
VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
|
||||
vlynq_rdiv1), &dev->remote->control);
|
||||
if (vlynq_linked(dev)) {
|
||||
printk(KERN_DEBUG
|
||||
"%s: using remote clock divisor %d\n",
|
||||
dev_name(&dev->dev),
|
||||
dev->divisor - vlynq_rdiv1 + 1);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ops->off(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int vlynq_enable_device(struct vlynq_device *dev)
|
||||
{
|
||||
struct plat_vlynq_ops *ops = dev->dev.platform_data;
|
||||
int result = -ENODEV;
|
||||
|
||||
result = __vlynq_enable_device(dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = vlynq_setup_irq(dev);
|
||||
if (result)
|
||||
ops->off(dev);
|
||||
|
||||
dev->enabled = !result;
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_enable_device);
|
||||
|
||||
|
||||
void vlynq_disable_device(struct vlynq_device *dev)
|
||||
{
|
||||
struct plat_vlynq_ops *ops = dev->dev.platform_data;
|
||||
|
||||
dev->enabled = 0;
|
||||
free_irq(dev->irq, dev);
|
||||
ops->off(dev);
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_disable_device);
|
||||
|
||||
int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
|
||||
struct vlynq_mapping *mapping)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!dev->enabled)
|
||||
return -ENXIO;
|
||||
|
||||
writel(tx_offset, &dev->local->tx_offset);
|
||||
for (i = 0; i < 4; i++) {
|
||||
writel(mapping[i].offset, &dev->local->rx_mapping[i].offset);
|
||||
writel(mapping[i].size, &dev->local->rx_mapping[i].size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_set_local_mapping);
|
||||
|
||||
int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
|
||||
struct vlynq_mapping *mapping)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!dev->enabled)
|
||||
return -ENXIO;
|
||||
|
||||
writel(tx_offset, &dev->remote->tx_offset);
|
||||
for (i = 0; i < 4; i++) {
|
||||
writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset);
|
||||
writel(mapping[i].size, &dev->remote->rx_mapping[i].size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_set_remote_mapping);
|
||||
|
||||
int vlynq_set_local_irq(struct vlynq_device *dev, int virq)
|
||||
{
|
||||
int irq = dev->irq_start + virq;
|
||||
if (dev->enabled)
|
||||
return -EBUSY;
|
||||
|
||||
if ((irq < dev->irq_start) || (irq > dev->irq_end))
|
||||
return -EINVAL;
|
||||
|
||||
if (virq == dev->remote_irq)
|
||||
return -EINVAL;
|
||||
|
||||
dev->local_irq = virq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_set_local_irq);
|
||||
|
||||
int vlynq_set_remote_irq(struct vlynq_device *dev, int virq)
|
||||
{
|
||||
int irq = dev->irq_start + virq;
|
||||
if (dev->enabled)
|
||||
return -EBUSY;
|
||||
|
||||
if ((irq < dev->irq_start) || (irq > dev->irq_end))
|
||||
return -EINVAL;
|
||||
|
||||
if (virq == dev->local_irq)
|
||||
return -EINVAL;
|
||||
|
||||
dev->remote_irq = virq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(vlynq_set_remote_irq);
|
||||
|
||||
static int vlynq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct vlynq_device *dev;
|
||||
struct resource *regs_res, *mem_res, *irq_res;
|
||||
int len, result;
|
||||
|
||||
regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||
if (!regs_res)
|
||||
return -ENODEV;
|
||||
|
||||
mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
|
||||
if (!mem_res)
|
||||
return -ENODEV;
|
||||
|
||||
irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq");
|
||||
if (!irq_res)
|
||||
return -ENODEV;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR
|
||||
"vlynq: failed to allocate device structure\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->id = pdev->id;
|
||||
dev->dev.bus = &vlynq_bus_type;
|
||||
dev->dev.parent = &pdev->dev;
|
||||
dev_set_name(&dev->dev, "vlynq%d", dev->id);
|
||||
dev->dev.platform_data = pdev->dev.platform_data;
|
||||
dev->dev.release = vlynq_device_release;
|
||||
|
||||
dev->regs_start = regs_res->start;
|
||||
dev->regs_end = regs_res->end;
|
||||
dev->mem_start = mem_res->start;
|
||||
dev->mem_end = mem_res->end;
|
||||
|
||||
len = regs_res->end - regs_res->start;
|
||||
if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) {
|
||||
printk(KERN_ERR "%s: Can't request vlynq registers\n",
|
||||
dev_name(&dev->dev));
|
||||
result = -ENXIO;
|
||||
goto fail_request;
|
||||
}
|
||||
|
||||
dev->local = ioremap(regs_res->start, len);
|
||||
if (!dev->local) {
|
||||
printk(KERN_ERR "%s: Can't remap vlynq registers\n",
|
||||
dev_name(&dev->dev));
|
||||
result = -ENXIO;
|
||||
goto fail_remap;
|
||||
}
|
||||
|
||||
dev->remote = (struct vlynq_regs *)((void *)dev->local +
|
||||
VLYNQ_REMOTE_OFFSET);
|
||||
|
||||
dev->irq = platform_get_irq_byname(pdev, "irq");
|
||||
dev->irq_start = irq_res->start;
|
||||
dev->irq_end = irq_res->end;
|
||||
dev->local_irq = dev->irq_end - dev->irq_start;
|
||||
dev->remote_irq = dev->local_irq - 1;
|
||||
|
||||
if (device_register(&dev->dev))
|
||||
goto fail_register;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
|
||||
dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
|
||||
(void *)dev->mem_start);
|
||||
|
||||
dev->dev_id = 0;
|
||||
dev->divisor = vlynq_div_auto;
|
||||
result = __vlynq_enable_device(dev);
|
||||
if (result == 0) {
|
||||
dev->dev_id = readl(&dev->remote->chip);
|
||||
((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
|
||||
}
|
||||
if (dev->dev_id)
|
||||
printk(KERN_INFO "Found a VLYNQ device: %08x\n", dev->dev_id);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_register:
|
||||
iounmap(dev->local);
|
||||
fail_remap:
|
||||
fail_request:
|
||||
release_mem_region(regs_res->start, len);
|
||||
kfree(dev);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int vlynq_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vlynq_device *dev = platform_get_drvdata(pdev);
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
iounmap(dev->local);
|
||||
release_mem_region(dev->regs_start, dev->regs_end - dev->regs_start);
|
||||
|
||||
kfree(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vlynq_platform_driver = {
|
||||
.driver.name = "vlynq",
|
||||
.probe = vlynq_probe,
|
||||
.remove = __devexit_p(vlynq_remove),
|
||||
};
|
||||
|
||||
struct bus_type vlynq_bus_type = {
|
||||
.name = "vlynq",
|
||||
.match = vlynq_device_match,
|
||||
.probe = vlynq_device_probe,
|
||||
.remove = vlynq_device_remove,
|
||||
};
|
||||
EXPORT_SYMBOL(vlynq_bus_type);
|
||||
|
||||
static int __devinit vlynq_init(void)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
res = bus_register(&vlynq_bus_type);
|
||||
if (res)
|
||||
goto fail_bus;
|
||||
|
||||
res = platform_driver_register(&vlynq_platform_driver);
|
||||
if (res)
|
||||
goto fail_platform;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_platform:
|
||||
bus_unregister(&vlynq_bus_type);
|
||||
fail_bus:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __devexit vlynq_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&vlynq_platform_driver);
|
||||
bus_unregister(&vlynq_bus_type);
|
||||
}
|
||||
|
||||
module_init(vlynq_init);
|
||||
module_exit(vlynq_exit);
|
||||
Loading…
Reference in a new issue