Commit 2fbc109c authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents 1b8ad82f 93d84590
...@@ -335,6 +335,16 @@ hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 ...@@ -335,6 +335,16 @@ hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0
if [ "$CONFIG_ARCH_SA1100" = "y" -o \ if [ "$CONFIG_ARCH_SA1100" = "y" -o \
"$CONFIG_ARCH_INTEGRATOR" = "y" ]; then "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
else
define_bool CONFIG_CPU_FREQ n
fi
if [ "$CONFIG_CPU_FREQ" = "y" ]; then
define_bool CONFIG_CPU_FREQ_24_API y
define_bool CONFIG_CPU_FREQ_26_API y
else
define_bool CONFIG_CPU_FREQ_24_API n
define_bool CONFIG_CPU_FREQ_26_API n
fi fi
source drivers/pci/Config.in source drivers/pci/Config.in
......
...@@ -95,13 +95,14 @@ static void __init build_tag_list(struct param_struct *params, void *taglist) ...@@ -95,13 +95,14 @@ static void __init build_tag_list(struct param_struct *params, void *taglist)
{ {
struct tag *tag = taglist; struct tag *tag = taglist;
printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
if (params->u1.s.page_size != PAGE_SIZE) { if (params->u1.s.page_size != PAGE_SIZE) {
printk(KERN_WARNING "Warning: bad configuration page, " printk(KERN_WARNING "Warning: bad configuration page, "
"trying to continue\n"); "trying to continue\n");
return; return;
} }
printk(KERN_DEBUG "Converting old-style param struct to taglist\n");
#ifdef CONFIG_ARCH_NETWINDER #ifdef CONFIG_ARCH_NETWINDER
if (params->u1.s.nr_pages != 0x02000 && if (params->u1.s.nr_pages != 0x02000 &&
params->u1.s.nr_pages != 0x04000 && params->u1.s.nr_pages != 0x04000 &&
......
...@@ -569,7 +569,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) ...@@ -569,7 +569,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
* On a shared IRQ the caller must ensure the interrupt is disabled * On a shared IRQ the caller must ensure the interrupt is disabled
* on the card it drives before calling this function. * on the card it drives before calling this function.
* *
* This function may be called from interrupt context. * This function must not be called from interrupt context.
*/ */
void free_irq(unsigned int irq, void *dev_id) void free_irq(unsigned int irq, void *dev_id)
{ {
...@@ -591,15 +591,19 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -591,15 +591,19 @@ void free_irq(unsigned int irq, void *dev_id)
/* Found it - now free it */ /* Found it - now free it */
*p = action->next; *p = action->next;
kfree(action); break;
goto out;
} }
printk(KERN_ERR "Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&irq_controller_lock, flags);
if (!action) {
printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
#ifdef CONFIG_DEBUG_ERRORS #ifdef CONFIG_DEBUG_ERRORS
__backtrace(); __backtrace();
#endif #endif
out: } else {
spin_unlock_irqrestore(&irq_controller_lock, flags); synchronize_irq(irq);
kfree(action);
}
} }
/* Start the interrupt probing. Unlike other architectures, /* Start the interrupt probing. Unlike other architectures,
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
static int __init adsbitsy_init(void) static int __init adsbitsy_init(void)
{ {
...@@ -53,7 +52,7 @@ static int __init adsbitsy_init(void) ...@@ -53,7 +52,7 @@ static int __init adsbitsy_init(void)
/* /*
* Probe for SA1111. * Probe for SA1111.
*/ */
ret = sa1111_init(NULL, 0x18000000, IRQ_GPIO0); ret = sa1111_init(0x18000000, IRQ_GPIO0);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
static int __init badge4_sa1111_init(void) static int __init badge4_sa1111_init(void)
{ {
...@@ -45,7 +44,7 @@ static int __init badge4_sa1111_init(void) ...@@ -45,7 +44,7 @@ static int __init badge4_sa1111_init(void)
/* /*
* Probe for SA1111. * Probe for SA1111.
*/ */
return sa1111_init(NULL, BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111); return sa1111_init(BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111);
} }
static int __init badge4_init(void) static int __init badge4_init(void)
......
...@@ -90,9 +90,7 @@ ...@@ -90,9 +90,7 @@
#include <asm/hardware.h> #include <asm/hardware.h>
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); #include "generic.h"
extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
extern unsigned int sa11x0_getspeed(void);
typedef struct { typedef struct {
int speed; int speed;
...@@ -107,7 +105,7 @@ typedef struct { ...@@ -107,7 +105,7 @@ typedef struct {
static sa1100_dram_regs_t sa1100_dram_settings[] = static sa1100_dram_regs_t sa1100_dram_settings[] =
{ {
/* { mdcnfg, mdcas0, mdcas1, mdcas2 } */ /* clock frequency */ /* speed, mdcnfg, mdcas0, mdcas1, mdcas2 clock frequency */
{ 59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 59.0 MHz */ { 59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 59.0 MHz */
{ 73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 73.7 MHz */ { 73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 73.7 MHz */
{ 88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 88.5 MHz */ { 88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 88.5 MHz */
...@@ -127,28 +125,25 @@ static sa1100_dram_regs_t sa1100_dram_settings[] = ...@@ -127,28 +125,25 @@ static sa1100_dram_regs_t sa1100_dram_settings[] =
{ 0, 0, 0, 0, 0 } /* last entry */ { 0, 0, 0, 0, 0 } /* last entry */
}; };
static void sa1100_update_dram_timings(int current_speed, int new_speed) static void sa1100_update_dram_timings(int current_speed, int new_speed)
{ {
sa1100_dram_regs_t *settings = sa1100_dram_settings; sa1100_dram_regs_t *settings = sa1100_dram_settings;
/* find speed */ /* find speed */
while(settings->speed != 0) { while (settings->speed != 0) {
if(new_speed == settings->speed) if(new_speed == settings->speed)
break; break;
settings++; settings++;
} }
if(settings->speed == 0) { if (settings->speed == 0) {
panic("%s: couldn't find dram setting for speed %d\n", panic("%s: couldn't find dram setting for speed %d\n",
__FUNCTION__, new_speed); __FUNCTION__, new_speed);
} }
/* No risk, no fun: run with interrupts on! */ /* No risk, no fun: run with interrupts on! */
if(new_speed > current_speed) { if (new_speed > current_speed) {
/* We're going FASTER, so first relax the memory /* We're going FASTER, so first relax the memory
* timings before changing the core frequency * timings before changing the core frequency
*/ */
...@@ -181,60 +176,39 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed) ...@@ -181,60 +176,39 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
} }
} }
static void sa1100_setspeed(struct cpufreq_policy *policy)
static int sa1100_dram_notifier(struct notifier_block *nb,
unsigned long val, void *data)
{ {
struct cpufreq_freqs *ci = data; unsigned int cur = sa11x0_getspeed();
struct cpufreq_freqs freqs;
switch(val) {
case CPUFREQ_MINMAX:
cpufreq_updateminmax(data, sa1100_dram_settings->speed, -1);
break;
case CPUFREQ_PRECHANGE: freqs.old = cur;
if(ci->new > ci->cur) freqs.new = policy->max;
sa1100_update_dram_timings(ci->cur, ci->new); freqs.cpu = CPUFREQ_ALL_CPUS;
break;
case CPUFREQ_POSTCHANGE: cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if(ci->new < ci->cur)
sa1100_update_dram_timings(ci->cur, ci->new);
break;
default:
printk(KERN_INFO "%s: ignoring unknown notifier type (%ld)\n",
__FUNCTION__, val);
}
return 0;
}
if (policy->max > cur)
sa1100_update_dram_timings(cur, policy->max);
PPCR = sa11x0_freq_to_ppcr(policy->max);
if (policy->max < cur)
sa1100_update_dram_timings(cur, policy->max);
static struct notifier_block sa1100_dram_block = { cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
.notifier_call = sa1100_dram_notifier,
};
static void sa1100_setspeed(unsigned int cpu, unsigned int khz)
{
PPCR = sa11x0_freq_to_ppcr(khz);
} }
static struct cpufreq_freqs sa1100_freqs = { static struct cpufreq_policy sa1100_policy = {
.min = 59000, .cpu = 0,
.max = 287000, .policy = CPUFREQ_POLICY_POWERSAVE,
.max_cpu_freq = 287000,
}; };
static struct cpufreq_driver sa1100_driver = { static struct cpufreq_driver sa1100_driver = {
.freq = &sa1100_freqs, .verify = sa11x0_verify_speed,
.validate = sa11x0_validatespeed, .setpolicy = sa1100_setspeed,
.setspeed = sa1100_setspeed, .policy = &sa1100_policy,
.sync = 1, .cpu_min_freq = 59000,
}; };
static int __init sa1100_dram_init(void) static int __init sa1100_dram_init(void)
...@@ -242,11 +216,9 @@ static int __init sa1100_dram_init(void) ...@@ -242,11 +216,9 @@ static int __init sa1100_dram_init(void)
int ret = -ENODEV; int ret = -ENODEV;
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) { if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
ret = cpufreq_register_notifier(&sa1100_dram_block); sa1100_driver.cpu_curr_freq[0] =
if (ret) sa1100_policy.min =
return ret; sa1100_policy.max = sa11x0_getspeed();
sa1100_freqs.cur = sa11x0_getspeed();
ret = cpufreq_register(&sa1100_driver); ret = cpufreq_register(&sa1100_driver);
} }
......
...@@ -28,11 +28,9 @@ ...@@ -28,11 +28,9 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#undef DEBUG #include "generic.h"
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); #undef DEBUG
extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
extern unsigned int sa11x0_getspeed(void);
struct sdram_params { struct sdram_params {
u_char rows; /* bits */ u_char rows; /* bits */
...@@ -214,15 +212,16 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) ...@@ -214,15 +212,16 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
* above, we can match for an exact frequency. If we don't find * above, we can match for an exact frequency. If we don't find
* an exact match, we will to set the lowest frequency to be safe. * an exact match, we will to set the lowest frequency to be safe.
*/ */
static void sa1110_setspeed(unsigned int cpu, unsigned int khz) static void sa1110_setspeed(struct cpufreq_policy *policy)
{ {
struct sdram_params *sdram = &sdram_params; struct sdram_params *sdram = &sdram_params;
struct cpufreq_freqs freqs;
struct sdram_info sd; struct sdram_info sd;
unsigned long flags; unsigned long flags;
unsigned int ppcr, unused; unsigned int ppcr, unused;
ppcr = sa11x0_freq_to_ppcr(khz); ppcr = sa11x0_freq_to_ppcr(policy->max);
sdram_calculate_timing(&sd, khz, sdram); sdram_calculate_timing(&sd, policy->max, sdram);
#if 0 #if 0
/* /*
...@@ -230,7 +229,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz) ...@@ -230,7 +229,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
* and errata, but they seem to work. Need to get a storage * and errata, but they seem to work. Need to get a storage
* scope on to the SDRAM signals to work out why. * scope on to the SDRAM signals to work out why.
*/ */
if (khz < 147500) { if (policy->max < 147500) {
sd.mdrefr |= MDREFR_K1DB2; sd.mdrefr |= MDREFR_K1DB2;
sd.mdcas[0] = 0xaaaaaa7f; sd.mdcas[0] = 0xaaaaaa7f;
} else { } else {
...@@ -240,6 +239,13 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz) ...@@ -240,6 +239,13 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
sd.mdcas[1] = 0xaaaaaaaa; sd.mdcas[1] = 0xaaaaaaaa;
sd.mdcas[2] = 0xaaaaaaaa; sd.mdcas[2] = 0xaaaaaaaa;
#endif #endif
freqs.old = sa11x0_getspeed();
freqs.new = policy->max;
freqs.cpu = CPUFREQ_ALL_CPUS;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/* /*
* The clock could be going away for some time. Set the SDRAMs * The clock could be going away for some time. Set the SDRAMs
* to refresh rapidly (every 64 memory clock cycles). To get * to refresh rapidly (every 64 memory clock cycles). To get
...@@ -257,7 +263,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz) ...@@ -257,7 +263,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
* the programming. * the programming.
*/ */
local_irq_save(flags); local_irq_save(flags);
asm("mcr p15, 0, %0, c10, c4" : : "r" (0)); asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
udelay(10); udelay(10);
__asm__ __volatile__(" __asm__ __volatile__("
b 2f b 2f
...@@ -282,19 +288,22 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz) ...@@ -282,19 +288,22 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
/* /*
* Now, return the SDRAM refresh back to normal. * Now, return the SDRAM refresh back to normal.
*/ */
sdram_update_refresh(khz, sdram); sdram_update_refresh(policy->max, sdram);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
} }
static struct cpufreq_freqs sa1110_freqs = { static struct cpufreq_policy sa1110_policy = {
.min = 59000, .cpu = 0,
.max = 287000, .policy = CPUFREQ_POLICY_POWERSAVE,
.max_cpu_freq = 287000,
}; };
static struct cpufreq_driver sa1110_driver = { static struct cpufreq_driver sa1110_driver = {
.freq = &sa1110_freqs, .verify = sa11x0_verify_speed,
.validate = sa11x0_validatespeed, .setpolicy = sa1110_setspeed,
.setspeed = sa1110_setspeed, .policy = &sa1110_policy,
.sync = 1, .cpu_min_freq = 59000,
}; };
static int __init sa1110_clk_init(void) static int __init sa1110_clk_init(void)
...@@ -318,8 +327,11 @@ static int __init sa1110_clk_init(void) ...@@ -318,8 +327,11 @@ static int __init sa1110_clk_init(void)
memcpy(&sdram_params, sdram, sizeof(sdram_params)); memcpy(&sdram_params, sdram, sizeof(sdram_params));
sa1110_freqs.cur = sa11x0_getspeed(); sa1110_driver.cpu_cur_freq[0] =
sa1110_setspeed(0, sa1110_freqs.cur); sa1110_policy.min =
sa1110_policy.max = sa11x0_getspeed();
sa1110_setspeed(&sa1110_policy);
return cpufreq_register(&sa1110_driver); return cpufreq_register(&sa1110_driver);
} }
......
...@@ -55,20 +55,26 @@ unsigned int sa11x0_freq_to_ppcr(unsigned int khz) ...@@ -55,20 +55,26 @@ unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
khz /= 100; khz /= 100;
for (i = NR_FREQS - 1; i > 0; i--) for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--)
if (cclk_frequency_100khz[i] <= khz) if (cclk_frequency_100khz[i] >= khz)
break; break;
return i; return i;
} }
/* /*
* Validate the speed in khz. If we can't generate the precise * Validate the policy. We aren't able to do any fancy in-kernel
* frequency requested, round it down (to be on the safe side). * scaling, so we force min=max, and set the policy to "performance".
* If we can't generate the precise frequency requested, round it up.
*/ */
unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz) void sa11x0_verify_speed(struct cpufreq_policy *policy)
{ {
return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100; if (policy->max > policy->max_cpu_freq)
policy->max = policy->max_cpu_freq;
policy->max = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->max)] * 100;
policy->min = policy->max;
policy->policy = CPUFREQ_POLICY_POWERSAVE;
} }
unsigned int sa11x0_getspeed(void) unsigned int sa11x0_getspeed(void)
......
...@@ -17,3 +17,9 @@ extern void (*sa1100fb_lcd_power)(int on); ...@@ -17,3 +17,9 @@ extern void (*sa1100fb_lcd_power)(int on);
extern void sa1110_mb_enable(void); extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void); extern void sa1110_mb_disable(void);
struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern void sa11x0_verify_speed(struct cpufreq_policy *policy);
extern unsigned int sa11x0_getspeed(void);
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
static int __init graphicsmaster_init(void) static int __init graphicsmaster_init(void)
{ {
...@@ -43,7 +42,7 @@ static int __init graphicsmaster_init(void) ...@@ -43,7 +42,7 @@ static int __init graphicsmaster_init(void)
/* /*
* Probe for SA1111. * Probe for SA1111.
*/ */
ret = sa1111_init(NULL, 0x18000000, ADS_EXT_IRQ(0)); ret = sa1111_init(0x18000000, ADS_EXT_IRQ(0));
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -24,65 +24,171 @@ ...@@ -24,65 +24,171 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/pm.h>
#include <linux/serial_core.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mach/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include <linux/serial_core.h>
#include <asm/arch/h3600.h>
#if defined (CONFIG_SA1100_H3600) || defined (CONFIG_SA1100_H3100)
#include <asm/arch/h3600_gpio.h> #include <asm/arch/h3600_gpio.h>
#endif
#ifdef CONFIG_SA1100_H3800
#include <asm/arch/h3600_asic.h>
#endif
#include "generic.h" #include "generic.h"
struct ipaq_model_ops ipaq_model_ops;
EXPORT_SYMBOL(ipaq_model_ops);
static void msleep(unsigned int msec)
{
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((msec * HZ + 999) / 1000);
}
/* /*
* H3600 has extended, write-only memory-mapped GPIO's * low-level UART features
* H3100 has 1/2 extended, write-only GPIO and 1/2 on
* regular GPIO lines.
* H3800 has memory-mapped GPIO through ASIC1 & 2
*/ */
#define H3600_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT) static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl)
{
if (port->mapbase == _Ser3UTCR0) {
if (mctrl & TIOCM_RTS)
GPCR = GPIO_H3600_COM_RTS;
else
GPSR = GPIO_H3600_COM_RTS;
}
}
static unsigned int h3600_egpio; static u_int h3600_uart_get_mctrl(struct uart_port *port)
{
u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
/************************* H3100 *************************/ if (port->mapbase == _Ser3UTCR0) {
int gplr = GPLR;
/* DCD and CTS bits are inverted in GPLR by RS232 transceiver */
if (gplr & GPIO_H3600_COM_DCD)
ret &= ~TIOCM_CD;
if (gplr & GPIO_H3600_COM_CTS)
ret &= ~TIOCM_CTS;
}
#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON \ return ret;
| GPIO_H3100_GPIO3 \ }
| GPIO_H3100_QMUTE \
| GPIO_H3100_LCD_3V_ON \
| GPIO_H3100_AUD_ON \
| GPIO_H3100_AUD_PWR_ON \
| GPIO_H3100_IR_ON \
| GPIO_H3100_IR_FSEL)
static void h3100_init_egpio( void ) static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
{ {
GPDR |= H3100_DIRECT_EGPIO; if (port->mapbase == _Ser2UTCR0) { /* TODO: REMOVE THIS */
GPCR = H3100_DIRECT_EGPIO; /* Initially all off */ assign_h3600_egpio(IPAQ_EGPIO_IR_ON, !state);
} else if (port->mapbase == _Ser3UTCR0) {
assign_h3600_egpio(IPAQ_EGPIO_RS232_ON, !state);
}
}
/* Older bootldrs put GPIO2-9 in alternate mode on the /*
assumption that they are used for video */ * Enable/Disable wake up events for this serial port.
GAFR &= ~H3100_DIRECT_EGPIO; * Obviously, we only support this on the normal COM port.
*/
static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
{
int err = -EINVAL;
if (port->mapbase == _Ser3UTCR0) {
if (enable)
PWER |= PWER_GPIO23 | PWER_GPIO25; /* DCD and CTS */
else
PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */
err = 0;
}
return err;
}
static struct sa1100_port_fns h3600_port_fns __initdata = {
.set_mctrl = h3600_uart_set_mctrl,
.get_mctrl = h3600_uart_get_mctrl,
.pm = h3600_uart_pm,
.set_wake = h3600_uart_set_wake,
};
/*
* helper for sa1100fb
*/
static void h3xxx_lcd_power(int enable)
{
assign_h3600_egpio(IPAQ_EGPIO_LCD_POWER, enable);
}
static struct map_desc h3600_io_desc[] __initdata = {
/* virtual physical length type */
{ H3600_BANK_2_VIRT, SA1100_CS2_PHYS, 0x02800000, MT_DEVICE }, /* static memory bank 2 CS#2 */
{ H3600_BANK_4_VIRT, SA1100_CS4_PHYS, 0x00800000, MT_DEVICE }, /* static memory bank 4 CS#4 */
{ H3600_EGPIO_VIRT, H3600_EGPIO_PHYS, 0x01000000, MT_DEVICE }, /* EGPIO 0 CS#5 */
};
/*
* Common map_io initialization
*/
static void __init h3xxx_map_io(void)
{
sa1100_map_io();
iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
sa1100_register_uart_fns(&h3600_port_fns);
sa1100_register_uart(0, 3); /* Common serial port */
// sa1100_register_uart(1, 1); /* Microcontroller on 3100/3600 */
/* Ensure those pins are outputs and driving low */
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
/* Configure suspend conditions */
PGSR = 0;
PWER = PWER_GPIO0 | PWER_RTC;
PCFR = PCFR_OPDE;
PSDR = 0;
sa1100fb_lcd_power = h3xxx_lcd_power;
}
h3600_egpio = EGPIO_H3600_RS232_ON; static __inline__ void do_blank(int setp)
H3600_EGPIO = h3600_egpio; {
if (ipaq_model_ops.blank_callback)
ipaq_model_ops.blank_callback(1-setp);
} }
static void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) /************************* H3100 *************************/
#ifdef CONFIG_SA1100_H3100
#define H3100_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT)
static unsigned int h3100_egpio = 0;
static void h3100_control_egpio(enum ipaq_egpio_type x, int setp)
{ {
unsigned int egpio = 0; unsigned int egpio = 0;
long gpio = 0; long gpio = 0;
unsigned long flags; unsigned long flags;
switch (x) { switch (x) {
case IPAQ_EGPIO_LCD_ON: case IPAQ_EGPIO_LCD_POWER:
egpio |= EGPIO_H3600_LCD_ON; egpio |= EGPIO_H3600_LCD_ON;
gpio |= GPIO_H3100_LCD_3V_ON; gpio |= GPIO_H3100_LCD_3V_ON;
do_blank(setp);
break;
case IPAQ_EGPIO_LCD_ENABLE:
break; break;
case IPAQ_EGPIO_CODEC_NRESET: case IPAQ_EGPIO_CODEC_NRESET:
egpio |= EGPIO_H3600_CODEC_NRESET; egpio |= EGPIO_H3600_CODEC_NRESET;
...@@ -120,66 +226,104 @@ static void h3100_control_egpio( enum ipaq_egpio_type x, int setp ) ...@@ -120,66 +226,104 @@ static void h3100_control_egpio( enum ipaq_egpio_type x, int setp )
break; break;
} }
local_irq_save(flags); if (egpio || gpio) {
if ( setp ) { local_irq_save(flags);
h3600_egpio |= egpio; if (setp) {
GPSR = gpio; h3100_egpio |= egpio;
} else { GPSR = gpio;
h3600_egpio &= ~egpio; } else {
GPCR = gpio; h3100_egpio &= ~egpio;
} GPCR = gpio;
H3600_EGPIO = h3600_egpio; }
local_irq_restore(flags); H3100_EGPIO = h3100_egpio;
local_irq_restore(flags);
/*
if ( x != IPAQ_EGPIO_VPP_ON ) {
printk("%s: type=%d (%s) gpio=0x%x (0x%x) egpio=0x%x (0x%x) setp=%d\n",
__FUNCTION__,
x, egpio_names[x], GPLR, gpio, h3600_egpio, egpio, setp );
} }
*/
} }
static unsigned long h3100_read_egpio( void ) static unsigned long h3100_read_egpio(void)
{ {
return h3600_egpio; return h3100_egpio;
}
static int h3100_pm_callback(int req)
{
if (ipaq_model_ops.pm_callback_aux)
return ipaq_model_ops.pm_callback_aux(req);
return 0;
} }
static struct ipaq_model_ops h3100_model_ops __initdata = { static struct ipaq_model_ops h3100_model_ops __initdata = {
model : IPAQ_H3100, .generic_name = "3100",
generic_name : "3100", .control = h3100_control_egpio,
initialize : h3100_init_egpio, .read = h3100_read_egpio,
control : h3100_control_egpio, .pm_callback = h3100_pm_callback
read : h3100_read_egpio
}; };
#define H3100_DIRECT_EGPIO (GPIO_H3100_BT_ON \
| GPIO_H3100_GPIO3 \
| GPIO_H3100_QMUTE \
| GPIO_H3100_LCD_3V_ON \
| GPIO_H3100_AUD_ON \
| GPIO_H3100_AUD_PWR_ON \
| GPIO_H3100_IR_ON \
| GPIO_H3100_IR_FSEL)
/************************* H3600 *************************/ static void __init h3100_map_io(void)
static void h3600_init_egpio( void )
{ {
h3600_egpio = EGPIO_H3600_RS232_ON; h3xxx_map_io();
H3600_EGPIO = h3600_egpio;
/* Initialize h3100-specific values here */
GPCR = 0x0fffffff; /* All outputs are set low by default */
GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
H3100_DIRECT_EGPIO;
/* Older bootldrs put GPIO2-9 in alternate mode on the
assumption that they are used for video */
GAFR &= ~H3100_DIRECT_EGPIO;
H3100_EGPIO = h3100_egpio;
ipaq_model_ops = h3100_model_ops;
} }
static void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) MACHINE_START(H3100, "Compaq iPAQ H3100")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
BOOT_PARAMS(0xc0000100)
MAPIO(h3100_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
#endif /* CONFIG_SA1100_H3100 */
/************************* H3600 *************************/
#ifdef CONFIG_SA1100_H3600
#define H3600_EGPIO (*(volatile unsigned int *)H3600_EGPIO_VIRT)
static unsigned int h3600_egpio = EGPIO_H3600_RS232_ON;
static void h3600_control_egpio(enum ipaq_egpio_type x, int setp)
{ {
unsigned int egpio = 0; unsigned int egpio = 0;
unsigned long flags; unsigned long flags;
switch (x) { switch (x) {
case IPAQ_EGPIO_LCD_ON: case IPAQ_EGPIO_LCD_POWER:
egpio |= EGPIO_H3600_LCD_ON | egpio |= EGPIO_H3600_LCD_ON |
EGPIO_H3600_LCD_PCI | EGPIO_H3600_LCD_PCI |
EGPIO_H3600_LCD_5V_ON | EGPIO_H3600_LCD_5V_ON |
EGPIO_H3600_LVDD_ON; EGPIO_H3600_LVDD_ON;
do_blank(setp);
break;
case IPAQ_EGPIO_LCD_ENABLE:
break; break;
case IPAQ_EGPIO_CODEC_NRESET: case IPAQ_EGPIO_CODEC_NRESET:
egpio |= EGPIO_H3600_CODEC_NRESET; egpio |= EGPIO_H3600_CODEC_NRESET;
break; break;
case IPAQ_EGPIO_AUDIO_ON: case IPAQ_EGPIO_AUDIO_ON:
egpio |= EGPIO_H3600_AUD_AMP_ON | egpio |= EGPIO_H3600_AUD_AMP_ON |
EGPIO_H3600_AUD_PWR_ON; EGPIO_H3600_AUD_PWR_ON;
break; break;
case IPAQ_EGPIO_QMUTE: case IPAQ_EGPIO_QMUTE:
egpio |= EGPIO_H3600_QMUTE; egpio |= EGPIO_H3600_QMUTE;
...@@ -210,288 +354,441 @@ static void h3600_control_egpio( enum ipaq_egpio_type x, int setp ) ...@@ -210,288 +354,441 @@ static void h3600_control_egpio( enum ipaq_egpio_type x, int setp )
break; break;
} }
local_irq_save(flags); if (egpio) {
if ( setp ) local_irq_save(flags);
h3600_egpio |= egpio; if (setp)
else h3600_egpio |= egpio;
h3600_egpio &= ~egpio; else
H3600_EGPIO = h3600_egpio; h3600_egpio &= ~egpio;
local_irq_restore(flags); H3600_EGPIO = h3600_egpio;
local_irq_restore(flags);
}
} }
static unsigned long h3600_read_egpio( void ) static unsigned long h3600_read_egpio(void)
{ {
return h3600_egpio; return h3600_egpio;
} }
static int h3600_pm_callback(int req)
{
if (ipaq_model_ops.pm_callback_aux)
return ipaq_model_ops.pm_callback_aux(req);
return 0;
}
static struct ipaq_model_ops h3600_model_ops __initdata = { static struct ipaq_model_ops h3600_model_ops __initdata = {
model : IPAQ_H3600, .generic_name = "3600",
generic_name : "3600", .control = h3600_control_egpio,
initialize : h3600_init_egpio, .read = h3600_read_egpio,
control : h3600_control_egpio, .pm_callback = h3600_pm_callback
read : h3600_read_egpio
}; };
/************************* H3800 *************************/ static void __init h3600_map_io(void)
{
h3xxx_map_io();
#define ASIC1_OUTPUTS 0x7fff /* First 15 bits are used */ /* Initialize h3600-specific values here */
static unsigned int h3800_asic1_gpio; GPCR = 0x0fffffff; /* All outputs are set low by default */
static unsigned int h3800_asic2_gpio; GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 |
GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
static void h3800_init_egpio(void) H3600_EGPIO = h3600_egpio; /* Maintains across sleep? */
{ ipaq_model_ops = h3600_model_ops;
/* Set up ASIC #1 */ }
H3800_ASIC1_GPIO_Direction = ASIC1_OUTPUTS; /* All outputs */
H3800_ASIC1_GPIO_Mask = ASIC1_OUTPUTS; /* No interrupts */ MACHINE_START(H3600, "Compaq iPAQ H3600")
H3800_ASIC1_GPIO_SleepMask = ASIC1_OUTPUTS; BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
H3800_ASIC1_GPIO_SleepDir = ASIC1_OUTPUTS; BOOT_PARAMS(0xc0000100)
H3800_ASIC1_GPIO_SleepOut = GPIO_H3800_ASIC1_EAR_ON_N; MAPIO(h3600_map_io)
H3800_ASIC1_GPIO_BattFaultDir = ASIC1_OUTPUTS; INITIRQ(sa1100_init_irq)
H3800_ASIC1_GPIO_BattFaultOut = GPIO_H3800_ASIC1_EAR_ON_N; MACHINE_END
h3800_asic1_gpio = GPIO_H3800_ASIC1_IR_ON_N /* TODO: Check IR level */ #endif /* CONFIG_SA1100_H3600 */
| GPIO_H3800_ASIC1_RS232_ON
| GPIO_H3800_ASIC1_EAR_ON_N;
H3800_ASIC1_GPIO_Out = h3800_asic1_gpio; #ifdef CONFIG_SA1100_H3800
/* Set up ASIC #2 */ #define SET_ASIC1(x) \
H3800_ASIC2_GPIO_Direction = GPIO_H3800_ASIC2_PEN_IRQ do {if (setp) { H3800_ASIC1_GPIO_OUT |= (x); } else { H3800_ASIC1_GPIO_OUT &= ~(x); }} while(0)
| GPIO_H3800_ASIC2_SD_DETECT
| GPIO_H3800_ASIC2_EAR_IN_N
| GPIO_H3800_ASIC2_USB_DETECT_N
| GPIO_H3800_ASIC2_SD_CON_SLT;
h3800_asic2_gpio = GPIO_H3800_ASIC2_IN_Y1_N | GPIO_H3800_ASIC2_IN_X1_N; #define SET_ASIC2(x) \
H3800_ASIC2_GPIO_Data = h3800_asic2_gpio; do {if (setp) { H3800_ASIC2_GPIOPIOD |= (x); } else { H3800_ASIC2_GPIOPIOD &= ~(x); }} while(0)
H3800_ASIC2_GPIO_BattFaultOut = h3800_asic2_gpio;
/* TODO : Set sleep states & battery fault states */ #define CLEAR_ASIC1(x) \
do {if (setp) { H3800_ASIC1_GPIO_OUT &= ~(x); } else { H3800_ASIC1_GPIO_OUT |= (x); }} while(0)
/* Clear VPP Enable */ #define CLEAR_ASIC2(x) \
H3800_ASIC1_FlashWP_VPP_ON = 0; do {if (setp) { H3800_ASIC2_GPIOPIOD &= ~(x); } else { H3800_ASIC2_GPIOPIOD |= (x); }} while(0)
/*
On screen enable, we get
h3800_video_power_on(1)
LCD controller starts
h3800_video_lcd_enable(1)
On screen disable, we get
h3800_video_lcd_enable(0)
LCD controller stops
h3800_video_power_on(0)
*/
static void h3800_video_power_on(int setp)
{
if (setp) {
H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_ON;
msleep(30);
H3800_ASIC1_GPIO_OUT |= GPIO1_VGL_ON;
msleep(5);
H3800_ASIC1_GPIO_OUT |= GPIO1_VGH_ON;
msleep(50);
H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_5V_ON;
msleep(5);
} else {
msleep(5);
H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_5V_ON;
msleep(50);
H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGL_ON;
msleep(5);
H3800_ASIC1_GPIO_OUT &= ~GPIO1_VGH_ON;
msleep(100);
H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_ON;
}
} }
static void h3800_control_egpio( enum ipaq_egpio_type x, int setp ) static void h3800_video_lcd_enable(int setp)
{ {
unsigned int set_asic1_egpio = 0; if (setp) {
unsigned int clear_asic1_egpio = 0; msleep(17); // Wait one from before turning on
unsigned long flags; H3800_ASIC1_GPIO_OUT |= GPIO1_LCD_PCI;
} else {
H3800_ASIC1_GPIO_OUT &= ~GPIO1_LCD_PCI;
msleep(30); // Wait before turning off
}
}
static void h3800_control_egpio(enum ipaq_egpio_type x, int setp)
{
switch (x) { switch (x) {
case IPAQ_EGPIO_LCD_ON: case IPAQ_EGPIO_LCD_POWER:
set_asic1_egpio |= GPIO_H3800_ASIC1_LCD_5V_ON h3800_video_power_on(setp);
| GPIO_H3800_ASIC1_LCD_ON
| GPIO_H3800_ASIC1_LCD_PCI
| GPIO_H3800_ASIC1_VGH_ON
| GPIO_H3800_ASIC1_VGL_ON;
break; break;
case IPAQ_EGPIO_CODEC_NRESET: case IPAQ_EGPIO_LCD_ENABLE:
h3800_video_lcd_enable(setp);
break; break;
case IPAQ_EGPIO_CODEC_NRESET:
case IPAQ_EGPIO_AUDIO_ON: case IPAQ_EGPIO_AUDIO_ON:
break;
case IPAQ_EGPIO_QMUTE: case IPAQ_EGPIO_QMUTE:
printk(__FUNCTION__ ": error - should not be called\n");
break; break;
case IPAQ_EGPIO_OPT_NVRAM_ON: case IPAQ_EGPIO_OPT_NVRAM_ON:
SET_ASIC2(GPIO2_OPT_ON_NVRAM);
break; break;
case IPAQ_EGPIO_OPT_ON: case IPAQ_EGPIO_OPT_ON:
SET_ASIC2(GPIO2_OPT_ON);
break; break;
case IPAQ_EGPIO_CARD_RESET: case IPAQ_EGPIO_CARD_RESET:
SET_ASIC2(GPIO2_OPT_PCM_RESET);
break; break;
case IPAQ_EGPIO_OPT_RESET: case IPAQ_EGPIO_OPT_RESET:
SET_ASIC2(GPIO2_OPT_RESET);
break; break;
case IPAQ_EGPIO_IR_ON: case IPAQ_EGPIO_IR_ON:
clear_asic1_egpio |= GPIO_H3800_ASIC1_IR_ON_N; /* TODO : This is backwards? */ CLEAR_ASIC1(GPIO1_IR_ON_N);
break; break;
case IPAQ_EGPIO_IR_FSEL: case IPAQ_EGPIO_IR_FSEL:
break; break;
case IPAQ_EGPIO_RS232_ON: case IPAQ_EGPIO_RS232_ON:
set_asic1_egpio |= GPIO_H3800_ASIC1_RS232_ON; SET_ASIC1(GPIO1_RS232_ON);
break; break;
case IPAQ_EGPIO_VPP_ON: case IPAQ_EGPIO_VPP_ON:
H3800_ASIC1_FlashWP_VPP_ON = setp; H3800_ASIC2_FlashWP_VPP_ON = setp;
break; break;
} }
}
local_irq_save(flags); static unsigned long h3800_read_egpio(void)
if ( setp ) { {
h3800_asic1_gpio |= set_asic1_egpio; return H3800_ASIC1_GPIO_OUT | (H3800_ASIC2_GPIOPIOD << 16);
h3800_asic1_gpio &= ~clear_asic1_egpio;
}
else {
h3800_asic1_gpio &= ~set_asic1_egpio;
h3800_asic1_gpio |= clear_asic1_egpio;
}
H3800_ASIC1_GPIO_Out = h3800_asic1_gpio;
local_irq_restore(flags);
} }
static unsigned long h3800_read_egpio( void ) /* We need to fix ASIC2 GPIO over suspend/resume. At the moment,
it doesn't appear that ASIC1 GPIO has the same problem */
static int h3800_pm_callback(int req)
{ {
return h3800_asic1_gpio | (h3800_asic2_gpio << 16); static u16 asic1_data;
static u16 asic2_data;
int result = 0;
printk(__FUNCTION__ " %d\n", req);
switch (req) {
case PM_RESUME:
MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000; /* Set MSC2 correctly */
H3800_ASIC2_GPIOPIOD = asic2_data;
H3800_ASIC2_GPIODIR = GPIO2_PEN_IRQ
| GPIO2_SD_DETECT
| GPIO2_EAR_IN_N
| GPIO2_USB_DETECT_N
| GPIO2_SD_CON_SLT;
H3800_ASIC1_GPIO_OUT = asic1_data;
if (ipaq_model_ops.pm_callback_aux)
result = ipaq_model_ops.pm_callback_aux(req);
break;
case PM_SUSPEND:
if (ipaq_model_ops.pm_callback_aux &&
((result = ipaq_model_ops.pm_callback_aux(req)) != 0))
return result;
asic1_data = H3800_ASIC1_GPIO_OUT;
asic2_data = H3800_ASIC2_GPIOPIOD;
break;
default:
printk(__FUNCTION__ ": unrecognized PM callback\n");
break;
}
return result;
} }
static struct ipaq_model_ops h3800_model_ops __initdata = { static struct ipaq_model_ops h3800_model_ops __initdata = {
model : IPAQ_H3800, .generic_name = "3800",
generic_name : "3800", .control = h3800_control_egpio,
initialize : h3800_init_egpio, .read = h3800_read_egpio,
control : h3800_control_egpio, .pm_callback = h3800_pm_callback
read : h3800_read_egpio
}; };
#define MAX_ASIC_ISR_LOOPS 20
/* The order of these is important - see #include <asm/arch/irqs.h> */
static u32 kpio_irq_mask[] = {
KPIO_KEY_ALL,
KPIO_SPI_INT,
KPIO_OWM_INT,
KPIO_ADC_INT,
KPIO_UART_0_INT,
KPIO_UART_1_INT,
KPIO_TIMER_0_INT,
KPIO_TIMER_1_INT,
KPIO_TIMER_2_INT
};
static u32 gpio_irq_mask[] = {
GPIO2_PEN_IRQ,
GPIO2_SD_DETECT,
GPIO2_EAR_IN_N,
GPIO2_USB_DETECT_N,
GPIO2_SD_CON_SLT,
};
static void h3600_lcd_power(int on) static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
if (on) int i;
set_h3600_egpio(IPAQ_EGPIO_LCD_ON);
else
clr_h3600_egpio(IPAQ_EGPIO_LCD_ON);
}
if (0) printk(__FUNCTION__ ": interrupt received\n");
struct ipaq_model_ops ipaq_model_ops; desc->chip->ack(irq);
EXPORT_SYMBOL(ipaq_model_ops);
static int __init h3600_init_model_ops(void) for (i = 0; i < MAX_ASIC_ISR_LOOPS && (GPLR & GPIO_H3800_ASIC); i++) {
{ u32 irq;
if (machine_is_h3xxx()) { int j;
sa1100fb_lcd_power = h3600_lcd_power;
/* KPIO */
if (machine_is_h3100()) { irq = H3800_ASIC2_KPIINTFLAG;
ipaq_model_ops = h3100_model_ops; if (0) printk(__FUNCTION__" KPIO 0x%08X\n", irq);
} else if (machine_is_h3600()) { for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++)
ipaq_model_ops = h3600_model_ops; if (irq & kpio_irq_mask[j])
} else if (machine_is_h3800()) { do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs);
ipaq_model_ops = h3800_model_ops;
} /* GPIO2 */
init_h3600_egpio(); irq = H3800_ASIC2_GPIINTFLAG;
if (0) printk(__FUNCTION__" GPIO 0x%08X\n", irq);
for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++)
if (irq & gpio_irq_mask[j])
do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs);
} }
return 0;
if (i >= MAX_ASIC_ISR_LOOPS)
printk(__FUNCTION__ ": interrupt processing overrun\n");
/* For level-based interrupts */
desc->chip->unmask(irq);
} }
__initcall(h3600_init_model_ops); static struct irqaction h3800_irq = {
.name = "h3800_asic",
.handler = h3800_IRQ_demux,
.flags = SA_INTERRUPT,
};
u32 kpio_int_shadow = 0;
/*
* low-level UART features /* mask_ack <- IRQ is first serviced.
mask <- IRQ is disabled.
unmask <- IRQ is enabled
The INTCLR registers are poorly documented. I believe that writing
a "1" to the register clears the specific interrupt, but the documentation
indicates writing a "0" clears the interrupt. In any case, they shouldn't
be read (that's the INTFLAG register)
*/ */
static void h3600_uart_set_mctrl(struct uart_port *port, u_int mctrl) static void h3800_mask_ack_kpio_irq(unsigned int irq)
{ {
if (port->mapbase == _Ser3UTCR0) { u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
if (mctrl & TIOCM_RTS) kpio_int_shadow &= ~mask;
GPCR = GPIO_H3600_COM_RTS; H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
else H3800_ASIC2_KPIINTCLR = mask;
GPSR = GPIO_H3600_COM_RTS;
}
} }
static u_int h3600_uart_get_mctrl(struct uart_port *port) static void h3800_mask_kpio_irq(unsigned int irq)
{ {
u_int ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR; u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
kpio_int_shadow &= ~mask;
H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
}
if (port->mapbase == _Ser3UTCR0) { static void h3800_unmask_kpio_irq(unsigned int irq)
int gplr = GPLR; {
if (gplr & GPIO_H3600_COM_DCD) u32 mask = kpio_irq_mask[irq - H3800_KPIO_IRQ_START];
ret &= ~TIOCM_CD; kpio_int_shadow |= mask;
if (gplr & GPIO_H3600_COM_CTS) H3800_ASIC2_KPIINTSTAT = kpio_int_shadow;
ret &= ~TIOCM_CTS; }
}
return ret; static void h3800_mask_ack_gpio_irq(unsigned int irq)
{
u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
H3800_ASIC2_GPIINTSTAT &= ~mask;
H3800_ASIC2_GPIINTCLR = mask;
} }
static void h3600_uart_pm(struct uart_port *port, u_int state, u_int oldstate) static void h3800_mask_gpio_irq(unsigned int irq)
{ {
if (port->mapbase == _Ser2UTCR0) { u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
assign_h3600_egpio( IPAQ_EGPIO_IR_ON, !state ); H3800_ASIC2_GPIINTSTAT &= ~mask;
} else if (port->mapbase == _Ser3UTCR0) {
assign_h3600_egpio( IPAQ_EGPIO_RS232_ON, !state );
} }
static void h3800_unmask_gpio_irq(unsigned int irq)
{
u32 mask = gpio_irq_mask[irq - H3800_GPIO_IRQ_START];
H3800_ASIC2_GPIINTSTAT |= mask;
} }
/* static void __init h3800_init_irq(void)
* Enable/Disable wake up events for this serial port.
* Obviously, we only support this on the normal COM port.
*/
static int h3600_uart_set_wake(struct uart_port *port, u_int enable)
{ {
int err = -EINVAL; int i;
if (port->mapbase == _Ser3UTCR0) { /* Initialize standard IRQs */
if (enable) sa1100_init_irq();
PWER |= PWER_GPIO23 | PWER_GPIO25 ; /* DCD and CTS */
else /* Disable all IRQs and set up clock */
PWER &= ~(PWER_GPIO23 | PWER_GPIO25); /* DCD and CTS */ H3800_ASIC2_KPIINTSTAT = 0; /* Disable all interrupts */
err = 0; H3800_ASIC2_GPIINTSTAT = 0;
H3800_ASIC2_KPIINTCLR = 0; /* Clear all KPIO interrupts */
H3800_ASIC2_GPIINTCLR = 0; /* Clear all GPIO interrupts */
// H3800_ASIC2_KPIINTCLR = 0xffff; /* Clear all KPIO interrupts */
// H3800_ASIC2_GPIINTCLR = 0xffff; /* Clear all GPIO interrupts */
H3800_ASIC2_CLOCK_Enable |= ASIC2_CLOCK_EX0; /* 32 kHZ crystal on */
H3800_ASIC2_INTR_ClockPrescale |= ASIC2_INTCPS_SET;
H3800_ASIC2_INTR_ClockPrescale = ASIC2_INTCPS_CPS(0x0e) | ASIC2_INTCPS_SET;
H3800_ASIC2_INTR_TimerSet = 1;
#if 0
for (i = 0; i < H3800_KPIO_IRQ_COUNT; i++) {
int irq = i + H3800_KPIO_IRQ_START;
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
set_irq_chip(irq, &h3800_kpio_irqchip);
} }
return err;
for (i = 0; i < H3800_GPIO_IRQ_COUNT; i++) {
int irq = i + H3800_GPIO_IRQ_START;
irq_desc[irq].valid = 1;
irq_desc[irq].probe_ok = 1;
set_irq_chip(irq, &h3800_gpio_irqchip);
}
#endif
set_irq_type(IRQ_GPIO_H3800_ASIC, IRQT_RISING);
set_irq_chained_handler(IRQ_GPIO_H3800_ASIC, &h3800_IRQ_demux);
} }
static struct sa1100_port_fns h3600_port_fns __initdata = {
.set_mctrl = h3600_uart_set_mctrl,
.get_mctrl = h3600_uart_get_mctrl,
.pm = h3600_uart_pm,
.set_wake = h3600_uart_set_wake,
};
static struct map_desc h3600_io_desc[] __initdata = { #define ASIC1_OUTPUTS 0x7fff /* First 15 bits are used */
/* virtual physical length type */
{ H3600_EGPIO_VIRT, 0x49000000, 0x01000000, MT_DEVICE }, /* EGPIO 0 CS#5 */
{ H3600_BANK_2_VIRT, 0x10000000, 0x02800000, MT_DEVICE }, /* static memory bank 2 CS#2 */
{ H3600_BANK_4_VIRT, 0x40000000, 0x00800000, MT_DEVICE } /* static memory bank 4 CS#4 */
};
static void __init h3600_map_io(void) static void __init h3800_map_io(void)
{ {
sa1100_map_io(); h3xxx_map_io();
iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
/* Add wakeup on AC plug/unplug */
PWER |= PWER_GPIO12;
/* Initialize h3800-specific values here */
GPCR = 0x0fffffff; /* All outputs are set low by default */
GAFR = GPIO_H3800_CLK_OUT |
GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
GPDR = GPIO_H3800_CLK_OUT |
GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK |
GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA |
GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
TUCR = TUCR_3_6864MHz; /* Seems to be used only for the Bluetooth UART */
/* Fix the memory bus */
MSC2 = (MSC2 & 0x0000ffff) | 0xE4510000;
sa1100_register_uart_fns(&h3600_port_fns); /* Set up ASIC #1 */
sa1100_register_uart(0, 3); H3800_ASIC1_GPIO_DIR = ASIC1_OUTPUTS; /* All outputs */
sa1100_register_uart(1, 1); /* isn't this one driven elsewhere? */ H3800_ASIC1_GPIO_MASK = ASIC1_OUTPUTS; /* No interrupts */
H3800_ASIC1_GPIO_SLEEP_MASK = ASIC1_OUTPUTS;
/* H3800_ASIC1_GPIO_SLEEP_DIR = ASIC1_OUTPUTS;
* Default GPIO settings. Should be set by machine H3800_ASIC1_GPIO_SLEEP_OUT = GPIO1_EAR_ON_N;
*/ H3800_ASIC1_GPIO_BATT_FAULT_DIR = ASIC1_OUTPUTS;
GPCR = 0x0fffffff; H3800_ASIC1_GPIO_BATT_FAULT_OUT = GPIO1_EAR_ON_N;
// GPDR = 0x0401f3fc;
GPDR = GPIO_H3600_COM_RTS | GPIO_H3600_L3_CLOCK | H3800_ASIC1_GPIO_OUT = GPIO1_IR_ON_N
GPIO_H3600_L3_MODE | GPIO_H3600_L3_DATA | | GPIO1_RS232_ON
GPIO_H3600_CLK_SET1 | GPIO_H3600_CLK_SET0 | | GPIO1_EAR_ON_N;
GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
init_h3600_egpio(); /* Set up ASIC #2 */
H3800_ASIC2_GPIOPIOD = GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
H3800_ASIC2_GPOBFSTAT = GPIO2_IN_Y1_N | GPIO2_IN_X1_N;
/* H3800_ASIC2_GPIODIR = GPIO2_PEN_IRQ
* Ensure those pins are outputs and driving low. | GPIO2_SD_DETECT
*/ | GPIO2_EAR_IN_N
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM; | GPIO2_USB_DETECT_N
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM); | GPIO2_SD_CON_SLT;
/* Configure suspend conditions */ /* TODO : Set sleep states & battery fault states */
PGSR = 0;
PWER = PWER_GPIO0 | PWER_RTC; /* Clear VPP Enable */
PCFR = PCFR_OPDE; H3800_ASIC2_FlashWP_VPP_ON = 0;
PSDR = 0; ipaq_model_ops = h3800_model_ops;
} }
MACHINE_START(H3600, "Compaq iPAQ H3600")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
BOOT_PARAMS(0xc0000100)
MAPIO(h3600_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
MACHINE_START(H3100, "Compaq iPAQ H3100")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
BOOT_PARAMS(0xc0000100)
MAPIO(h3600_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
MACHINE_START(H3800, "Compaq iPAQ H3800") MACHINE_START(H3800, "Compaq iPAQ H3800")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
BOOT_PARAMS(0xc0000100) BOOT_PARAMS(0xc0000100)
MAPIO(h3600_map_io) MAPIO(h3800_map_io)
INITIRQ(sa1100_init_irq) INITIRQ(h3800_init_irq)
MACHINE_END MACHINE_END
#endif /* CONFIG_SA1100_H3800 */
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
#define JORTUCR_VAL 0x20000400 #define JORTUCR_VAL 0x20000400
...@@ -46,11 +45,7 @@ static int __init jornada720_init(void) ...@@ -46,11 +45,7 @@ static int __init jornada720_init(void)
PPSR &= ~(PPC_LDD3 | PPC_LDD4); PPSR &= ~(PPC_LDD3 | PPC_LDD4);
PPDR |= PPC_LDD3 | PPC_LDD4; PPDR |= PPC_LDD3 | PPC_LDD4;
/* initialize extra IRQs */ return sa1111_init(0x40000000, IRQ_GPIO1);
set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
sa1111_init_irq(IRQ_GPIO1); /* chained on GPIO 1 */
return 0;
} }
arch_initcall(jornada720_init); arch_initcall(jornada720_init);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -23,13 +24,6 @@ ...@@ -23,13 +24,6 @@
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#include <asm/sizes.h> #include <asm/sizes.h>
#include "sa1111.h"
static struct device neponset_device = {
.name = "Neponset",
.bus_id = "nep_bus",
};
/* /*
* Install handler for Neponset IRQ. Note that we have to loop here * Install handler for Neponset IRQ. Note that we have to loop here
* since the ETHERNET and USAR IRQs are level based, and we need to * since the ETHERNET and USAR IRQs are level based, and we need to
...@@ -163,6 +157,52 @@ static struct sa1100_port_fns neponset_port_fns __initdata = { ...@@ -163,6 +157,52 @@ static struct sa1100_port_fns neponset_port_fns __initdata = {
.get_mctrl = neponset_get_mctrl, .get_mctrl = neponset_get_mctrl,
}; };
/*
* LDM power management.
*/
static int neponset_suspend(struct device *dev, u32 state, u32 level)
{
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE ||
level == SUSPEND_DISABLE ||
level == SUSPEND_POWER_DOWN) {
if (!dev->saved_state)
dev->saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
*(unsigned int *)dev->saved_state = NCR_0;
}
return 0;
}
static int neponset_resume(struct device *dev, u32 level)
{
if (level == RESUME_RESTORE_STATE || level == RESUME_ENABLE) {
if (dev->saved_state) {
NCR_0 = *(unsigned int *)dev->saved_state;
kfree(dev->saved_state);
dev->saved_state = NULL;
}
}
return 0;
}
static struct device_driver neponset_device_driver = {
.suspend = neponset_suspend,
.resume = neponset_resume,
};
static struct device neponset_device = {
.name = "Neponset",
.bus_id = "neponset",
.driver = &neponset_device_driver,
};
static int __init neponset_init(void) static int __init neponset_init(void)
{ {
int ret; int ret;
...@@ -191,7 +231,7 @@ static int __init neponset_init(void) ...@@ -191,7 +231,7 @@ static int __init neponset_init(void)
return -ENODEV; return -ENODEV;
} }
ret = device_register(&neponset_device); ret = register_sys_device(&neponset_device);
if (ret) if (ret)
return ret; return ret;
...@@ -213,7 +253,7 @@ static int __init neponset_init(void) ...@@ -213,7 +253,7 @@ static int __init neponset_init(void)
/* /*
* Probe and initialise the SA1111. * Probe and initialise the SA1111.
*/ */
return sa1111_init(&neponset_device, 0x40000000, IRQ_NEPONSET_SA1111); return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111);
} }
arch_initcall(neponset_init); arch_initcall(neponset_init);
......
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#include <asm/mach/serial_sa1100.h> #include <asm/mach/serial_sa1100.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
static int __init pfs168_init(void) static int __init pfs168_init(void)
...@@ -36,7 +35,7 @@ static int __init pfs168_init(void) ...@@ -36,7 +35,7 @@ static int __init pfs168_init(void)
/* /*
* Probe for SA1111. * Probe for SA1111.
*/ */
return sa1111_init(NULL, 0x40000000, IRQ_GPIO25); return sa1111_init(0x40000000, IRQ_GPIO25);
} }
arch_initcall(pfs168_init); arch_initcall(pfs168_init);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/device.h>
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <asm/hardware.h> #include <asm/hardware.h>
...@@ -193,11 +194,29 @@ static int sysctl_pm_do_suspend(void) ...@@ -193,11 +194,29 @@ static int sysctl_pm_do_suspend(void)
{ {
int retval; int retval;
/*
* Suspend "legacy" devices.
*/
retval = pm_send_all(PM_SUSPEND, (void *)3); retval = pm_send_all(PM_SUSPEND, (void *)3);
if (retval == 0) { if (retval == 0) {
/*
* Suspend LDM devices.
*/
device_suspend(4, SUSPEND_NOTIFY);
device_suspend(4, SUSPEND_SAVE_STATE);
device_suspend(4, SUSPEND_DISABLE);
retval = pm_do_suspend(); retval = pm_do_suspend();
/*
* Resume LDM devices.
*/
device_resume(RESUME_RESTORE_STATE);
device_resume(RESUME_ENABLE);
/*
* Resume "legacy" devices.
*/
pm_send_all(PM_RESUME, (void *)0); pm_send_all(PM_RESUME, (void *)0);
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -34,11 +35,132 @@ ...@@ -34,11 +35,132 @@
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#include "sa1111.h" /*
* We keep the following data for the overall SA1111. Note that the
* struct device and struct resource are "fake"; they should be supplied
* by the bus above us. However, in the interests of getting all SA1111
* drivers converted over to the device model, we provide this as an
* anchor point for all the other drivers.
*/
struct sa1111 {
struct device dev;
struct resource res;
int irq;
spinlock_t lock;
void *base;
};
/*
* We _really_ need to eliminate this. Its only users
* are the PWM and DMA checking code.
*/
static struct sa1111 *g_sa1111;
static struct sa1111_dev usb_dev = {
.dev = {
.name = "Intel Corporation SA1111 [USB Controller]",
},
.skpcr_mask = SKPCR_UCLKEN,
.devid = SA1111_DEVID_USB,
.irq = {
IRQ_USBPWR,
IRQ_NHCIM,
IRQ_HCIBUFFACC,
IRQ_HCIRMTWKP,
IRQ_NHCIMFCIR,
IRQ_USB_PORT_RESUME
},
};
struct sa1111_device *sa1111; static struct sa1111_dev sac_dev = {
.dev = {
.name = "Intel Corporation SA1111 [Audio Controller]",
},
.skpcr_mask = SKPCR_I2SCLKEN | SKPCR_L3CLKEN,
.devid = SA1111_DEVID_SAC,
.irq = {
AUDXMTDMADONEA,
AUDXMTDMADONEB,
AUDRCVDMADONEA,
AUDRCVDMADONEB
},
};
EXPORT_SYMBOL(sa1111); static struct sa1111_dev ssp_dev = {
.dev = {
.name = "Intel Corporation SA1111 [SSP Controller]",
},
.skpcr_mask = SKPCR_SCLKEN,
.devid = SA1111_DEVID_SSP,
};
static struct sa1111_dev kbd_dev = {
.dev = {
.name = "Intel Corporation SA1111 [PS2]",
},
.skpcr_mask = SKPCR_PTCLKEN,
.devid = SA1111_DEVID_PS2,
.irq = {
IRQ_TPRXINT,
IRQ_TPTXINT
},
};
static struct sa1111_dev mse_dev = {
.dev = {
.name = "Intel Corporation SA1111 [PS2]",
},
.skpcr_mask = SKPCR_PMCLKEN,
.devid = SA1111_DEVID_PS2,
.irq = {
IRQ_MSRXINT,
IRQ_MSTXINT
},
};
static struct sa1111_dev int_dev = {
.dev = {
.name = "Intel Corporation SA1111 [Interrupt Controller]",
},
.skpcr_mask = 0,
.devid = SA1111_DEVID_INT,
};
static struct sa1111_dev pcmcia_dev = {
.dev = {
.name = "Intel Corporation SA1111 [PCMCIA Controller]",
},
.skpcr_mask = 0,
.devid = SA1111_DEVID_PCMCIA,
.irq = {
IRQ_S0_READY_NINT,
IRQ_S0_CD_VALID,
IRQ_S0_BVD1_STSCHG,
IRQ_S1_READY_NINT,
IRQ_S1_CD_VALID,
IRQ_S1_BVD1_STSCHG,
},
};
static struct sa1111_dev *devs[] = {
&usb_dev,
&sac_dev,
&ssp_dev,
&kbd_dev,
&mse_dev,
&int_dev,
&pcmcia_dev,
};
static unsigned int dev_offset[] = {
SA1111_USB,
0x0600,
0x0800,
SA1111_KBD,
SA1111_MSE,
SA1111_INTC,
0x1800,
};
/* /*
* SA1111 interrupt support. Since clearing an IRQ while there are * SA1111 interrupt support. Since clearing an IRQ while there are
...@@ -50,11 +172,15 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -50,11 +172,15 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
{ {
unsigned int stat0, stat1, i; unsigned int stat0, stat1, i;
desc->chip->ack(irq);
stat0 = INTSTATCLR0; stat0 = INTSTATCLR0;
stat1 = INTSTATCLR1; stat1 = INTSTATCLR1;
INTSTATCLR0 = stat0;
desc->chip->ack(irq);
INTSTATCLR1 = stat1;
if (stat0 == 0 && stat1 == 0) { if (stat0 == 0 && stat1 == 0) {
do_bad_IRQ(irq, desc, regs); do_bad_IRQ(irq, desc, regs);
return; return;
...@@ -75,9 +201,8 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) ...@@ -75,9 +201,8 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
#define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START)) #define SA1111_IRQMASK_LO(x) (1 << (x - IRQ_SA1111_START))
#define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32)) #define SA1111_IRQMASK_HI(x) (1 << (x - IRQ_SA1111_START - 32))
static void sa1111_ack_lowirq(unsigned int irq) static void sa1111_ack_irq(unsigned int irq)
{ {
INTSTATCLR0 = SA1111_IRQMASK_LO(irq);
} }
static void sa1111_mask_lowirq(unsigned int irq) static void sa1111_mask_lowirq(unsigned int irq)
...@@ -133,18 +258,13 @@ static int sa1111_type_lowirq(unsigned int irq, unsigned int flags) ...@@ -133,18 +258,13 @@ static int sa1111_type_lowirq(unsigned int irq, unsigned int flags)
} }
static struct irqchip sa1111_low_chip = { static struct irqchip sa1111_low_chip = {
.ack = sa1111_ack_lowirq, .ack = sa1111_ack_irq,
.mask = sa1111_mask_lowirq, .mask = sa1111_mask_lowirq,
.unmask = sa1111_unmask_lowirq, .unmask = sa1111_unmask_lowirq,
.rerun = sa1111_rerun_lowirq, .rerun = sa1111_rerun_lowirq,
.type = sa1111_type_lowirq, .type = sa1111_type_lowirq,
}; };
static void sa1111_ack_highirq(unsigned int irq)
{
INTSTATCLR1 = SA1111_IRQMASK_HI(irq);
}
static void sa1111_mask_highirq(unsigned int irq) static void sa1111_mask_highirq(unsigned int irq)
{ {
INTEN1 &= ~SA1111_IRQMASK_HI(irq); INTEN1 &= ~SA1111_IRQMASK_HI(irq);
...@@ -198,34 +318,40 @@ static int sa1111_type_highirq(unsigned int irq, unsigned int flags) ...@@ -198,34 +318,40 @@ static int sa1111_type_highirq(unsigned int irq, unsigned int flags)
} }
static struct irqchip sa1111_high_chip = { static struct irqchip sa1111_high_chip = {
.ack = sa1111_ack_highirq, .ack = sa1111_ack_irq,
.mask = sa1111_mask_highirq, .mask = sa1111_mask_highirq,
.unmask = sa1111_unmask_highirq, .unmask = sa1111_unmask_highirq,
.rerun = sa1111_rerun_highirq, .rerun = sa1111_rerun_highirq,
.type = sa1111_type_highirq, .type = sa1111_type_highirq,
}; };
static void __init sa1111_init_irq(int irq_nr) static void __init sa1111_init_irq(struct sa1111_dev *sadev)
{ {
unsigned int irq; unsigned int irq;
request_mem_region(_INTTEST0, 512, "irqs"); /*
* We're guaranteed that this region hasn't been taken.
*/
request_mem_region(sadev->res.start, 512, "irqs");
/* disable all IRQs */ /* disable all IRQs */
INTEN0 = 0; sa1111_writel(0, sadev->mapbase + SA1111_INTEN0);
INTEN1 = 0; sa1111_writel(0, sadev->mapbase + SA1111_INTEN1);
sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN0);
sa1111_writel(0, sadev->mapbase + SA1111_WAKEEN1);
/* /*
* detect on rising edge. Note: Feb 2001 Errata for SA1111 * detect on rising edge. Note: Feb 2001 Errata for SA1111
* specifies that S0ReadyInt and S1ReadyInt should be '1'. * specifies that S0ReadyInt and S1ReadyInt should be '1'.
*/ */
INTPOL0 = 0; sa1111_writel(0, sadev->mapbase + SA1111_INTPOL0);
INTPOL1 = SA1111_IRQMASK_HI(S0_READY_NINT) | sa1111_writel(SA1111_IRQMASK_HI(IRQ_S0_READY_NINT) |
SA1111_IRQMASK_HI(S1_READY_NINT); SA1111_IRQMASK_HI(IRQ_S1_READY_NINT),
sadev->mapbase + SA1111_INTPOL1);
/* clear all IRQs */ /* clear all IRQs */
INTSTATCLR0 = ~0; sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR0);
INTSTATCLR1 = ~0; sa1111_writel(~0, sadev->mapbase + SA1111_INTSTATCLR1);
for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) { for (irq = IRQ_GPAIN0; irq <= SSPROR; irq++) {
set_irq_chip(irq, &sa1111_low_chip); set_irq_chip(irq, &sa1111_low_chip);
...@@ -233,7 +359,7 @@ static void __init sa1111_init_irq(int irq_nr) ...@@ -233,7 +359,7 @@ static void __init sa1111_init_irq(int irq_nr)
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
} }
for (irq = AUDXMTDMADONEA; irq <= S1_BVD1_STSCHG; irq++) { for (irq = AUDXMTDMADONEA; irq <= IRQ_S1_BVD1_STSCHG; irq++) {
set_irq_chip(irq, &sa1111_high_chip); set_irq_chip(irq, &sa1111_high_chip);
set_irq_handler(irq, do_edge_IRQ); set_irq_handler(irq, do_edge_IRQ);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
...@@ -242,24 +368,11 @@ static void __init sa1111_init_irq(int irq_nr) ...@@ -242,24 +368,11 @@ static void __init sa1111_init_irq(int irq_nr)
/* /*
* Register SA1111 interrupt * Register SA1111 interrupt
*/ */
set_irq_type(irq_nr, IRQT_RISING); set_irq_type(sadev->irq[0], IRQT_RISING);
set_irq_chained_handler(irq_nr, sa1111_irq_handler); set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler);
}
static int sa1111_suspend(struct device *dev, u32 state, u32 level)
{
return 0;
} }
static int sa1111_resume(struct device *dev, u32 level) static struct device_driver sa1111_device_driver;
{
return 0;
}
static struct device_driver sa1111_device_driver = {
.suspend = sa1111_suspend,
.resume = sa1111_resume,
};
/** /**
* sa1111_probe - probe for a single SA1111 chip. * sa1111_probe - probe for a single SA1111 chip.
...@@ -274,30 +387,38 @@ static struct device_driver sa1111_device_driver = { ...@@ -274,30 +387,38 @@ static struct device_driver sa1111_device_driver = {
* %0 successful. * %0 successful.
*/ */
static int __init static int __init
sa1111_probe(struct device *parent, unsigned long phys_addr) sa1111_probe(unsigned long phys_addr, int irq)
{ {
struct sa1111_device *sa; struct sa1111 *sachip;
unsigned long id; unsigned long id;
int ret = -ENODEV; unsigned int has_devs;
int i, ret = -ENODEV;
sa = kmalloc(sizeof(struct sa1111_device), GFP_KERNEL); sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL);
if (!sa) if (!sachip)
return -ENOMEM; return -ENOMEM;
memset(sa, 0, sizeof(struct sa1111_device)); memset(sachip, 0, sizeof(struct sa1111));
spin_lock_init(&sachip->lock);
sa->resource.name = "SA1111"; strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name));
sa->resource.start = phys_addr; snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr);
sa->resource.end = phys_addr + 0x2000; sachip->dev.driver = &sa1111_device_driver;
sachip->dev.driver_data = sachip;
if (request_resource(&iomem_resource, &sa->resource)) { sachip->res.name = sachip->dev.name;
sachip->res.start = phys_addr;
sachip->res.end = phys_addr + 0x2000;
sachip->irq = irq;
if (request_resource(&iomem_resource, &sachip->res)) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
/* eventually ioremap... */ sachip->base = ioremap(phys_addr, PAGE_SIZE * 2);
sa->base = (void *)0xf4000000; if (!sachip->base) {
if (!sa->base) {
ret = -ENOMEM; ret = -ENOMEM;
goto release; goto release;
} }
...@@ -305,7 +426,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr) ...@@ -305,7 +426,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
/* /*
* Probe for the chip. Only touch the SBI registers. * Probe for the chip. Only touch the SBI registers.
*/ */
id = sa1111_readl(sa->base + SA1111_SKID); id = sa1111_readl(sachip->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id); printk(KERN_DEBUG "SA1111 not detected: ID = %08lx\n", id);
ret = -ENODEV; ret = -ENODEV;
...@@ -315,12 +436,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr) ...@@ -315,12 +436,7 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
/* /*
* We found the chip. * We found the chip.
*/ */
strcpy(sa->dev.name, "SA1111"); ret = register_sys_device(&sachip->dev);
sprintf(sa->dev.bus_id, "%8.8lx", phys_addr);
sa->dev.parent = parent;
sa->dev.driver = &sa1111_device_driver;
ret = device_register(&sa->dev);
if (ret) if (ret)
printk("sa1111 device_register failed: %d\n", ret); printk("sa1111 device_register failed: %d\n", ret);
...@@ -328,19 +444,64 @@ sa1111_probe(struct device *parent, unsigned long phys_addr) ...@@ -328,19 +444,64 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
"silicon revision %lx, metal revision %lx\n", "silicon revision %lx, metal revision %lx\n",
(id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK));
sa1111 = sa; g_sa1111 = sachip;
has_devs = ~0;
if (machine_is_assabet() || machine_is_jornada720() ||
machine_is_badge4())
has_devs &= ~(1 << 4);
else
has_devs &= ~(1 << 1);
for (i = 0; i < ARRAY_SIZE(devs); i++) {
if (!(has_devs & (1 << i)))
continue;
snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id),
"%4.4x", dev_offset[i]);
devs[i]->dev.parent = &sachip->dev;
devs[i]->dev.bus = &sa1111_bus_type;
devs[i]->res.start = sachip->res.start + dev_offset[i];
devs[i]->res.end = devs[i]->res.start + 511;
devs[i]->res.name = devs[i]->dev.name;
devs[i]->res.flags = IORESOURCE_MEM;
devs[i]->mapbase = sachip->base + dev_offset[i];
if (request_resource(&sachip->res, &devs[i]->res)) {
printk("SA1111: failed to allocate resource for %s\n",
devs[i]->res.name);
continue;
}
device_register(&devs[i]->dev);
}
return 0; return 0;
unmap: unmap:
// iounmap(sa->base); iounmap(sachip->base);
release: release:
release_resource(&sa->resource); release_resource(&sachip->res);
out: out:
kfree(sa); kfree(sachip);
return ret; return ret;
} }
static void __sa1111_remove(struct sa1111 *sachip)
{
int i;
for (i = 0; i < ARRAY_SIZE(devs); i++) {
put_device(&devs[i]->dev);
release_resource(&devs[i]->res);
}
iounmap(sachip->base);
release_resource(&sachip->res);
kfree(sachip);
}
/* /*
* Bring the SA1111 out of reset. This requires a set procedure: * Bring the SA1111 out of reset. This requires a set procedure:
* 1. nRESET asserted (by hardware) * 1. nRESET asserted (by hardware)
...@@ -355,12 +516,11 @@ sa1111_probe(struct device *parent, unsigned long phys_addr) ...@@ -355,12 +516,11 @@ sa1111_probe(struct device *parent, unsigned long phys_addr)
* SBI_SMCR * SBI_SMCR
* SBI_SKID * SBI_SKID
*/ */
void sa1111_wake(void) static void sa1111_wake(struct sa1111 *sachip)
{ {
struct sa1111_device *sa = sa1111;
unsigned long flags, r; unsigned long flags, r;
local_irq_save(flags); spin_lock_irqsave(&sachip->lock, flags);
/* /*
* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
...@@ -373,11 +533,11 @@ void sa1111_wake(void) ...@@ -373,11 +533,11 @@ void sa1111_wake(void)
/* /*
* Turn VCO on, and disable PLL Bypass. * Turn VCO on, and disable PLL Bypass.
*/ */
r = sa1111_readl(sa->base + SA1111_SKCR); r = sa1111_readl(sachip->base + SA1111_SKCR);
r &= ~SKCR_VCO_OFF; r &= ~SKCR_VCO_OFF;
sa1111_writel(r, sa->base + SA1111_SKCR); sa1111_writel(r, sachip->base + SA1111_SKCR);
r |= SKCR_PLL_BYPASS | SKCR_OE_EN; r |= SKCR_PLL_BYPASS | SKCR_OE_EN;
sa1111_writel(r, sa->base + SA1111_SKCR); sa1111_writel(r, sachip->base + SA1111_SKCR);
/* /*
* Wait lock time. SA1111 manual _doesn't_ * Wait lock time. SA1111 manual _doesn't_
...@@ -389,7 +549,7 @@ void sa1111_wake(void) ...@@ -389,7 +549,7 @@ void sa1111_wake(void)
* Enable RCLK. We also ensure that RDYEN is set. * Enable RCLK. We also ensure that RDYEN is set.
*/ */
r |= SKCR_RCLKEN | SKCR_RDYEN; r |= SKCR_RCLKEN | SKCR_RDYEN;
sa1111_writel(r, sa->base + SA1111_SKCR); sa1111_writel(r, sachip->base + SA1111_SKCR);
/* /*
* Wait 14 RCLK cycles for the chip to finish coming out * Wait 14 RCLK cycles for the chip to finish coming out
...@@ -400,76 +560,31 @@ void sa1111_wake(void) ...@@ -400,76 +560,31 @@ void sa1111_wake(void)
/* /*
* Ensure all clocks are initially off. * Ensure all clocks are initially off.
*/ */
sa1111_writel(0, sa->base + SA1111_SKPCR); sa1111_writel(0, sachip->base + SA1111_SKPCR);
local_irq_restore(flags); spin_unlock_irqrestore(&sachip->lock, flags);
}
void sa1111_doze(void)
{
struct sa1111_device *sa = sa1111;
unsigned long flags;
unsigned int val;
local_irq_save(flags);
if (sa1111_readl(sa->base + SA1111_SKPCR) & SKPCR_UCLKEN) {
local_irq_restore(flags);
printk("SA1111 doze mode refused\n");
return;
}
val = sa1111_readl(sa->base + SA1111_SKCR);
sa1111_writel(val & ~SKCR_RCLKEN, sa->base + SA1111_SKCR);
local_irq_restore(flags);
} }
/* /*
* Configure the SA1111 shared memory controller. * Configure the SA1111 shared memory controller.
*/ */
void sa1111_configure_smc(int sdram, unsigned int drac, unsigned int cas_latency) void
sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac,
unsigned int cas_latency)
{ {
struct sa1111_device *sa = sa1111;
unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC);
if (cas_latency == 3) if (cas_latency == 3)
smcr |= SMCR_CLAT; smcr |= SMCR_CLAT;
sa1111_writel(smcr, sa->base + SA1111_SMCR); sa1111_writel(smcr, sachip->base + SA1111_SMCR);
} }
EXPORT_SYMBOL(sa1111_wake); /*
EXPORT_SYMBOL(sa1111_doze); * According to the "Intel StrongARM SA-1111 Microprocessor Companion
void sa1111_enable_device(unsigned int mask)
{
struct sa1111_device *sa = sa1111;
unsigned int val;
preempt_disable();
val = sa1111_readl(sa->base + SA1111_SKPCR);
sa1111_writel(val | mask, sa->base + SA1111_SKPCR);
preempt_enable();
}
void sa1111_disable_device(unsigned int mask)
{
struct sa1111_device *sa = sa1111;
unsigned int val;
preempt_disable();
val = sa1111_readl(sa->base + SA1111_SKPCR);
sa1111_writel(val & ~mask, sa->base + SA1111_SKPCR);
preempt_enable();
}
EXPORT_SYMBOL(sa1111_enable_device);
EXPORT_SYMBOL(sa1111_disable_device);
/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
* Chip Specification Update" (June 2000), erratum #7, there is a * Chip Specification Update" (June 2000), erratum #7, there is a
* significant bug in Serial Audio Controller DMA. If the SAC is * significant bug in the SA1111 SDRAM shared memory controller. If
* accessing a region of memory above 1MB relative to the bank base, * an access to a region of memory above 1MB relative to the bank base,
* it is important that address bit 10 _NOT_ be asserted. Depending * it is important that address bit 10 _NOT_ be asserted. Depending
* on the configuration of the RAM, bit 10 may correspond to one * on the configuration of the RAM, bit 10 may correspond to one
* of several different (processor-relative) address bits. * of several different (processor-relative) address bits.
...@@ -479,7 +594,9 @@ EXPORT_SYMBOL(sa1111_disable_device); ...@@ -479,7 +594,9 @@ EXPORT_SYMBOL(sa1111_disable_device);
*/ */
int sa1111_check_dma_bug(dma_addr_t addr) int sa1111_check_dma_bug(dma_addr_t addr)
{ {
unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr); struct sa1111 *sachip = g_sa1111;
unsigned int physaddr = SA1111_DMA_ADDR((unsigned int)addr);
unsigned int smcr;
/* Section 4.6 of the "Intel StrongARM SA-1111 Development Module /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
* User's Guide" mentions that jumpers R51 and R52 control the * User's Guide" mentions that jumpers R51 and R52 control the
...@@ -494,9 +611,10 @@ int sa1111_check_dma_bug(dma_addr_t addr) ...@@ -494,9 +611,10 @@ int sa1111_check_dma_bug(dma_addr_t addr)
* above the start of the target bank: * above the start of the target bank:
*/ */
if (physaddr<(1<<20)) if (physaddr<(1<<20))
return 0; return 0;
switch (FExtr(SBI_SMCR, SMCR_DRAC)) { smcr = sa1111_readl(sachip->base + SA1111_SMCR);
switch (FExtr(smcr, SMCR_DRAC)) {
case 01: /* 10 row + bank address bits, A<20> must not be set */ case 01: /* 10 row + bank address bits, A<20> must not be set */
if (physaddr & (1<<20)) if (physaddr & (1<<20))
return -1; return -1;
...@@ -523,27 +641,26 @@ int sa1111_check_dma_bug(dma_addr_t addr) ...@@ -523,27 +641,26 @@ int sa1111_check_dma_bug(dma_addr_t addr)
break; break;
default: default:
printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n", printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
__FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC)); __FUNCTION__, FExtr(smcr, SMCR_DRAC));
return -1; return -1;
} }
return 0; return 0;
} }
EXPORT_SYMBOL(sa1111_check_dma_bug); int sa1111_init(unsigned long phys, unsigned int irq)
int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
{ {
unsigned int val;
int ret; int ret;
ret = sa1111_probe(parent, phys); ret = sa1111_probe(phys, irq);
if (ret < 0) if (ret < 0)
return ret; return ret;
/* /*
* We found it. Wake the chip up. * We found it. Wake the chip up.
*/ */
sa1111_wake(); sa1111_wake(g_sa1111);
/* /*
* The SDRAM configuration of the SA1110 and the SA1111 must * The SDRAM configuration of the SA1110 and the SA1111 must
...@@ -552,7 +669,7 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq) ...@@ -552,7 +669,7 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
* MBGNT signal, so we must have called sa1110_mb_disable() * MBGNT signal, so we must have called sa1110_mb_disable()
* beforehand. * beforehand.
*/ */
sa1111_configure_smc(1, sa1111_configure_smc(g_sa1111, 1,
FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), FExtr(MDCNFG, MDCNFG_SA1110_DRAC0),
FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); FExtr(MDCNFG, MDCNFG_SA1110_TDL0));
...@@ -560,7 +677,8 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq) ...@@ -560,7 +677,8 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
* We only need to turn on DCLK whenever we want to use the * We only need to turn on DCLK whenever we want to use the
* DMA. It can otherwise be held firmly in the off position. * DMA. It can otherwise be held firmly in the off position.
*/ */
sa1111_enable_device(SKPCR_DCLKEN); val = sa1111_readl(g_sa1111->base + SA1111_SKPCR);
sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR);
/* /*
* Enable the SA1110 memory bus request and grant signals. * Enable the SA1110 memory bus request and grant signals.
...@@ -570,7 +688,341 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq) ...@@ -570,7 +688,341 @@ int sa1111_init(struct device *parent, unsigned long phys, unsigned int irq)
/* /*
* Initialise SA1111 IRQs * Initialise SA1111 IRQs
*/ */
sa1111_init_irq(irq); int_dev.irq[0] = irq;
sa1111_init_irq(&int_dev);
return 0;
}
struct sa1111_save_data {
unsigned int skcr;
unsigned int skpcr;
unsigned int skcdr;
unsigned char skaud;
unsigned char skpwm0;
unsigned char skpwm1;
/*
* Interrupt controller
*/
unsigned int intpol0;
unsigned int intpol1;
unsigned int inten0;
unsigned int inten1;
unsigned int wakepol0;
unsigned int wakepol1;
unsigned int wakeen0;
unsigned int wakeen1;
};
static int sa1111_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1111 *sachip = dev->driver_data;
unsigned long flags;
char *base;
/*
* Save state.
*/
if (level == SUSPEND_SAVE_STATE ||
level == SUSPEND_DISABLE ||
level == SUSPEND_POWER_DOWN) {
struct sa1111_save_data *save;
if (!dev->saved_state)
dev->saved_state = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!dev->saved_state)
return -ENOMEM;
save = (struct sa1111_save_data *)dev->saved_state;
spin_lock_irqsave(&sachip->lock, flags);
base = sachip->base;
save->skcr = sa1111_readl(base + SA1111_SKCR);
save->skpcr = sa1111_readl(base + SA1111_SKPCR);
save->skcdr = sa1111_readl(base + SA1111_SKCDR);
save->skaud = sa1111_readl(base + SA1111_SKAUD);
save->skpwm0 = sa1111_readl(base + SA1111_SKPWM0);
save->skpwm1 = sa1111_readl(base + SA1111_SKPWM1);
base = sachip->base + SA1111_INTC;
save->intpol0 = sa1111_readl(base + SA1111_INTPOL0);
save->intpol1 = sa1111_readl(base + SA1111_INTPOL1);
save->inten0 = sa1111_readl(base + SA1111_INTEN0);
save->inten1 = sa1111_readl(base + SA1111_INTEN1);
save->wakepol0 = sa1111_readl(base + SA1111_WAKEPOL0);
save->wakepol1 = sa1111_readl(base + SA1111_WAKEPOL1);
save->wakeen0 = sa1111_readl(base + SA1111_WAKEEN0);
save->wakeen1 = sa1111_readl(base + SA1111_WAKEEN1);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/*
* Disable.
*/
if (level == SUSPEND_DISABLE && state == 4) {
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
base = sachip->base;
sa1111_writel(0, base + SA1111_SKPWM0);
sa1111_writel(0, base + SA1111_SKPWM1);
val = sa1111_readl(base + SA1111_SKCR);
sa1111_writel(val | SKCR_SLEEP, base + SA1111_SKCR);
spin_unlock_irqrestore(&sachip->lock, flags);
}
return 0; return 0;
} }
/*
* sa1111_resume - Restore the SA1111 device state.
* @dev: device to restore
* @level: resume level
*
* Restore the general state of the SA1111; clock control and
* interrupt controller. Other parts of the SA1111 must be
* restored by their respective drivers, and must be called
* via LDM after this function.
*/
static int sa1111_resume(struct device *dev, u32 level)
{
struct sa1111 *sachip = dev->driver_data;
struct sa1111_save_data *save;
unsigned long flags, id;
char *base;
if (level != RESUME_RESTORE_STATE && level != RESUME_ENABLE)
return 0;
save = (struct sa1111_save_data *)dev->saved_state;
if (!save)
return 0;
dev->saved_state = NULL;
/*
* Ensure that the SA1111 is still here.
*/
id = sa1111_readl(sachip->base + SA1111_SKID);
if ((id & SKID_ID_MASK) != SKID_SA1111_ID) {
__sa1111_remove(sachip);
kfree(save);
return 0;
}
spin_lock_irqsave(&sachip->lock, flags);
sa1111_wake(sachip);
base = sachip->base;
sa1111_writel(save->skcr, base + SA1111_SKCR);
sa1111_writel(save->skpcr, base + SA1111_SKPCR);
sa1111_writel(save->skcdr, base + SA1111_SKCDR);
sa1111_writel(save->skaud, base + SA1111_SKAUD);
sa1111_writel(save->skpwm0, base + SA1111_SKPWM0);
sa1111_writel(save->skpwm1, base + SA1111_SKPWM1);
base = sachip->base + SA1111_INTC;
sa1111_writel(save->intpol0, base + SA1111_INTPOL0);
sa1111_writel(save->intpol1, base + SA1111_INTPOL1);
sa1111_writel(save->inten0, base + SA1111_INTEN0);
sa1111_writel(save->inten1, base + SA1111_INTEN1);
sa1111_writel(save->wakepol0, base + SA1111_WAKEPOL0);
sa1111_writel(save->wakepol1, base + SA1111_WAKEPOL1);
sa1111_writel(save->wakeen0, base + SA1111_WAKEEN0);
sa1111_writel(save->wakeen1, base + SA1111_WAKEEN1);
spin_unlock_irqrestore(&sachip->lock, flags);
kfree(save);
return 0;
}
static struct device_driver sa1111_device_driver = {
.suspend = sa1111_suspend,
.resume = sa1111_resume,
};
/*
* Get the parent device driver (us) structure
* from a child function device
*/
static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev)
{
return (struct sa1111 *)sadev->dev.parent->driver_data;
}
/*
* The bits in the opdiv field are non-linear.
*/
static unsigned char opdiv_table[] = { 1, 4, 2, 8 };
static unsigned int __sa1111_pll_clock(struct sa1111 *sachip)
{
unsigned int skcdr, fbdiv, ipdiv, opdiv;
skcdr = sa1111_readl(sachip->base + SA1111_SKCDR);
fbdiv = (skcdr & 0x007f) + 2;
ipdiv = ((skcdr & 0x0f80) >> 7) + 2;
opdiv = opdiv_table[(skcdr & 0x3000) >> 12];
return 3686400 * fbdiv / (ipdiv * opdiv);
}
/**
* sa1111_pll_clock - return the current PLL clock frequency.
* @sadev: SA1111 function block
*
* BUG: we should look at SKCR. We also blindly believe that
* the chip is being fed with the 3.6864MHz clock.
*
* Returns the PLL clock in Hz.
*/
unsigned int sa1111_pll_clock(struct sa1111_dev *sadev)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
return __sa1111_pll_clock(sachip);
}
/**
* sa1111_select_audio_mode - select I2S or AC link mode
* @sadev: SA1111 function block
* @mode: One of %SA1111_AUDIO_ACLINK or %SA1111_AUDIO_I2S
*
* Frob the SKCR to select AC Link mode or I2S mode for
* the audio block.
*/
void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
val = sa1111_readl(sachip->base + SA1111_SKCR);
if (mode == SA1111_AUDIO_I2S) {
val &= ~SKCR_SELAC;
} else {
val |= SKCR_SELAC;
}
sa1111_writel(val, sachip->base + SA1111_SKCR);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/**
* sa1111_set_audio_rate - set the audio sample rate
* @sadev: SA1111 SAC function block
* @rate: sample rate to select
*/
int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned int div;
if (sadev->devid != SA1111_DEVID_SAC)
return -EINVAL;
div = (__sa1111_pll_clock(sachip) / 256 + rate / 2) / rate;
if (div == 0)
div = 1;
if (div > 128)
div = 128;
sa1111_writel(div - 1, sachip->base + SA1111_SKAUD);
return 0;
}
/**
* sa1111_get_audio_rate - get the audio sample rate
* @sadev: SA1111 SAC function block device
*/
int sa1111_get_audio_rate(struct sa1111_dev *sadev)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long div;
if (sadev->devid != SA1111_DEVID_SAC)
return -EINVAL;
div = sa1111_readl(sachip->base + SA1111_SKAUD) + 1;
return __sa1111_pll_clock(sachip) / (256 * div);
}
/*
* Individual device operations.
*/
/**
* sa1111_enable_device - enable an on-chip SA1111 function block
* @sadev: SA1111 function block device to enable
*/
void sa1111_enable_device(struct sa1111_dev *sadev)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
val = sa1111_readl(sachip->base + SA1111_SKPCR);
sa1111_writel(val | sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/**
* sa1111_disable_device - disable an on-chip SA1111 function block
* @sadev: SA1111 function block device to disable
*/
void sa1111_disable_device(struct sa1111_dev *sadev)
{
struct sa1111 *sachip = sa1111_chip_driver(sadev);
unsigned long flags;
unsigned int val;
spin_lock_irqsave(&sachip->lock, flags);
val = sa1111_readl(sachip->base + SA1111_SKPCR);
sa1111_writel(val & ~sadev->skpcr_mask, sachip->base + SA1111_SKPCR);
spin_unlock_irqrestore(&sachip->lock, flags);
}
/*
* SA1111 "Register Access Bus."
*
* We model this as a regular bus type, and hang devices directly
* off this.
*/
static int sa1111_match(struct device *_dev, struct device_driver *_drv)
{
struct sa1111_dev *dev = SA1111_DEV(_dev);
struct sa1111_driver *drv = SA1111_DRV(_drv);
return dev->devid == drv->devid;
}
struct bus_type sa1111_bus_type = {
.name = "RAB",
.match = sa1111_match,
};
static int sa1111_rab_bus_init(void)
{
return bus_register(&sa1111_bus_type);
}
postcore_initcall(sa1111_rab_bus_init);
EXPORT_SYMBOL(sa1111_check_dma_bug);
EXPORT_SYMBOL(sa1111_select_audio_mode);
EXPORT_SYMBOL(sa1111_set_audio_rate);
EXPORT_SYMBOL(sa1111_get_audio_rate);
EXPORT_SYMBOL(sa1111_enable_device);
EXPORT_SYMBOL(sa1111_disable_device);
EXPORT_SYMBOL(sa1111_pll_clock);
EXPORT_SYMBOL(sa1111_bus_type);
/*
* linux/arch/arm/mach-sa1100/sa1111.h
*/
struct device;
/*
* Probe for a SA1111 chip.
*/
extern int
sa1111_init(struct device *parent, unsigned long phys, unsigned int irq);
/*
* Wake up a SA1111 chip.
*/
extern void sa1111_wake(void);
/*
* Doze the SA1111 chip.
*/
extern void sa1111_doze(void);
...@@ -284,6 +284,17 @@ storkInitTSandDtoA(void) ...@@ -284,6 +284,17 @@ storkInitTSandDtoA(void)
storkClockShortToDtoA(0x0A00); /* turn on the brightness */ storkClockShortToDtoA(0x0A00); /* turn on the brightness */
} }
static void stork_lcd_power(int on)
{
if (on) {
storkSetLCDCPLD(0, 1);
storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
} else {
storkSetLCDCPLD(0, 0);
storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
}
}
struct map_desc stork_io_desc[] __initdata = { struct map_desc stork_io_desc[] __initdata = {
/* virtual physical length type */ /* virtual physical length type */
{ STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, MT_DEVICE }, /* EGPIO 0 */ { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, MT_DEVICE }, /* EGPIO 0 */
...@@ -312,6 +323,8 @@ stork_map_io(void) ...@@ -312,6 +323,8 @@ stork_map_io(void)
storkInitTSandDtoA(); storkInitTSandDtoA();
sa1100fb_lcd_power = stork_lcd_power;
return 0; return 0;
} }
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include "generic.h" #include "generic.h"
#include "sa1111.h"
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#define DEBUG 1 #define DEBUG 1
...@@ -401,7 +400,7 @@ static int __init system3_init(void) ...@@ -401,7 +400,7 @@ static int __init system3_init(void)
/* /*
* Probe for a SA1111. * Probe for a SA1111.
*/ */
ret = sa1111_init(NULL, PT_SA1111_BASE, IRQ_SYSTEM3_SA1111); ret = sa1111_init(PT_SA1111_BASE, IRQ_SYSTEM3_SA1111);
if (ret < 0) { if (ret < 0) {
printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
goto DONE; goto DONE;
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#else #else
/* /*
* "code" is actually the FSR register. Bit 11 set means the * "code" is actually the FSR register. Bit 11 set means the
* isntruction was performing a write. * instruction was performing a write.
*/ */
#define DO_COW(code) ((code) & (1 << 11)) #define DO_COW(code) ((code) & (1 << 11))
#define READ_FAULT(code) (!DO_COW(code)) #define READ_FAULT(code) (!DO_COW(code))
...@@ -54,7 +54,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr) ...@@ -54,7 +54,7 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
printk(KERN_ALERT "pgd = %p\n", mm->pgd); printk(KERN_ALERT "pgd = %p\n", mm->pgd);
pgd = pgd_offset(mm, addr); pgd = pgd_offset(mm, addr);
printk(KERN_ALERT "*pgd=%08lx", pgd_val(*pgd)); printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd));
do { do {
pmd_t *pmd; pmd_t *pmd;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# To add an entry into this database, please see Documentation/arm/README, # To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk # or contact rmk@arm.linux.org.uk
# #
# Last update: Sat Jul 27 09:56:53 2002 # Last update: Sat Sep 21 13:39:13 2002
# #
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
# #
...@@ -214,3 +214,31 @@ emailphone SA1100_EMAILPHONE EMAILPHONE 202 ...@@ -214,3 +214,31 @@ emailphone SA1100_EMAILPHONE EMAILPHONE 202
h3900 ARCH_H3900 H3900 203 h3900 ARCH_H3900 H3900 203
pxa1 ARCH_PXA1 PXA1 204 pxa1 ARCH_PXA1 PXA1 204
koan369 SA1100_KOAN369 KOAN369 205 koan369 SA1100_KOAN369 KOAN369 205
cogent ARCH_COGENT COGENT 206
esl_simputer ARCH_ESL_SIMPUTER ESL_SIMPUTER 207
esl_simputer_clr ARCH_ESL_SIMPUTER_CLR ESL_SIMPUTER_CLR 208
esl_simputer_bw ARCH_ESL_SIMPUTER_BW ESL_SIMPUTER_BW 209
hhp_cradle ARCH_HHP_CRADLE HHP_CRADLE 210
he500 ARCH_HE500 HE500 211
inhandelf2 SA1100_INHANDELF2 INHANDELF2 212
inhandftip SA1100_INHANDFTIP INHANDFTIP 213
dnp1110 SA1100_DNP1110 DNP1110 214
pnp1110 SA1100_PNP1110 PNP1110 215
csb226 ARCH_CSB226 CSB226 216
arnold SA1100_ARNOLD ARNOLD 217
psiboard SA1100_PSIBOARD PSIBOARD 218
jz8028 ARCH_JZ8028 JZ8028 219
ipaq3 ARCH_IPAQ3 IPAQ3 220
forte SA1100_FORTE FORTE 221
acam SA1100_ACAM ACAM 222
abox SA1100_ABOX ABOX 223
atmel ARCH_ATMEL ATMEL 224
sitsang ARCH_SITSANG SITSANG 225
cpu1110lcdnet SA1100_CPU1110LCDNET CPU1110LCDNET 226
mpl_vcma9 ARCH_MPL_VCMA9 MPL_VCMA9 227
opus_a1 ARCH_OPUS_A1 OPUS_A1 228
daytona ARCH_DAYTONA DAYTONA 229
killbear SA1100_KILLBEAR KILLBEAR 230
yoho ARCH_YOHO YOHO 231
jasper ARCH_JASPER JASPER 232
dsc25 ARCH_DSC25 DSC25 233
...@@ -15,20 +15,26 @@ ...@@ -15,20 +15,26 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/hardware/sa1111.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/hardware/sa1111.h>
extern struct pt_regs *kbd_pt_regs; extern struct pt_regs *kbd_pt_regs;
struct ps2if { struct ps2if {
struct serio io; struct serio io;
struct resource *res; struct sa1111_dev *dev;
unsigned long base; unsigned long base;
unsigned int irq; unsigned int open;
unsigned int skpcr_mask; spinlock_t lock;
unsigned int head;
unsigned int tail;
unsigned char buf[4];
}; };
/* /*
...@@ -36,104 +42,150 @@ struct ps2if { ...@@ -36,104 +42,150 @@ struct ps2if {
* at the most one, but we loop for safety. If there was a * at the most one, but we loop for safety. If there was a
* framing error, we have to manually clear the status. * framing error, we have to manually clear the status.
*/ */
static void ps2_int(int irq, void *dev_id, struct pt_regs *regs) static void ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct ps2if *sa = dev_id; struct ps2if *ps2if = dev_id;
unsigned int scancode, flag, status; unsigned int scancode, flag, status;
kbd_pt_regs = regs; kbd_pt_regs = regs;
status = sa1111_readl(sa->base + SA1111_PS2STAT); status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
while (status & PS2STAT_RXF) { while (status & PS2STAT_RXF) {
if (status & PS2STAT_STP) if (status & PS2STAT_STP)
sa1111_writel(PS2STAT_STP, sa->base + SA1111_PS2STAT); sa1111_writel(PS2STAT_STP, ps2if->base + SA1111_PS2STAT);
flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) | flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
(status & PS2STAT_RXP ? 0 : SERIO_PARITY); (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
scancode = sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff; scancode = sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff;
if (hweight8(scancode) & 1) if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY; flag ^= SERIO_PARITY;
serio_interrupt(&sa->io, scancode, flag); serio_interrupt(&ps2if->io, scancode, flag);
status = sa1111_readl(sa->base + SA1111_PS2STAT); status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
} }
} }
/*
* Completion of ps2 write
*/
static void ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
{
struct ps2if *ps2if = dev_id;
unsigned int status;
spin_lock(&ps2if->lock);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
if (ps2if->head == ps2if->tail) {
disable_irq(irq);
/* done */
} else if (status & PS2STAT_TXE) {
sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + SA1111_PS2DATA);
ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
}
spin_unlock(&ps2if->lock);
}
/* /*
* Write a byte to the PS2 port. We have to wait for the * Write a byte to the PS2 port. We have to wait for the
* port to indicate that the transmitter is empty. * port to indicate that the transmitter is empty.
*/ */
static int ps2_write(struct serio *io, unsigned char val) static int ps2_write(struct serio *io, unsigned char val)
{ {
struct ps2if *sa = io->driver; struct ps2if *ps2if = io->driver;
unsigned int timeleft = 10000; /* timeout in 100ms */ unsigned long flags;
unsigned int head;
while ((sa1111_readl(sa->base + SA1111_PS2STAT) & PS2STAT_TXE) == 0 && spin_lock_irqsave(&ps2if->lock, flags);
timeleft--)
udelay(10);
if (timeleft) /*
sa1111_writel(val, sa->base + SA1111_PS2DATA); * If the TX register is empty, we can go straight out.
*/
if (sa1111_readl(ps2if->base + SA1111_PS2STAT) & PS2STAT_TXE) {
sa1111_writel(val, ps2if->base + SA1111_PS2DATA);
} else {
if (ps2if->head == ps2if->tail)
enable_irq(ps2if->dev->irq[1]);
head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
if (head != ps2if->tail) {
ps2if->buf[ps2if->head] = val;
ps2if->head = head;
}
}
return timeleft ? 0 : SERIO_TIMEOUT; spin_unlock_irqrestore(&ps2if->lock, flags);
return 0;
} }
static int ps2_open(struct serio *io) static int ps2_open(struct serio *io)
{ {
struct ps2if *sa = io->driver; struct ps2if *ps2if = io->driver;
int ret; int ret;
sa1111_enable_device(sa->skpcr_mask); sa1111_enable_device(ps2if->dev);
ret = request_irq(sa->irq, ps2_int, 0, "ps2", sa); ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
SA1111_DRIVER_NAME(ps2if->dev), ps2if);
if (ret) { if (ret) {
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n", printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
sa->irq, ret); ps2if->dev->irq[0], ret);
return ret; return ret;
} }
sa1111_writel(PS2CR_ENA, sa->base + SA1111_PS2CR); ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
SA1111_DRIVER_NAME(ps2if->dev), ps2if);
if (ret) {
printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
ps2if->dev->irq[1], ret);
free_irq(ps2if->dev->irq[0], ps2if);
return ret;
}
ps2if->open = 1;
sa1111_writel(PS2CR_ENA, ps2if->base + SA1111_PS2CR);
return 0; return 0;
} }
static void ps2_close(struct serio *io) static void ps2_close(struct serio *io)
{ {
struct ps2if *sa = io->driver; struct ps2if *ps2if = io->driver;
sa1111_writel(0, ps2if->base + SA1111_PS2CR);
sa1111_writel(0, sa->base + SA1111_PS2CR); ps2if->open = 0;
free_irq(sa->irq, sa); free_irq(ps2if->dev->irq[1], ps2if);
free_irq(ps2if->dev->irq[0], ps2if);
sa1111_disable_device(sa->skpcr_mask); sa1111_disable_device(ps2if->dev);
} }
/* /*
* Clear the input buffer. * Clear the input buffer.
*/ */
static void __init ps2_clear_input(struct ps2if *sa) static void __init ps2_clear_input(struct ps2if *ps2if)
{ {
int maxread = 100; int maxread = 100;
while (maxread--) { while (maxread--) {
if ((sa1111_readl(sa->base + SA1111_PS2DATA) & 0xff) == 0xff) if ((sa1111_readl(ps2if->base + SA1111_PS2DATA) & 0xff) == 0xff)
break; break;
} }
} }
static inline unsigned int static inline unsigned int
ps2_test_one(struct ps2if *sa, unsigned int mask) ps2_test_one(struct ps2if *ps2if, unsigned int mask)
{ {
unsigned int val; unsigned int val;
sa1111_writel(PS2CR_ENA | mask, sa->base + SA1111_PS2CR); sa1111_writel(PS2CR_ENA | mask, ps2if->base + SA1111_PS2CR);
udelay(2); udelay(2);
val = sa1111_readl(sa->base + SA1111_PS2STAT); val = sa1111_readl(ps2if->base + SA1111_PS2STAT);
return val & (PS2STAT_KBC | PS2STAT_KBD); return val & (PS2STAT_KBC | PS2STAT_KBD);
} }
...@@ -141,141 +193,168 @@ ps2_test_one(struct ps2if *sa, unsigned int mask) ...@@ -141,141 +193,168 @@ ps2_test_one(struct ps2if *sa, unsigned int mask)
* Test the keyboard interface. We basically check to make sure that * Test the keyboard interface. We basically check to make sure that
* we can drive each line to the keyboard independently of each other. * we can drive each line to the keyboard independently of each other.
*/ */
static int __init ps2_test(struct ps2if *sa) static int __init ps2_test(struct ps2if *ps2if)
{ {
unsigned int stat; unsigned int stat;
int ret = 0; int ret = 0;
stat = ps2_test_one(sa, PS2CR_FKC); stat = ps2_test_one(ps2if, PS2CR_FKC);
if (stat != PS2STAT_KBD) { if (stat != PS2STAT_KBD) {
printk("Keyboard interface test failed[1]: %02x\n", stat); printk("PS/2 interface test failed[1]: %02x\n", stat);
ret = -ENODEV; ret = -ENODEV;
} }
stat = ps2_test_one(sa, 0); stat = ps2_test_one(ps2if, 0);
if (stat != (PS2STAT_KBC | PS2STAT_KBD)) { if (stat != (PS2STAT_KBC | PS2STAT_KBD)) {
printk("Keyboard interface test failed[2]: %02x\n", stat); printk("PS/2 interface test failed[2]: %02x\n", stat);
ret = -ENODEV; ret = -ENODEV;
} }
stat = ps2_test_one(sa, PS2CR_FKD); stat = ps2_test_one(ps2if, PS2CR_FKD);
if (stat != PS2STAT_KBC) { if (stat != PS2STAT_KBC) {
printk("Keyboard interface test failed[3]: %02x\n", stat); printk("PS/2 interface test failed[3]: %02x\n", stat);
ret = -ENODEV; ret = -ENODEV;
} }
sa1111_writel(0, sa->base + SA1111_PS2CR); sa1111_writel(0, ps2if->base + SA1111_PS2CR);
return ret; return ret;
} }
/* /*
* Initialise one PS/2 port. * Add one device to this driver.
*/ */
static int __init ps2_init_one(struct sa1111_device *dev, struct ps2if *sa) static int ps2_probe(struct device *dev)
{ {
struct sa1111_dev *sadev = SA1111_DEV(dev);
struct ps2if *ps2if;
int ret; int ret;
ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
if (!ps2if) {
return -ENOMEM;
}
memset(ps2if, 0, sizeof(struct ps2if));
ps2if->io.type = SERIO_8042;
ps2if->io.write = ps2_write;
ps2if->io.open = ps2_open;
ps2if->io.close = ps2_close;
ps2if->io.name = dev->name;
ps2if->io.phys = dev->bus_id;
ps2if->io.driver = ps2if;
ps2if->dev = sadev;
dev->driver_data = ps2if;
spin_lock_init(&ps2if->lock);
/* /*
* Request the physical region for this PS2 port. * Request the physical region for this PS2 port.
*/ */
sa->res = request_mem_region(_SA1111(sa->base), 512, "ps2"); if (!request_mem_region(sadev->res.start,
if (!sa->res) sadev->res.end - sadev->res.start + 1,
return -EBUSY; SA1111_DRIVER_NAME(sadev))) {
ret = -EBUSY;
goto free;
}
/* /*
* Convert the chip offset to virtual address. * Our parent device has already mapped the region.
*/ */
sa->base += (unsigned long)dev->base; ps2if->base = (unsigned long)sadev->mapbase;
sa1111_enable_device(sa->skpcr_mask); sa1111_enable_device(ps2if->dev);
/* Incoming clock is 8MHz */ /* Incoming clock is 8MHz */
sa1111_writel(0, sa->base + SA1111_PS2CLKDIV); sa1111_writel(0, ps2if->base + SA1111_PS2CLKDIV);
sa1111_writel(127, sa->base + SA1111_PS2PRECNT); sa1111_writel(127, ps2if->base + SA1111_PS2PRECNT);
/* /*
* Flush any pending input. * Flush any pending input.
*/ */
ps2_clear_input(sa); ps2_clear_input(ps2if);
/* /*
* Test the keyboard interface. * Test the keyboard interface.
*/ */
ret = ps2_test(sa); ret = ps2_test(ps2if);
if (ret) if (ret)
goto out; goto out;
/* /*
* Flush any pending input. * Flush any pending input.
*/ */
ps2_clear_input(sa); ps2_clear_input(ps2if);
sa1111_disable_device(sa->skpcr_mask);
serio_register_port(&sa->io); sa1111_disable_device(ps2if->dev);
serio_register_port(&ps2if->io);
return 0; return 0;
out: out:
sa1111_disable_device(sa->skpcr_mask); sa1111_disable_device(ps2if->dev);
release_resource(sa->res); release_mem_region(sadev->res.start,
sadev->res.end - sadev->res.start + 1);
free:
dev->driver_data = NULL;
kfree(ps2if);
return ret; return ret;
} }
/* /*
* Remove one PS/2 port. * Remove one device from this driver.
*/ */
static void __exit ps2_remove_one(struct ps2if *sa) static int ps2_remove(struct device *dev)
{ {
serio_unregister_port(&sa->io); struct ps2if *ps2if = dev->driver_data;
release_resource(sa->res); struct sa1111_dev *sadev = SA1111_DEV(dev);
serio_unregister_port(&ps2if->io);
release_mem_region(sadev->res.start,
sadev->res.end - sadev->res.start + 1);
kfree(ps2if);
dev->driver_data = NULL;
return 0;
} }
static struct ps2if ps2_kbd_port = /*
* We should probably do something here, but what?
*/
static int ps2_suspend(struct device *dev, u32 state, u32 level)
{ {
io: { return 0;
type: SERIO_8042, }
write: ps2_write,
open: ps2_open,
close: ps2_close,
name: "SA1111 PS/2 kbd port",
phys: "sa1111/serio0",
driver: &ps2_kbd_port,
},
base: SA1111_KBD,
irq: IRQ_TPRXINT,
skpcr_mask: SKPCR_PTCLKEN,
};
static struct ps2if ps2_mse_port = static int ps2_resume(struct device *dev, u32 level)
{ {
io: { return 0;
type: SERIO_8042, }
write: ps2_write,
open: ps2_open, /*
close: ps2_close, * Our device driver structure
name: "SA1111 PS/2 mouse port", */
phys: "sa1111/serio1", static struct sa1111_driver ps2_driver = {
driver: &ps2_mse_port, .drv = {
.name = "SA1111 PS2",
.bus = &sa1111_bus_type,
.probe = ps2_probe,
.remove = ps2_remove,
.suspend = ps2_suspend,
.resume = ps2_resume,
}, },
base: SA1111_MSE, .devid = SA1111_DEVID_PS2,
irq: IRQ_MSRXINT,
skpcr_mask: SKPCR_PMCLKEN,
}; };
static int __init ps2_init(void) static int __init ps2_init(void)
{ {
int ret = -ENODEV; return driver_register(&ps2_driver.drv);
if (sa1111) {
ret = ps2_init_one(sa1111, &ps2_kbd_port);
}
return ret;
} }
static void __exit ps2_exit(void) static void __exit ps2_exit(void)
{ {
ps2_remove_one(&ps2_kbd_port); remove_driver(&ps2_driver.drv);
} }
module_init(ps2_init); module_init(ps2_init);
......
...@@ -20,6 +20,7 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then ...@@ -20,6 +20,7 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
fi fi
if [ "$CONFIG_ARM" = "y" ]; then if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
dep_tristate ' SA1111 support' CONFIG_PCMCIA_SA1111 $CONFIG_PCMCIA_SA1100 $CONFIG_SA1111 $CONFIG_PCMCIA
fi fi
fi fi
......
...@@ -14,6 +14,7 @@ obj-$(CONFIG_I82092) += i82092.o ...@@ -14,6 +14,7 @@ obj-$(CONFIG_I82092) += i82092.o
obj-$(CONFIG_TCIC) += tcic.o obj-$(CONFIG_TCIC) += tcic.o
obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
obj-$(CONFIG_PCMCIA_SA1111) += sa1111_cs.o
yenta_socket-objs := pci_socket.o yenta.o yenta_socket-objs := pci_socket.o yenta.o
...@@ -21,26 +22,29 @@ pcmcia_core-objs-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o ...@@ -21,26 +22,29 @@ pcmcia_core-objs-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o
pcmcia_core-objs-$(CONFIG_CARDBUS) += cardbus.o pcmcia_core-objs-$(CONFIG_CARDBUS) += cardbus.o
pcmcia_core-objs := $(pcmcia_core-objs-y) pcmcia_core-objs := $(pcmcia_core-objs-y)
sa1111_cs-objs-y := sa1111_generic.o
sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o
sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o
sa1111_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o
sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o
sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o
sa1111_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o
sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o
sa1111_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o
sa1111_cs-objs := $(sa1111_cs-objs-y)
sa1100_cs-objs-y := sa1100_generic.o sa1100_cs-objs-y := sa1100_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o
sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o
sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o
sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o
sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o
sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o
sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o
sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o
sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
sa1100_cs-objs := $(sa1100_cs-objs-y) sa1100_cs-objs := $(sa1100_cs-objs-y)
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
#include "sa1111_generic.h" #include "sa1111_generic.h"
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/arch/badge4.h> #include <asm/arch/badge4.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
......
...@@ -110,12 +110,11 @@ sa1100_pcmcia_default_mecr_timing(unsigned int sock, unsigned int cpu_speed, ...@@ -110,12 +110,11 @@ sa1100_pcmcia_default_mecr_timing(unsigned int sock, unsigned int cpu_speed,
* Call board specific BS value calculation to allow boards * Call board specific BS value calculation to allow boards
* to tweak the BS values. * to tweak the BS values.
*/ */
static int sa1100_pcmcia_set_mecr(int sock) static int sa1100_pcmcia_set_mecr(int sock, unsigned int cpu_clock)
{ {
struct sa1100_pcmcia_socket *skt; struct sa1100_pcmcia_socket *skt;
u32 mecr; u32 mecr;
int clock; unsigned long flags;
long flags;
unsigned int bs; unsigned int bs;
if (sock < 0 || sock > SA1100_PCMCIA_MAX_SOCK) if (sock < 0 || sock > SA1100_PCMCIA_MAX_SOCK)
...@@ -125,8 +124,7 @@ static int sa1100_pcmcia_set_mecr(int sock) ...@@ -125,8 +124,7 @@ static int sa1100_pcmcia_set_mecr(int sock)
local_irq_save(flags); local_irq_save(flags);
clock = cpufreq_get(0); bs = pcmcia_low_level->socket_get_timing(sock, cpu_clock, skt->speed_io);
bs = pcmcia_low_level->socket_get_timing(sock, clock, skt->speed_io);
mecr = MECR; mecr = MECR;
MECR_FAST_SET(mecr, sock, 0); MECR_FAST_SET(mecr, sock, 0);
...@@ -652,7 +650,7 @@ sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) ...@@ -652,7 +650,7 @@ sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
if ( map->speed == 0) if ( map->speed == 0)
map->speed = SA1100_PCMCIA_IO_ACCESS; map->speed = SA1100_PCMCIA_IO_ACCESS;
sa1100_pcmcia_set_mecr( sock ); sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
} }
if (map->stop == 1) if (map->stop == 1)
...@@ -741,7 +739,7 @@ sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) ...@@ -741,7 +739,7 @@ sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
map->speed = SA1100_PCMCIA_5V_MEM_ACCESS; map->speed = SA1100_PCMCIA_5V_MEM_ACCESS;
} }
sa1100_pcmcia_set_mecr( sock ); sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
} }
...@@ -885,9 +883,8 @@ static void sa1100_pcmcia_update_mecr(unsigned int clock) ...@@ -885,9 +883,8 @@ static void sa1100_pcmcia_update_mecr(unsigned int clock)
{ {
unsigned int sock; unsigned int sock;
for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock)
sa1100_pcmcia_set_mecr(sock); sa1100_pcmcia_set_mecr(sock, clock);
}
} }
/* sa1100_pcmcia_notifier() /* sa1100_pcmcia_notifier()
...@@ -904,31 +901,31 @@ static int ...@@ -904,31 +901,31 @@ static int
sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
void *data) void *data)
{ {
struct cpufreq_info *ci = data; struct cpufreq_freqs *freqs = data;
switch (val) { switch (val) {
case CPUFREQ_PRECHANGE: case CPUFREQ_PRECHANGE:
if (ci->new_freq > ci->old_freq) { if (freqs->new > freqs->old) {
DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n", DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
__FUNCTION__, "pre-updating\n", __FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10, freqs->new / 1000, (freqs->new / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10); freqs->old / 1000, (freqs->old / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq); sa1100_pcmcia_update_mecr(freqs->new);
} }
break; break;
case CPUFREQ_POSTCHANGE: case CPUFREQ_POSTCHANGE:
if (ci->new_freq < ci->old_freq) { if (freqs->new < freqs->old) {
DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n", DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
__FUNCTION__, "post-updating\n", __FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10, freqs->new / 1000, (freqs->new / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10); freqs->old / 1000, (freqs->old / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq); sa1100_pcmcia_update_mecr(freqs->new);
} }
break; break;
} }
return 0; return 0;
} }
static struct notifier_block sa1100_pcmcia_notifier_block = { static struct notifier_block sa1100_pcmcia_notifier_block = {
...@@ -946,7 +943,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops) ...@@ -946,7 +943,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
struct pcmcia_init pcmcia_init; struct pcmcia_init pcmcia_init;
struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
struct pcmcia_state_array state_array; struct pcmcia_state_array state_array;
unsigned int i; unsigned int i, cpu_clock;
int ret; int ret;
/* /*
...@@ -986,6 +983,8 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops) ...@@ -986,6 +983,8 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
goto shutdown; goto shutdown;
} }
cpu_clock = cpufreq_get(0);
/* /*
* We initialize the MECR to default values here, because we are * We initialize the MECR to default values here, because we are
* not guaranteed to see a SetIOMap operation at runtime. * not guaranteed to see a SetIOMap operation at runtime.
...@@ -1019,7 +1018,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops) ...@@ -1019,7 +1018,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
goto out_err; goto out_err;
} }
sa1100_pcmcia_set_mecr( i ); sa1100_pcmcia_set_mecr(i, cpu_clock);
} }
...@@ -1110,7 +1109,7 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1110,7 +1109,7 @@ static int __init sa1100_pcmcia_init(void)
servinfo_t info; servinfo_t info;
int ret, i; int ret, i;
printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); printk(KERN_INFO "SA11x0 PCMCIA (CS release %s)\n", CS_RELEASE);
CardServices(GetCardServicesInfo, &info); CardServices(GetCardServicesInfo, &info);
if (info.Revision != CS_RELEASE_CODE) { if (info.Revision != CS_RELEASE_CODE) {
...@@ -1127,7 +1126,8 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1127,7 +1126,8 @@ static int __init sa1100_pcmcia_init(void)
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block); ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "Unable to register CPU frequency change " printk(KERN_ERR "Unable to register CPU frequency change "
"notifier (%d)\n", ret); "notifier (%d)\n", ret);
...@@ -1135,15 +1135,9 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1135,15 +1135,9 @@ static int __init sa1100_pcmcia_init(void)
} }
#endif #endif
#ifdef CONFIG_SA1100_ADSBITSY
pcmcia_adsbitsy_init();
#endif
#ifdef CONFIG_SA1100_ASSABET #ifdef CONFIG_SA1100_ASSABET
pcmcia_assabet_init(); pcmcia_assabet_init();
#endif #endif
#ifdef CONFIG_SA1100_BADGE4
pcmcia_badge4_init();
#endif
#ifdef CONFIG_SA1100_CERF #ifdef CONFIG_SA1100_CERF
pcmcia_cerf_init(); pcmcia_cerf_init();
#endif #endif
...@@ -1156,24 +1150,9 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1156,24 +1150,9 @@ static int __init sa1100_pcmcia_init(void)
#ifdef CONFIG_SA1100_GRAPHICSCLIENT #ifdef CONFIG_SA1100_GRAPHICSCLIENT
pcmcia_gcplus_init(); pcmcia_gcplus_init();
#endif #endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
pcmcia_graphicsmaster_init();
#endif
#ifdef CONFIG_SA1100_JORNADA720
pcmcia_jornada720_init();
#endif
#ifdef CONFIG_ASSABET_NEPONSET
pcmcia_neponset_init();
#endif
#ifdef CONFIG_SA1100_PANGOLIN #ifdef CONFIG_SA1100_PANGOLIN
pcmcia_pangolin_init(); pcmcia_pangolin_init();
#endif #endif
#ifdef CONFIG_SA1100_PFS168
pcmcia_pfs_init();
#endif
#ifdef CONFIG_SA1100_PT_SYSTEM3
pcmcia_system3_init();
#endif
#ifdef CONFIG_SA1100_SHANNON #ifdef CONFIG_SA1100_SHANNON
pcmcia_shannon_init(); pcmcia_shannon_init();
#endif #endif
...@@ -1186,9 +1165,6 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1186,9 +1165,6 @@ static int __init sa1100_pcmcia_init(void)
#ifdef CONFIG_SA1100_TRIZEPS #ifdef CONFIG_SA1100_TRIZEPS
pcmcia_trizeps_init(); pcmcia_trizeps_init();
#endif #endif
#ifdef CONFIG_SA1100_XP860
pcmcia_xp860_init();
#endif
#ifdef CONFIG_SA1100_YOPY #ifdef CONFIG_SA1100_YOPY
pcmcia_yopy_init(); pcmcia_yopy_init();
#endif #endif
...@@ -1203,15 +1179,9 @@ static int __init sa1100_pcmcia_init(void) ...@@ -1203,15 +1179,9 @@ static int __init sa1100_pcmcia_init(void)
*/ */
static void __exit sa1100_pcmcia_exit(void) static void __exit sa1100_pcmcia_exit(void)
{ {
#ifdef CONFIG_SA1100_ADSBITSY
pcmcia_adsbitsy_exit();
#endif
#ifdef CONFIG_SA1100_ASSABET #ifdef CONFIG_SA1100_ASSABET
pcmcia_assabet_exit(); pcmcia_assabet_exit();
#endif #endif
#ifdef CONFIG_SA1100_BADGE4
pcmcia_badge4_exit();
#endif
#ifdef CONFIG_SA1100_CERF #ifdef CONFIG_SA1100_CERF
pcmcia_cerf_exit(); pcmcia_cerf_exit();
#endif #endif
...@@ -1224,21 +1194,9 @@ static void __exit sa1100_pcmcia_exit(void) ...@@ -1224,21 +1194,9 @@ static void __exit sa1100_pcmcia_exit(void)
#ifdef CONFIG_SA1100_GRAPHICSCLIENT #ifdef CONFIG_SA1100_GRAPHICSCLIENT
pcmcia_gcplus_exit(); pcmcia_gcplus_exit();
#endif #endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
pcmcia_graphicsmaster_exit();
#endif
#ifdef CONFIG_SA1100_JORNADA720
pcmcia_jornada720_exit();
#endif
#ifdef CONFIG_ASSABET_NEPONSET
pcmcia_neponset_exit();
#endif
#ifdef CONFIG_SA1100_PANGOLIN #ifdef CONFIG_SA1100_PANGOLIN
pcmcia_pangolin_exit(); pcmcia_pangolin_exit();
#endif #endif
#ifdef CONFIG_SA1100_PFS168
pcmcia_pfs_exit();
#endif
#ifdef CONFIG_SA1100_SHANNON #ifdef CONFIG_SA1100_SHANNON
pcmcia_shannon_exit(); pcmcia_shannon_exit();
#endif #endif
...@@ -1248,9 +1206,6 @@ static void __exit sa1100_pcmcia_exit(void) ...@@ -1248,9 +1206,6 @@ static void __exit sa1100_pcmcia_exit(void)
#ifdef CONFIG_SA1100_STORK #ifdef CONFIG_SA1100_STORK
pcmcia_stork_exit(); pcmcia_stork_exit();
#endif #endif
#ifdef CONFIG_SA1100_XP860
pcmcia_xp860_exit();
#endif
#ifdef CONFIG_SA1100_YOPY #ifdef CONFIG_SA1100_YOPY
pcmcia_yopy_exit(); pcmcia_yopy_exit();
#endif #endif
...@@ -1261,7 +1216,7 @@ static void __exit sa1100_pcmcia_exit(void) ...@@ -1261,7 +1216,7 @@ static void __exit sa1100_pcmcia_exit(void)
} }
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block); cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
#endif #endif
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
#include "sa1111_generic.h" #include "sa1111_generic.h"
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
#include "sa1111_generic.h" #include "sa1111_generic.h"
......
...@@ -10,21 +10,50 @@ ...@@ -10,21 +10,50 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/arch/assabet.h> #include <asm/mach-types.h>
#include <asm/arch/neponset.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
#include "sa1111_generic.h" #include "sa1111_generic.h"
/*
* Neponset uses the Maxim MAX1600, with the following connections:
*
* MAX1600 Neponset
*
* A0VCC SA-1111 GPIO A<1>
* A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
* A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
* B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
* B1VPP ground (slot B is CF)
*
* VX VCC (5V)
* VY VCC3_3 (3.3V)
* 12INA 12V
* 12INB ground (slot B is CF)
*
* The MAX1600 CODE pin is tied to ground, placing the device in
* "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
*/
static int neponset_pcmcia_init(struct pcmcia_init *init) static int neponset_pcmcia_init(struct pcmcia_init *init)
{ {
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* MAX1600 to standby mode: */
PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
/*
* Set GPIO_A<3:0> to be outputs for the MAX1600,
* and switch to standby mode.
*/
PA_DDR = 0;
PA_SDR = 0;
PA_DWR = 0;
PA_SSR = 0;
return sa1111_pcmcia_init(init); return sa1111_pcmcia_init(init);
} }
...@@ -35,29 +64,6 @@ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf) ...@@ -35,29 +64,6 @@ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
unsigned int ncr_set, pa_dwr_set; unsigned int ncr_set, pa_dwr_set;
int ret; int ret;
/* Neponset uses the Maxim MAX1600, with the following connections:
* MAX1600 Neponset
*
* A0VCC SA-1111 GPIO A<1>
* A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
* A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
* B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
* B1VPP ground (slot B is CF)
*
* VX VCC (5V)
* VY VCC3_3 (3.3V)
* 12INA 12V
* 12INB ground (slot B is CF)
*
* The MAX1600 CODE pin is tied to ground, placing the device in
* "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
*/
switch (conf->sock) { switch (conf->sock) {
case 0: case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
...@@ -135,13 +141,13 @@ int __init pcmcia_neponset_init(void) ...@@ -135,13 +141,13 @@ int __init pcmcia_neponset_init(void)
{ {
int ret = -ENODEV; int ret = -ENODEV;
if (machine_is_assabet() && sa1111) if (machine_is_assabet())
ret = sa1100_register_pcmcia(&neponset_pcmcia_ops); ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
return ret; return ret;
} }
void __exit pcmcia_neponset_exit(void) void __devexit pcmcia_neponset_exit(void)
{ {
sa1100_unregister_pcmcia(&neponset_pcmcia_ops); sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
} }
...@@ -7,10 +7,11 @@ ...@@ -7,10 +7,11 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h> #include <asm/irq.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h>
#include <asm/irq.h> #include <asm/irq.h>
#include "sa1100_generic.h" #include "sa1100_generic.h"
......
...@@ -5,10 +5,12 @@ ...@@ -5,10 +5,12 @@
* basically means we handle everything except controlling the * basically means we handle everything except controlling the
* power. Power is machine specific... * power. Power is machine specific...
*/ */
#include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/hardware/sa1111.h> #include <asm/hardware/sa1111.h>
...@@ -21,19 +23,18 @@ static struct irqs { ...@@ -21,19 +23,18 @@ static struct irqs {
int irq; int irq;
const char *str; const char *str;
} irqs[] = { } irqs[] = {
{ S0_CD_VALID, "SA1111 PCMCIA card detect" }, { IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" },
{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, { IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" },
{ S1_CD_VALID, "SA1111 CF card detect" }, { IRQ_S1_CD_VALID, "SA1111 CF card detect" },
{ S1_BVD1_STSCHG, "SA1111 CF BVD1" }, { IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" },
}; };
static struct sa1111_dev *pcmcia;
int sa1111_pcmcia_init(struct pcmcia_init *init) int sa1111_pcmcia_init(struct pcmcia_init *init)
{ {
int i, ret; int i, ret;
if (!request_mem_region(_PCCR, 512, "PCMCIA"))
return -1;
for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) { for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_FALLING); set_irq_type(irqs[i].irq, IRQT_FALLING);
ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT, ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
...@@ -47,8 +48,6 @@ int sa1111_pcmcia_init(struct pcmcia_init *init) ...@@ -47,8 +48,6 @@ int sa1111_pcmcia_init(struct pcmcia_init *init)
irqs[i].irq, ret); irqs[i].irq, ret);
while (i--) while (i--)
free_irq(irqs[i].irq, NULL); free_irq(irqs[i].irq, NULL);
release_mem_region(_PCCR, 16);
} }
return ret ? -1 : 2; return ret ? -1 : 2;
...@@ -61,8 +60,6 @@ int sa1111_pcmcia_shutdown(void) ...@@ -61,8 +60,6 @@ int sa1111_pcmcia_shutdown(void)
for (i = 0; i < ARRAY_SIZE(irqs); i++) for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL); free_irq(irqs[i].irq, NULL);
release_mem_region(_PCCR, 512);
return 0; return 0;
} }
...@@ -73,7 +70,7 @@ int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state) ...@@ -73,7 +70,7 @@ int sa1111_pcmcia_socket_state(struct pcmcia_state_array *state)
if (state->size < 2) if (state->size < 2)
return -1; return -1;
status = PCSR; status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR);
state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1; state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
state->state[0].ready = status & PCSR_S0_READY ? 1 : 0; state->state[0].ready = status & PCSR_S0_READY ? 1 : 0;
...@@ -99,8 +96,8 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ...@@ -99,8 +96,8 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
int ret = 0; int ret = 0;
switch (info->sock) { switch (info->sock) {
case 0: info->irq = S0_READY_NINT; break; case 0: info->irq = IRQ_S0_READY_NINT; break;
case 1: info->irq = S1_READY_NINT; break; case 1: info->irq = IRQ_S1_READY_NINT; break;
default: ret = 1; default: ret = 1;
} }
...@@ -109,7 +106,7 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info) ...@@ -109,7 +106,7 @@ int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned int rst, flt, wait, pse, irq, pccr_mask; unsigned int rst, flt, wait, pse, irq, pccr_mask, val;
unsigned long flags; unsigned long flags;
switch (conf->sock) { switch (conf->sock) {
...@@ -118,7 +115,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) ...@@ -118,7 +115,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
flt = PCCR_S0_FLT; flt = PCCR_S0_FLT;
wait = PCCR_S0_PWAITEN; wait = PCCR_S0_PWAITEN;
pse = PCCR_S0_PSE; pse = PCCR_S0_PSE;
irq = S0_READY_NINT; irq = IRQ_S0_READY_NINT;
break; break;
case 1: case 1:
...@@ -126,7 +123,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) ...@@ -126,7 +123,7 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
flt = PCCR_S1_FLT; flt = PCCR_S1_FLT;
wait = PCCR_S1_PWAITEN; wait = PCCR_S1_PWAITEN;
pse = PCCR_S1_PSE; pse = PCCR_S1_PSE;
irq = S1_READY_NINT; irq = IRQ_S1_READY_NINT;
break; break;
default: default:
...@@ -159,7 +156,9 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf) ...@@ -159,7 +156,9 @@ int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *conf)
pccr_mask |= flt; pccr_mask |= flt;
local_irq_save(flags); local_irq_save(flags);
PCCR = (PCCR & ~(pse | flt | wait | rst)) | pccr_mask; val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR);
val = (val & ~(pse | flt | wait | rst)) | pccr_mask;
sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR);
local_irq_restore(flags); local_irq_restore(flags);
if (conf->irq) if (conf->irq)
...@@ -179,3 +178,130 @@ int sa1111_pcmcia_socket_suspend(int sock) ...@@ -179,3 +178,130 @@ int sa1111_pcmcia_socket_suspend(int sock)
{ {
return 0; return 0;
} }
static int pcmcia_probe(struct device *dev)
{
struct sa1111_dev *sadev = SA1111_DEV(dev);
unsigned long flags;
char *base;
local_irq_save(flags);
if (pcmcia) {
local_irq_restore(flags);
return -EBUSY;
}
pcmcia = sadev;
local_irq_restore(flags);
if (!request_mem_region(sadev->res.start, 512,
SA1111_DRIVER_NAME(sadev)))
return -EBUSY;
base = sadev->mapbase;
/*
* Initialise the suspend state.
*/
sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + SA1111_PCSSR);
sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + SA1111_PCCR);
#ifdef CONFIG_SA1100_ADSBITSY
pcmcia_adsbitsy_init();
#endif
#ifdef CONFIG_SA1100_BADGE4
pcmcia_badge4_init();
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
pcmcia_graphicsmaster_init();
#endif
#ifdef CONFIG_SA1100_JORNADA720
pcmcia_jornada720_init();
#endif
#ifdef CONFIG_ASSABET_NEPONSET
pcmcia_neponset_init();
#endif
#ifdef CONFIG_SA1100_PFS168
pcmcia_pfs_init();
#endif
#ifdef CONFIG_SA1100_PT_SYSTEM3
pcmcia_system3_init();
#endif
#ifdef CONFIG_SA1100_XP860
pcmcia_xp860_init();
#endif
return 0;
}
static int __devexit pcmcia_remove(struct device *dev)
{
struct sa1111_dev *sadev = SA1111_DEV(dev);
#ifdef CONFIG_SA1100_ADSBITSY
pcmcia_adsbitsy_exit();
#endif
#ifdef CONFIG_SA1100_BADGE4
pcmcia_badge4_exit();
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
pcmcia_graphicsmaster_exit();
#endif
#ifdef CONFIG_SA1100_JORNADA720
pcmcia_jornada720_exit();
#endif
#ifdef CONFIG_ASSABET_NEPONSET
pcmcia_neponset_exit();
#endif
#ifdef CONFIG_SA1100_PFS168
pcmcia_pfs_exit();
#endif
#ifdef CONFIG_SA1100_PT_SYSTEM3
pcmcia_system3_exit();
#endif
#ifdef CONFIG_SA1100_XP860
pcmcia_xp860_exit();
#endif
release_mem_region(sadev->res.start, 512);
pcmcia = NULL;
return 0;
}
static int pcmcia_suspend(struct device *dev, u32 state, u32 level)
{
return 0;
}
static int pcmcia_resume(struct device *dev, u32 level)
{
return 0;
}
static struct sa1111_driver pcmcia_driver = {
.drv = {
.name = "SA1111 PCMCIA",
.bus = &sa1111_bus_type,
.probe = pcmcia_probe,
.remove = __devexit_p(pcmcia_remove),
.suspend = pcmcia_suspend,
.resume = pcmcia_resume,
},
.devid = SA1111_DEVID_PCMCIA,
};
static int __init sa1111_drv_pcmcia_init(void)
{
return driver_register(&pcmcia_driver.drv);
}
static void __exit sa1111_drv_pcmcia_exit(void)
{
remove_driver(&pcmcia_driver.drv);
}
module_init(sa1111_drv_pcmcia_init);
module_exit(sa1111_drv_pcmcia_exit);
MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
MODULE_LICENSE("GPL");
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static void sa1111_start_hc(void) static void sa1111_start_hc(struct sa1111_dev *dev)
{ {
unsigned int usb_rst = 0; unsigned int usb_rst = 0;
...@@ -48,31 +48,35 @@ static void sa1111_start_hc(void) ...@@ -48,31 +48,35 @@ static void sa1111_start_hc(void)
* Configure the power sense and control lines. Place the USB * Configure the power sense and control lines. Place the USB
* host controller in reset. * host controller in reset.
*/ */
USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
dev->mapbase + SA1111_USB_RESET);
/* /*
* Now, carefully enable the USB clock, and take * Now, carefully enable the USB clock, and take
* the USB host controller out of reset. * the USB host controller out of reset.
*/ */
SKPCR |= SKPCR_UCLKEN; sa1111_enable_device(dev);
udelay(11); udelay(11);
USB_RESET = usb_rst; sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
} }
static void sa1111_stop_hc(void) static void sa1111_stop_hc(struct sa1111_dev *dev)
{ {
unsigned int usb_rst;
printk(KERN_DEBUG __FILE__ printk(KERN_DEBUG __FILE__
": stopping SA-1111 OHCI USB Controller\n"); ": stopping SA-1111 OHCI USB Controller\n");
/* /*
* Put the USB host controller into reset. * Put the USB host controller into reset.
*/ */
USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET; usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
dev->mapbase + SA1111_USB_RESET);
/* /*
* Stop the USB clock. * Stop the USB clock.
*/ */
SKPCR &= ~SKPCR_UCLKEN; sa1111_disable_device(dev);
#ifdef CONFIG_SA1100_BADGE4 #ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) { if (machine_is_badge4()) {
...@@ -86,9 +90,9 @@ static void sa1111_stop_hc(void) ...@@ -86,9 +90,9 @@ static void sa1111_stop_hc(void)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#if 0 #if 0
static void dump_hci_status(const char *label) static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{ {
unsigned long status = USB_STATUS; unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
dbg ("%s USB_STATUS = { %s%s%s%s%s}", label, dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
...@@ -101,11 +105,14 @@ static void dump_hci_status(const char *label) ...@@ -101,11 +105,14 @@ static void dump_hci_status(const char *label)
static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r) static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
{ {
//dump_hci_status("irq"); struct usb_hcd *hcd = __hcd;
// unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
//dump_hci_status(hcd, "irq");
#if 0 #if 0
/* may work better this way -- need to investigate further */ /* may work better this way -- need to investigate further */
if (USB_STATUS & USB_STATUS_NIRQHCIM) { if (status & USB_STATUS_NIRQHCIM) {
//dbg ("not normal HC interrupt; ignoring"); //dbg ("not normal HC interrupt; ignoring");
return; return;
} }
...@@ -116,7 +123,7 @@ static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -116,7 +123,7 @@ static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
void usb_hcd_sa1111_remove (struct usb_hcd *); void usb_hcd_sa1111_remove (struct usb_hcd *, struct sa1111_dev *);
/* configure so an HC device and id are always provided */ /* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */ /* always called with process context; sleeping is OK */
...@@ -132,21 +139,20 @@ void usb_hcd_sa1111_remove (struct usb_hcd *); ...@@ -132,21 +139,20 @@ void usb_hcd_sa1111_remove (struct usb_hcd *);
* *
* Store this function in the HCD's struct pci_driver as probe(). * Store this function in the HCD's struct pci_driver as probe().
*/ */
int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_out) int usb_hcd_sa1111_probe (const struct hc_driver *driver,
struct usb_hcd **hcd_out,
struct sa1111_dev *dev)
{ {
int retval; int retval;
struct usb_hcd *hcd = 0; struct usb_hcd *hcd = 0;
if (!sa1111) if (!request_mem_region(dev->res.start,
return -ENODEV; dev->res.end - dev->res.start + 1, hcd_name)) {
if (!request_mem_region(_USB_OHCI_OP_BASE,
_USB_EXTENT, hcd_name)) {
dbg("request_mem_region failed"); dbg("request_mem_region failed");
return -EBUSY; return -EBUSY;
} }
sa1111_start_hc(); sa1111_start_hc(dev);
hcd = driver->hcd_alloc (); hcd = driver->hcd_alloc ();
if (hcd == NULL){ if (hcd == NULL){
...@@ -157,9 +163,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -157,9 +163,10 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
hcd->driver = (struct hc_driver *) driver; hcd->driver = (struct hc_driver *) driver;
hcd->description = driver->description; hcd->description = driver->description;
hcd->irq = NIRQHCIM; hcd->irq = dev->irq[1];
hcd->regs = (void *) &USB_OHCI_OP_BASE; hcd->regs = dev->mapbase;
hcd->pdev = SA1111_FAKE_PCIDEV; hcd->pdev = SA1111_FAKE_PCIDEV;
hcd->parent = &dev->dev;
retval = hcd_buffer_create (hcd); retval = hcd_buffer_create (hcd);
if (retval != 0) { if (retval != 0) {
...@@ -167,8 +174,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -167,8 +174,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
goto err1; goto err1;
} }
set_irq_type(NIRQHCIM, IRQT_RISING); set_irq_type(hcd->irq, IRQT_RISING);
retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT, retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
hcd->description, hcd); hcd->description, hcd);
if (retval != 0) { if (retval != 0) {
dbg("request_irq failed"); dbg("request_irq failed");
...@@ -191,7 +198,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -191,7 +198,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
if ((retval = driver->start (hcd)) < 0) if ((retval = driver->start (hcd)) < 0)
{ {
usb_hcd_sa1111_remove(hcd); usb_hcd_sa1111_remove(hcd, dev);
return retval; return retval;
} }
...@@ -202,8 +209,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -202,8 +209,8 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
hcd_buffer_destroy (hcd); hcd_buffer_destroy (hcd);
if (hcd) driver->hcd_free(hcd); if (hcd) driver->hcd_free(hcd);
err1: err1:
sa1111_stop_hc(); sa1111_stop_hc(dev);
release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
return retval; return retval;
} }
...@@ -221,7 +228,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o ...@@ -221,7 +228,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_o
* context, normally "rmmod", "apmd", or something similar. * context, normally "rmmod", "apmd", or something similar.
* *
*/ */
void usb_hcd_sa1111_remove (struct usb_hcd *hcd) void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
{ {
struct usb_device *hub; struct usb_device *hub;
void *base; void *base;
...@@ -244,13 +251,13 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd) ...@@ -244,13 +251,13 @@ void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
usb_deregister_bus (&hcd->self); usb_deregister_bus (&hcd->self);
if (atomic_read (&hcd->self.refcnt) != 1) if (atomic_read (&hcd->self.refcnt) != 1)
err (__FUNCTION__ ": %s, count != 1", hcd->self.bus_name); err ("%s: %s, count != 1", __FUNCTION__, hcd->self.bus_name);
base = hcd->regs; base = hcd->regs;
hcd->driver->hcd_free (hcd); hcd->driver->hcd_free (hcd);
sa1111_stop_hc(); sa1111_stop_hc(dev);
release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -275,7 +282,7 @@ ohci_sa1111_start (struct usb_hcd *hcd) ...@@ -275,7 +282,7 @@ ohci_sa1111_start (struct usb_hcd *hcd)
} }
ohci->regs = hcd->regs; ohci->regs = hcd->regs;
ohci->parent_dev = &sa1111->dev; ohci->parent_dev = hcd->parent;
if (hc_reset (ohci) < 0) { if (hc_reset (ohci) < 0) {
ohci_stop (hcd); ohci_stop (hcd);
...@@ -342,26 +349,67 @@ static const struct hc_driver ohci_sa1111_hc_driver = { ...@@ -342,26 +349,67 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* Only one SA-1111 ever exists. */ static int ohci_hcd_sa1111_drv_probe(struct device *_dev)
static struct usb_hcd *the_sa1111_hcd; {
struct sa1111_dev *dev = SA1111_DEV(_dev);
struct usb_hcd *hcd = NULL;
int ret;
ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev);
if (ret == 0)
dev->dev.driver_data = hcd;
return ret;
}
static int ohci_hcd_sa1111_drv_remove(struct device *_dev)
{
struct sa1111_dev *dev = SA1111_DEV(_dev);
struct usb_hcd *hcd = dev->dev.driver_data;
usb_hcd_sa1111_remove(hcd, dev);
dev->dev.driver_data = NULL;
static int __init ohci_hcd_sa1111_init (void) return 0;
}
static int ohci_hcd_sa1111_drv_suspend(struct device *dev, u32 state, u32 level)
{
return 0;
}
static int ohci_hcd_sa1111_drv_resume(struct device *dev, u32 level)
{
return 0;
}
static struct sa1111_driver ohci_hcd_sa1111_driver = {
.drv = {
.name = "SA1111 OHCI",
.bus = &sa1111_bus_type,
.probe = ohci_hcd_sa1111_drv_probe,
.remove = ohci_hcd_sa1111_drv_remove,
.suspend = ohci_hcd_sa1111_drv_suspend,
.resume = ohci_hcd_sa1111_drv_resume,
},
.devid = SA1111_DEVID_USB,
};
static int __init ohci_hcd_sa1111_init (void)
{ {
dbg (DRIVER_INFO " (SA-1111)"); dbg (DRIVER_INFO " (SA-1111)");
dbg ("block sizes: ed %d td %d", dbg ("block sizes: ed %d td %d",
sizeof (struct ed), sizeof (struct td)); sizeof (struct ed), sizeof (struct td));
the_sa1111_hcd = 0; return driver_register(&ohci_hcd_sa1111_driver.drv);
return usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &the_sa1111_hcd);
} }
module_init (ohci_hcd_sa1111_init);
static void __exit ohci_hcd_sa1111_cleanup (void)
static void __exit ohci_hcd_sa1111_cleanup (void) {
{ remove_driver(&ohci_hcd_sa1111_driver.drv);
if (the_sa1111_hcd) {
usb_hcd_sa1111_remove(the_sa1111_hcd);
the_sa1111_hcd = 0;
}
} }
module_init (ohci_hcd_sa1111_init);
module_exit (ohci_hcd_sa1111_cleanup); module_exit (ohci_hcd_sa1111_cleanup);
...@@ -209,17 +209,17 @@ extern void (*sa1100fb_lcd_power)(int on); ...@@ -209,17 +209,17 @@ extern void (*sa1100fb_lcd_power)(int on);
* IMHO this looks wrong. In 8BPP, length should be 8. * IMHO this looks wrong. In 8BPP, length should be 8.
*/ */
static struct sa1100fb_rgb rgb_8 = { static struct sa1100fb_rgb rgb_8 = {
red: { offset: 0, length: 4, }, .red = { .offset = 0, .length = 4, },
green: { offset: 0, length: 4, }, .green = { .offset = 0, .length = 4, },
blue: { offset: 0, length: 4, }, .blue = { .offset = 0, .length = 4, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
static struct sa1100fb_rgb def_rgb_16 = { static struct sa1100fb_rgb def_rgb_16 = {
red: { offset: 11, length: 5, }, .red = { .offset = 11, .length = 5, },
green: { offset: 5, length: 6, }, .green = { .offset = 5, .length = 6, },
blue: { offset: 0, length: 5, }, .blue = { .offset = 0, .length = 5, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
#ifdef CONFIG_SA1100_ASSABET #ifdef CONFIG_SA1100_ASSABET
...@@ -230,155 +230,151 @@ static struct sa1100fb_rgb def_rgb_16 = { ...@@ -230,155 +230,151 @@ static struct sa1100fb_rgb def_rgb_16 = {
* instead (def_rgb_16). * instead (def_rgb_16).
*/ */
static struct sa1100fb_mach_info lq039q2ds54_info __initdata = { static struct sa1100fb_mach_info lq039q2ds54_info __initdata = {
pixclock: 171521, bpp: 16, .pixclock = 171521, .bpp = 16,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 5, vsync_len: 1, .hsync_len = 5, .vsync_len = 1,
left_margin: 61, upper_margin: 3, .left_margin = 61, .upper_margin = 3,
right_margin: 9, lower_margin: 0, .right_margin = 9, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
}; };
#else #else
static struct sa1100fb_mach_info pal_info __initdata = { static struct sa1100fb_mach_info pal_info __initdata = {
pixclock: 67797, bpp: 16, .pixclock = 67797, .bpp = 16,
xres: 640, yres: 512, .xres = 640, .yres = 512,
hsync_len: 64, vsync_len: 6, .hsync_len = 64, .vsync_len = 6,
left_margin: 125, upper_margin: 70, .left_margin = 125, .upper_margin = 70,
right_margin: 115, lower_margin: 36, .right_margin = 115, .lower_margin = 36,
sync: 0, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
}; };
#endif #endif
#endif #endif
#ifdef CONFIG_SA1100_H3800 #ifdef CONFIG_SA1100_H3800
static struct sa1100fb_mach_info h3800_info __initdata = { static struct sa1100fb_mach_info h3800_info __initdata = {
pixclock: 174757, bpp: 16, .pixclock = 174757, .bpp = 16,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 3, vsync_len: 3, .hsync_len = 3, .vsync_len = 3,
left_margin: 12, upper_margin: 10, .left_margin = 12, .upper_margin = 10,
right_margin: 17, lower_margin: 1, .right_margin = 17, .lower_margin = 1,
sync: 0, cmap_static: 1, .cmap_static = 1,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_ACBsDiv(2) | LCCR3_PixRsEdg | LCCR3_OutEnH | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
LCCR3_ACBsCntOff,
}; };
#endif #endif
#ifdef CONFIG_SA1100_H3600 #ifdef CONFIG_SA1100_H3600
static struct sa1100fb_mach_info h3600_info __initdata = { static struct sa1100fb_mach_info h3600_info __initdata = {
pixclock: 174757, bpp: 16, .pixclock = 174757, .bpp = 16,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 3, vsync_len: 3, .hsync_len = 3, .vsync_len = 3,
left_margin: 12, upper_margin: 10, .left_margin = 12, .upper_margin = 10,
right_margin: 17, lower_margin: 1, .right_margin = 17, .lower_margin = 1,
sync: 0, cmap_static: 1, .cmap_static = 1,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_ACBsDiv(2) | LCCR3_PixRsEdg | LCCR3_OutEnH | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
LCCR3_ACBsCntOff,
}; };
static struct sa1100fb_rgb h3600_rgb_16 = { static struct sa1100fb_rgb h3600_rgb_16 = {
red: { offset: 12, length: 4, }, .red = { .offset = 12, .length = 4, },
green: { offset: 7, length: 4, }, .green = { .offset = 7, .length = 4, },
blue: { offset: 1, length: 4, }, .blue = { .offset = 1, .length = 4, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
#endif #endif
#ifdef CONFIG_SA1100_H3100 #ifdef CONFIG_SA1100_H3100
static struct sa1100fb_mach_info h3100_info __initdata = { static struct sa1100fb_mach_info h3100_info __initdata = {
pixclock: 406977, bpp: 4, .pixclock = 406977, .bpp = 4,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 26, vsync_len: 41, .hsync_len = 26, .vsync_len = 41,
left_margin: 4, upper_margin: 0, .left_margin = 4, .upper_margin = 0,
right_margin: 4, lower_margin: 0, .right_margin = 4, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
cmap_greyscale: 1, .cmap_greyscale = 1,
cmap_inverse: 1, .cmap_inverse = 1,
lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
}; };
#endif #endif
#ifdef CONFIG_SA1100_BRUTUS #ifdef CONFIG_SA1100_BRUTUS
static struct sa1100fb_mach_info brutus_info __initdata = { static struct sa1100fb_mach_info brutus_info __initdata = {
pixclock: 0, bpp: 8, .pixclock = 0, .bpp = 8,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 3, vsync_len: 1, .hsync_len = 3, .vsync_len = 1,
left_margin: 41, upper_margin: 0, .left_margin = 41, .upper_margin = 0,
right_margin: 101, lower_margin: 0, .right_margin = 101, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
LCCR3_PixClkDiv(44), LCCR3_PixClkDiv(44),
}; };
#endif #endif
#ifdef CONFIG_SA1100_CERF #ifdef CONFIG_SA1100_CERF
static struct sa1100fb_mach_info cerf_info __initdata = { static struct sa1100fb_mach_info cerf_info __initdata = {
#if defined(CONFIG_CERF_LCD_72_A) #if defined(CONFIG_CERF_LCD_72_A)
pixclock: 171521, bpp: 8, .pixclock = 171521, .bpp = 8,
xres: 640, yres: 480, .xres = 640, .yres = 480,
lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
LCCR3_PixClkDiv(38), LCCR3_PixClkDiv(38),
#elif defined(CONFIG_CERF_LCD_57_A) #elif defined(CONFIG_CERF_LCD_57_A)
pixclock: 171521, bpp: 8, .pixclock = 171521, .bpp = 8,
xres: 320, yres: 240, .xres = 320, .yres = 240,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
LCCR3_PixClkDiv(38), LCCR3_PixClkDiv(38),
#elif defined(CONFIG_CERF_LCD_38_A) #elif defined(CONFIG_CERF_LCD_38_A)
pixclock: 171521, bpp: 8, .pixclock = 171521, .bpp = 8,
xres: 240, yres: 320, .xres = 240, .yres = 320,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
LCCR3_PixClkDiv(38), LCCR3_PixClkDiv(38),
#elif defined(CONFIG_CERF_LCD_38_B) #elif defined(CONFIG_CERF_LCD_38_B)
pixclock: 171521, bpp: 4, .pixclock = 171521, .bpp = 4,
xres: 320, yres: 240, .xres = 320, .yres = 240,
lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(56) |
LCCR3_PixClkDiv(38), LCCR3_PixClkDiv(38),
#else #else
#error "Must have a CerfBoard LCD form factor selected" #error "Must have a CerfBoard LCD form factor selected"
#endif #endif
hsync_len: 5, vsync_len: 1, .hsync_len = 5, .vsync_len = 1,
left_margin: 61, upper_margin: 3, .left_margin = 61, .upper_margin = 3,
right_margin: 9, lower_margin: 0, .right_margin = 9, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
}; };
#if 0 #if 0
static struct sa1100fb_rgb cerf_rgb_16 = { static struct sa1100fb_rgb cerf_rgb_16 = {
red: { offset: 8, length: 4, }, .red = { .offset = 8, .length = 4, },
green: { offset: 4, length: 4, }, .green = { .offset = 4, .length = 4, },
blue: { offset: 0, length: 4, }, .blue = { .offset = 0, .length = 4, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
#endif #endif
#endif #endif
...@@ -386,56 +382,54 @@ static struct sa1100fb_rgb cerf_rgb_16 = { ...@@ -386,56 +382,54 @@ static struct sa1100fb_rgb cerf_rgb_16 = {
#ifdef CONFIG_SA1100_FREEBIRD #ifdef CONFIG_SA1100_FREEBIRD
#warning Please check this carefully #warning Please check this carefully
static struct sa1100fb_mach_info freebird_info __initdata = { static struct sa1100fb_mach_info freebird_info __initdata = {
pixclock: 171521, bpp: 16, .pixclock = 171521, .bpp = 16,
xres: 240, yres: 320, .xres = 240, .yres = 320,
hsync_len: 3, vsync_len: 2, .hsync_len = 3, .vsync_len = 2,
left_margin: 2, upper_margin: 0, .left_margin = 2, .upper_margin = 0,
right_margin: 2, lower_margin: 0, .right_margin = 2, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2), .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
}; };
static struct sa1100fb_rgb freebird_rgb_16 = { static struct sa1100fb_rgb freebird_rgb_16 = {
red: { offset: 8, length: 4, }, .red = { .offset = 8, .length = 4, },
green: { offset: 4, length: 4, }, .green = { .offset = 4, .length = 4, },
blue: { offset: 0, length: 4, }, .blue = { .offset = 0, .length = 4, },
transp: { offset: 12, length: 4, }, .transp = { .offset = 12, .length = 4, },
}; };
#endif #endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT #ifdef CONFIG_SA1100_GRAPHICSCLIENT
static struct sa1100fb_mach_info graphicsclient_info __initdata = { static struct sa1100fb_mach_info graphicsclient_info __initdata = {
pixclock: 53500, bpp: 8, .pixclock = 53500, .bpp = 8,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 9, vsync_len: 9,
left_margin: 54, upper_margin: 24,
right_margin: 54, lower_margin: 32,
sync: 0, .hsync_len = 9, .vsync_len = 9,
.left_margin = 54, .upper_margin = 24,
.right_margin = 54, .lower_margin = 32,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
}; };
#endif #endif
#ifdef CONFIG_SA1100_HUW_WEBPANEL #ifdef CONFIG_SA1100_HUW_WEBPANEL
static struct sa1100fb_mach_info huw_webpanel_info __initdata = { static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
pixclock: 0, bpp: 8, .pixclock = 0, .bpp = 8,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 3, vsync_len: 1, .hsync_len = 3, .vsync_len = 1,
left_margin: 41, upper_margin: 0, .left_margin = 41, .upper_margin = 0,
right_margin: 101, lower_margin: 0, .right_margin = 101, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
#error FIXME #error FIXME
/* /*
* FIXME: please get rid of the '| 8' in preference to an * FIXME: please get rid of the '| 8' in preference to an
...@@ -446,99 +440,94 @@ static struct sa1100fb_mach_info huw_webpanel_info __initdata = { ...@@ -446,99 +440,94 @@ static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
#ifdef LART_GREY_LCD #ifdef LART_GREY_LCD
static struct sa1100fb_mach_info lart_grey_info __initdata = { static struct sa1100fb_mach_info lart_grey_info __initdata = {
pixclock: 150000, bpp: 4, .pixclock = 150000, .bpp = 4,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 1, vsync_len: 1, .hsync_len = 1, .vsync_len = 1,
left_margin: 4, upper_margin: 0, .left_margin = 4, .upper_margin = 0,
right_margin: 2, lower_margin: 0, .right_margin = 2, .lower_margin = 0,
cmap_greyscale: 1, .cmap_greyscale = 1,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono, .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512), .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
}; };
#endif #endif
#ifdef LART_COLOR_LCD #ifdef LART_COLOR_LCD
static struct sa1100fb_mach_info lart_color_info __initdata = { static struct sa1100fb_mach_info lart_color_info __initdata = {
pixclock: 150000, bpp: 16, .pixclock = 150000, .bpp = 16,
xres: 320, yres: 240, .xres = 320, .yres = 240,
hsync_len: 2, vsync_len: 3, .hsync_len = 2, .vsync_len = 3,
left_margin: 69, upper_margin: 14, .left_margin = 69, .upper_margin = 14,
right_margin: 8, lower_margin: 4, .right_margin = 8, .lower_margin = 4,
sync: 0, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
}; };
#endif #endif
#ifdef LART_VIDEO_OUT #ifdef LART_VIDEO_OUT
static struct sa1100fb_mach_info lart_video_info __initdata = { static struct sa1100fb_mach_info lart_video_info __initdata = {
pixclock: 39721, bpp: 16, .pixclock = 39721, .bpp = 16,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 95, vsync_len: 2, .hsync_len = 95, .vsync_len = 2,
left_margin: 40, upper_margin: 32, .left_margin = 40, .upper_margin = 32,
right_margin: 24, lower_margin: 11, .right_margin = 24, .lower_margin = 11,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512), .lccr3 = LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
}; };
#endif #endif
#ifdef LART_KIT01_LCD #ifdef LART_KIT01_LCD
static struct sa1100fb_mach_info lart_kit01_info __initdata = static struct sa1100fb_mach_info lart_kit01_info __initdata = {
{ .pixclock = 63291, .bpp = 16,
pixclock: 63291, bpp: 16, .xres = 640, .yres = 480,
xres: 640, yres: 480,
hsync_len: 64, vsync_len: 3, .hsync_len = 64, .vsync_len = 3,
left_margin: 122, upper_margin: 45, .left_margin = 122, .upper_margin = 45,
right_margin: 10, lower_margin: 10, .right_margin = 10, .lower_margin = 10,
sync: 0, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
.lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg
}; };
#endif #endif
#ifdef CONFIG_SA1100_SHANNON #ifdef CONFIG_SA1100_SHANNON
static struct sa1100fb_mach_info shannon_info __initdata = { static struct sa1100fb_mach_info shannon_info __initdata = {
pixclock: 152500, bpp: 8, .pixclock = 152500, .bpp = 8,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 4, vsync_len: 3, .hsync_len = 4, .vsync_len = 3,
left_margin: 2, upper_margin: 0, .left_margin = 2, .upper_margin = 0,
right_margin: 1, lower_margin: 0, .right_margin = 1, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
lccr3: LCCR3_ACBsDiv(512), .lccr3 = LCCR3_ACBsDiv(512),
}; };
#endif #endif
#ifdef CONFIG_SA1100_OMNIMETER #ifdef CONFIG_SA1100_OMNIMETER
static struct sa1100fb_mach_info omnimeter_info __initdata = { static struct sa1100fb_mach_info omnimeter_info __initdata = {
pixclock: 0, bpp: 4, .pixclock = 0, .bpp = 4,
xres: 480, yres: 320, .xres = 480, .yres = 320,
hsync_len: 1, vsync_len: 1, .hsync_len = 1, .vsync_len = 1,
left_margin: 10, upper_margin: 0, .left_margin = 10, .upper_margin = 0,
right_margin: 10, lower_margin: 0, .right_margin = 10, .lower_margin = 0,
cmap_greyscale: 1, .cmap_greyscale = 1,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono, .lccr0 = LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
LCCR3_PixClkDiv(44), LCCR3_PixClkDiv(44),
#error FIXME: fix pixclock, ACBsDiv #error FIXME: fix pixclock, ACBsDiv
/* /*
* FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)? * FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)?
...@@ -549,17 +538,17 @@ static struct sa1100fb_mach_info omnimeter_info __initdata = { ...@@ -549,17 +538,17 @@ static struct sa1100fb_mach_info omnimeter_info __initdata = {
#ifdef CONFIG_SA1100_PANGOLIN #ifdef CONFIG_SA1100_PANGOLIN
static struct sa1100fb_mach_info pangolin_info __initdata = { static struct sa1100fb_mach_info pangolin_info __initdata = {
pixclock: 341521, bpp: 16, .pixclock = 341521, .bpp = 16,
xres: 800, yres: 600, .xres = 800, .yres = 600,
hsync_len: 64, vsync_len: 7, .hsync_len = 64, .vsync_len = 7,
left_margin: 160, upper_margin: 7, .left_margin = 160, .upper_margin = 7,
right_margin: 24, lower_margin: 1, .right_margin = 24, .lower_margin = 1,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff, .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff,
}; };
#endif #endif
...@@ -571,49 +560,47 @@ static struct sa1100fb_mach_info pangolin_info __initdata = { ...@@ -571,49 +560,47 @@ static struct sa1100fb_mach_info pangolin_info __initdata = {
* NB likely to be increased to ease bus timings wrt pcmcia interface * NB likely to be increased to ease bus timings wrt pcmcia interface
*/ */
static struct sa1100fb_mach_info stork_tft_info __initdata = { static struct sa1100fb_mach_info stork_tft_info __initdata = {
pixclock: 28935, bpp: 16, .pixclock = 28935, .bpp = 16,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 64, vsync_len: 2,
left_margin: 48, upper_margin: 12,
right_margin: 48, lower_margin: 31,
sync: 0, .hsync_len = 64, .vsync_len = 2,
.left_margin = 48, .upper_margin = 12,
.right_margin = 48, .lower_margin = 31,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg, .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsCntOff,
}; };
static struct sa1100fb_rgb stork_tft_rgb_16 = { static struct sa1100fb_rgb stork_tft_rgb_16 = {
red: { offset: 11, length: 5, }, .red = { .offset = 11, .length = 5, },
green: { offset: 5, length: 6, }, .green = { .offset = 5, .length = 6, },
blue: { offset: 0, length: 5, }, .blue = { .offset = 0, .length = 5, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
#else /* Kyocera DSTN */ #else /* Kyocera DSTN */
static struct sa1100fb_mach_info stork_dstn_info __initdata = { static struct sa1100fb_mach_info stork_dstn_info __initdata = {
pixclock: 0, bpp: 16, .pixclock = 0, .bpp = 16,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 2, vsync_len: 2, .hsync_len = 2, .vsync_len = 2,
left_margin: 2, upper_margin: 0, .left_margin = 2, .upper_margin = 0,
right_margin: 2, lower_margin: 0, .right_margin = 2, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT , .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
#error Fixme #error Fixme
lccr3: 0xff00 | .lccr3 = 0xff00 |
0x18 /* ought to be 0x14 but DMA isn't up to that as yet */ 0x18 /* ought to be 0x14 but DMA isn't up to that as yet */
}; };
static struct sa1100fb_rgb stork_dstn_rgb_16 = { static struct sa1100fb_rgb stork_dstn_rgb_16 = {
red: { offset: 8, length: 4, }, .red = { .offset = 8, .length = 4, },
green: { offset: 4, length: 4, }, .green = { .offset = 4, .length = 4, },
blue: { offset: 0, length: 4, }, .blue = { .offset = 0, .length = 4, },
transp: { offset: 0, length: 0, }, .transp = { .offset = 0, .length = 0, },
}; };
#endif #endif
#endif #endif
...@@ -630,34 +617,31 @@ static struct sa1100fb_rgb stork_dstn_rgb_16 = { ...@@ -630,34 +617,31 @@ static struct sa1100fb_rgb stork_dstn_rgb_16 = {
* =>4.32Mhz => 231481E-12s * =>4.32Mhz => 231481E-12s
*/ */
static struct sa1100fb_mach_info system3_info __initdata = { static struct sa1100fb_mach_info system3_info __initdata = {
pixclock: 231481, bpp: 8, .pixclock = 231481, .bpp = 8,
xres: 640, yres: 480, .xres = 640, .yres = 480,
hsync_len: 2, vsync_len: 2, .hsync_len = 2, .vsync_len = 2,
left_margin: 2, upper_margin: 0, .left_margin = 2, .upper_margin = 0,
right_margin: 2, lower_margin: 0, .right_margin = 2, .lower_margin = 0,
sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas, .lccr0 = LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512) | .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
LCCR3_ACBsCntOff,
}; };
#endif #endif
#ifdef CONFIG_SA1100_XP860 #ifdef CONFIG_SA1100_XP860
static struct sa1100fb_mach_info xp860_info __initdata = { static struct sa1100fb_mach_info xp860_info __initdata = {
pixclock: 0, bpp: 8, .pixclock = 0, .bpp = 8,
xres: 1024, yres: 768, .xres = 1024, .yres = 768,
hsync_len: 3, vsync_len: 3,
left_margin: 3, upper_margin: 2,
right_margin: 2, lower_margin: 1,
sync: 0, .hsync_len = 3, .vsync_len = 3,
.left_margin = 3, .upper_margin = 2,
.right_margin = 2, .lower_margin = 1,
lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act, .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6), .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
}; };
#endif #endif
...@@ -808,33 +792,7 @@ static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state ...@@ -808,33 +792,7 @@ static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state
local_irq_restore(flags); local_irq_restore(flags);
} }
/* static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
* Get the VAR structure pointer for the specified console
*/
static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->var : &fb_display[con].var;
}
/*
* Get the DISPLAY structure pointer for the specified console
*/
static inline struct display *get_con_display(struct fb_info *info, int con)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
return (con < 0) ? fbi->fb.disp : &fb_display[con];
}
/*
* Get the CMAP pointer for the specified console
*/
static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
{
return (con == info->currcon || con == -1) ? &info->cmap : &fb_display[con].cmap;
}
static inline u_int
chan_to_field(u_int chan, struct fb_bitfield *bf)
{ {
chan &= 0xffff; chan &= 0xffff;
chan >>= 16 - bf->length; chan >>= 16 - bf->length;
...@@ -844,8 +802,7 @@ chan_to_field(u_int chan, struct fb_bitfield *bf) ...@@ -844,8 +802,7 @@ chan_to_field(u_int chan, struct fb_bitfield *bf)
/* /*
* Convert bits-per-pixel to a hardware palette PBS value. * Convert bits-per-pixel to a hardware palette PBS value.
*/ */
static inline u_int static inline u_int palette_pbs(struct fb_var_screeninfo *var)
palette_pbs(struct fb_var_screeninfo *var)
{ {
int ret = 0; int ret = 0;
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
...@@ -888,8 +845,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -888,8 +845,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int trans, struct fb_info *info) u_int trans, struct fb_info *info)
{ {
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp = get_con_display(info, info->currcon); unsigned int val;
u_int val;
int ret = 1; int ret = 1;
/* /*
...@@ -898,7 +854,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -898,7 +854,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* is what you poke into the framebuffer to produce the * is what you poke into the framebuffer to produce the
* colour you requested. * colour you requested.
*/ */
if (disp->inverse) { if (fbi->cmap_inverse) {
red = 0xffff - red; red = 0xffff - red;
green = 0xffff - green; green = 0xffff - green;
blue = 0xffff - blue; blue = 0xffff - blue;
...@@ -912,7 +868,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -912,7 +868,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
red = green = blue = (19595 * red + 38470 * green + red = green = blue = (19595 * red + 38470 * green +
7471 * blue) >> 16; 7471 * blue) >> 16;
switch (fbi->fb.disp->visual) { switch (fbi->fb.fix.visual) {
case FB_VISUAL_TRUECOLOR: case FB_VISUAL_TRUECOLOR:
/* /*
* 12 or 16-bit True Colour. We encode the RGB value * 12 or 16-bit True Colour. We encode the RGB value
...@@ -942,38 +898,29 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -942,38 +898,29 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/* /*
* sa1100fb_display_dma_period() * sa1100fb_display_dma_period()
* Calculate the minimum period (in picoseconds) between two DMA * Calculate the minimum period (in picoseconds) between two DMA
* requests for the LCD controller. * requests for the LCD controller. If we hit this, it means we're
* doing nothing but LCD DMA.
*/ */
static unsigned int static unsigned int sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
{ {
unsigned int mem_bits_per_pixel;
mem_bits_per_pixel = var->bits_per_pixel;
if (mem_bits_per_pixel == 12)
mem_bits_per_pixel = 16;
/* /*
* Period = pixclock * bits_per_byte * bytes_per_transfer * Period = pixclock * bits_per_byte * bytes_per_transfer
* / memory_bits_per_pixel; * / memory_bits_per_pixel;
*/ */
return var->pixclock * 8 * 16 / mem_bits_per_pixel; return var->pixclock * 8 * 16 / var->bits_per_pixel;
} }
/* /*
* sa1100fb_decode_var(): * sa1100fb_check_var():
* Get the video params out of 'var'. If a value doesn't fit, round it up, * Round up in the following order: bits_per_pixel, xres,
* if it's too big, return -EINVAL.
*
* Suggestion: Round up in the following order: bits_per_pixel, xres,
* yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale, * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
* bitfields, horizontal timing, vertical timing. * bitfields, horizontal timing, vertical timing.
*/ */
static int static int
sa1100fb_validate_var(struct fb_var_screeninfo *var, sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
struct sa1100fb_info *fbi)
{ {
int ret = -EINVAL; struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
int rgbidx;
if (var->xres < MIN_XRES) if (var->xres < MIN_XRES)
var->xres = MIN_XRES; var->xres = MIN_XRES;
...@@ -983,42 +930,60 @@ sa1100fb_validate_var(struct fb_var_screeninfo *var, ...@@ -983,42 +930,60 @@ sa1100fb_validate_var(struct fb_var_screeninfo *var,
var->xres = fbi->max_xres; var->xres = fbi->max_xres;
if (var->yres > fbi->max_yres) if (var->yres > fbi->max_yres)
var->yres = fbi->max_yres; var->yres = fbi->max_yres;
var->xres_virtual = var->xres_virtual = max(var->xres_virtual, var->xres);
var->xres_virtual < var->xres ? var->xres : var->xres_virtual; var->yres_virtual = max(var->yres_virtual, var->yres);
var->yres_virtual =
var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel); DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
switch (var->bits_per_pixel) { switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4 #ifdef FBCON_HAS_CFB4
case 4: ret = 0; break; case 4:
rgbidx = RGB_8;
break;
#endif #endif
#ifdef FBCON_HAS_CFB8 #ifdef FBCON_HAS_CFB8
case 8: ret = 0; break; case 8:
rgbidx = RGB_8;
break;
#endif #endif
#ifdef FBCON_HAS_CFB16 #ifdef FBCON_HAS_CFB16
case 16: ret = 0; break; case 16:
rgbidx = RGB_16;
break;
#endif #endif
default: default:
break; return -EINVAL;
} }
/*
* Copy the RGB parameters for this display
* from the machine specific parameters.
*/
var->red = fbi->rgb[rgbidx]->red;
var->green = fbi->rgb[rgbidx]->green;
var->blue = fbi->rgb[rgbidx]->blue;
var->transp = fbi->rgb[rgbidx]->transp;
DPRINTK("RGBT length = %d:%d:%d:%d\n",
var->red.length, var->green.length, var->blue.length,
var->transp.length);
DPRINTK("RGBT offset = %d:%d:%d:%d\n",
var->red.offset, var->green.offset, var->blue.offset,
var->transp.offset);
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n", printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz\n",
sa1100fb_display_dma_period(var), sa1100fb_display_dma_period(var),
cpufreq_get(smp_processor_id())); cpufreq_get(smp_processor_id()));
#endif #endif
return ret; return 0;
} }
static inline void sa1100fb_set_truecolor(u_int is_true_color) static inline void sa1100fb_set_truecolor(u_int is_true_color)
{ {
DPRINTK("true_color = %d\n", is_true_color);
if (machine_is_assabet()) { if (machine_is_assabet()) {
#if 1 #if 1 // phase 4 or newer Assabet's
// phase 4 or newer Assabet's
if (is_true_color) if (is_true_color)
ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB); ASSABET_BCR_set(ASSABET_BCR_LCD_12RGB);
else else
...@@ -1033,10 +998,30 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color) ...@@ -1033,10 +998,30 @@ static inline void sa1100fb_set_truecolor(u_int is_true_color)
} }
} }
static void /*
sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) * sa1100fb_set_par():
* Set the user defined part of the display for the specified console
*/
static int sa1100fb_set_par(struct fb_info *info)
{ {
u_long palette_mem_size; struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_var_screeninfo *var = &info->var;
unsigned long palette_mem_size;
DPRINTK("set_par\n");
if (var->bits_per_pixel == 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
else if (!fbi->cmap_static)
fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
else {
/*
* Some people have weird ideas about wanting static
* pseudocolor maps. I suspect their user space
* applications are broken.
*/
fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
}
fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16; fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
...@@ -1047,10 +1032,10 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) ...@@ -1047,10 +1032,10 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
fb_set_cmap(&fbi->fb.cmap, 1, &fbi->fb); /*
* Set (any) board control register to handle new color depth
/* Set board control register to handle new color depth */ */
sa1100fb_set_truecolor(var->bits_per_pixel >= 16); sa1100fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
#ifdef CONFIG_SA1100_OMNIMETER #ifdef CONFIG_SA1100_OMNIMETER
#error Do we have to do this here? We already do it at init time. #error Do we have to do this here? We already do it at init time.
...@@ -1060,9 +1045,7 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) ...@@ -1060,9 +1045,7 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
sa1100fb_activate_var(var, fbi); sa1100fb_activate_var(var, fbi);
fbi->palette_cpu[0] = (fbi->palette_cpu[0] & return 0;
0xcfff) | palette_pbs(var);
} }
/* /*
...@@ -1072,197 +1055,38 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) ...@@ -1072,197 +1055,38 @@ sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
static int static int
sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{ {
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info; int ret, act;
struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
struct display *display = get_con_display(&fbi->fb, con);
int err, chgvar = 0, rgbidx;
DPRINTK("set_var\n");
/* act = var->activate & FB_ACTIVATE_MASK;
* Decode var contents into a par structure, adjusting any
* out of range values.
*/
err = sa1100fb_validate_var(var, fbi);
if (err)
return err;
if (var->activate & FB_ACTIVATE_TEST) ret = gen_set_var(var, con, info);
return 0;
if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) if (ret == 0 && act & FB_ACTIVATE_NOW) {
return -EINVAL; struct display *display = (con < 0) ? info->disp : fb_display + con;
if (dvar->xres != var->xres) /*
chgvar = 1; * fbcon assumes too much.
if (dvar->yres != var->yres) */
chgvar = 1; display->can_soft_blank = 1;
if (dvar->xres_virtual != var->xres_virtual)
chgvar = 1;
if (dvar->yres_virtual != var->yres_virtual)
chgvar = 1;
if (dvar->bits_per_pixel != var->bits_per_pixel)
chgvar = 1;
if (con < 0)
chgvar = 0;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
if (fbi->cmap_static)
display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else
display->visual = FB_VISUAL_PSEUDOCOLOR;
display->line_length = var->xres / 2;
display->dispsw = &fbcon_cfb4;
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB8
case 8:
if (fbi->cmap_static)
display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
else
display->visual = FB_VISUAL_PSEUDOCOLOR;
display->line_length = var->xres;
display->dispsw = &fbcon_cfb8;
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
display->visual = FB_VISUAL_TRUECOLOR;
display->line_length = var->xres * 2;
display->dispsw = &fbcon_cfb16;
display->dispsw_data = fbi->fb.pseudo_palette;
rgbidx = RGB_16;
break;
#endif
default:
rgbidx = 0;
display->dispsw = &fbcon_dummy;
break;
} }
display->next_line = display->line_length; return ret;
display->type = fbi->fb.fix.type;
display->type_aux = fbi->fb.fix.type_aux;
display->ypanstep = fbi->fb.fix.ypanstep;
display->ywrapstep = fbi->fb.fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = fbi->cmap_inverse;
*dvar = *var;
dvar->activate &= ~FB_ACTIVATE_ALL;
/*
* Copy the RGB parameters for this display
* from the machine specific parameters.
*/
dvar->red = fbi->rgb[rgbidx]->red;
dvar->green = fbi->rgb[rgbidx]->green;
dvar->blue = fbi->rgb[rgbidx]->blue;
dvar->transp = fbi->rgb[rgbidx]->transp;
DPRINTK("RGBT length = %d:%d:%d:%d\n",
dvar->red.length, dvar->green.length, dvar->blue.length,
dvar->transp.length);
DPRINTK("RGBT offset = %d:%d:%d:%d\n",
dvar->red.offset, dvar->green.offset, dvar->blue.offset,
dvar->transp.offset);
/*
* Update the old var. The fbcon drivers still use this.
* Once they are using fbi->fb.var, this can be dropped.
*/
display->var = *dvar;
/*
* If we are setting all the virtual consoles, also set the
* defaults used to create new consoles.
*/
if (var->activate & FB_ACTIVATE_ALL)
fbi->fb.disp->var = *dvar;
/*
* If the console has changed and the console has defined
* a changevar function, call that function.
*/
if (chgvar && info && fbi->fb.changevar)
fbi->fb.changevar(con);
/* If the current console is selected, activate the new var. */
if (con != fbi->fb.currcon)
return 0;
sa1100fb_hw_set_var(dvar, fbi);
return 0;
}
static int
__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct fb_cmap *dcmap = get_con_cmap(info, con);
int err = 0;
if (con == -1)
con = info->currcon;
/* no colormap allocated? (we always have "this" colour map allocated) */
if (con >= 0)
err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
if (!err && con == info->currcon)
err = fb_set_cmap(cmap, kspc, info);
if (!err)
fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
return err;
} }
static int static int
sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info) struct fb_info *info)
{ {
struct display *disp = get_con_display(info, con); struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp = (con < 0) ? info->disp : (fb_display + con);
if (disp->visual == FB_VISUAL_TRUECOLOR || /*
disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) * Make sure the user isn't doing something stupid.
*/
if (!kspc && (disp->var.bits_per_pixel == 16 || fbi->cmap_static))
return -EINVAL; return -EINVAL;
return __do_set_cmap(cmap, kspc, con, info); return gen_set_cmap(cmap, kspc, con, info);
}
static int
sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
{
struct display *display = get_con_display(info, con);
*fix = info->fix;
fix->line_length = display->line_length;
fix->visual = display->visual;
return 0;
}
static int
sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
*var = *get_con_var(info, con);
return 0;
}
static int
sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
{
struct fb_cmap *dcmap = get_con_cmap(info, con);
fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
return 0;
} }
/* /*
...@@ -1312,16 +1136,16 @@ static int sa1100fb_blank(int blank, struct fb_info *info) ...@@ -1312,16 +1136,16 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
case VESA_POWERDOWN: case VESA_POWERDOWN:
case VESA_VSYNC_SUSPEND: case VESA_VSYNC_SUSPEND:
case VESA_HSYNC_SUSPEND: case VESA_HSYNC_SUSPEND:
if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
for (i = 0; i < fbi->palette_size; i++) for (i = 0; i < fbi->palette_size; i++)
sa1100fb_setpalettereg(i, 0, 0, 0, 0, info); sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
sa1100fb_schedule_task(fbi, C_DISABLE); sa1100fb_schedule_task(fbi, C_DISABLE);
break; break;
case VESA_NO_BLANKING: case VESA_NO_BLANKING:
if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR || if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR) fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, 1, info); fb_set_cmap(&fbi->fb.cmap, 1, info);
sa1100fb_schedule_task(fbi, C_ENABLE); sa1100fb_schedule_task(fbi, C_ENABLE);
} }
...@@ -1329,71 +1153,19 @@ static int sa1100fb_blank(int blank, struct fb_info *info) ...@@ -1329,71 +1153,19 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
} }
static struct fb_ops sa1100fb_ops = { static struct fb_ops sa1100fb_ops = {
owner: THIS_MODULE, .owner = THIS_MODULE,
fb_get_fix: sa1100fb_get_fix, .fb_check_var = sa1100fb_check_var,
fb_get_var: sa1100fb_get_var, .fb_set_par = sa1100fb_set_par,
fb_set_var: sa1100fb_set_var, .fb_set_var = sa1100fb_set_var,
fb_get_cmap: sa1100fb_get_cmap, .fb_get_cmap = gen_get_cmap,
fb_set_cmap: sa1100fb_set_cmap, .fb_set_cmap = sa1100fb_set_cmap,
fb_setcolreg: sa1100fb_setcolreg, .fb_setcolreg = sa1100fb_setcolreg,
fb_blank: sa1100fb_blank, .fb_blank = sa1100fb_blank,
}; };
/*
* sa1100fb_switch():
* Change to the specified console. Palette and video mode
* are changed to the console's stored parameters.
*
* Uh oh, this can be called from a tasklet (IRQ)
*/
static int sa1100fb_switch(int con, struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp;
struct fb_cmap *cmap;
DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
if (con == info->currcon)
return 0;
if (info->currcon >= 0) {
disp = fb_display + info->currcon;
/*
* Save the old colormap and video mode.
*/
disp->var = fbi->fb.var;
if (disp->cmap.len)
fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
}
info->currcon = con;
disp = fb_display + con;
/*
* Make sure that our colourmap contains 256 entries.
*/
fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
if (disp->cmap.len)
cmap = &disp->cmap;
else
cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
fbi->fb.var = disp->var;
fbi->fb.var.activate = FB_ACTIVATE_NOW;
sa1100fb_set_var(&fbi->fb.var, con, info);
return 0;
}
static int sa1100fb_updatevar(int con, struct fb_info *info) static int sa1100fb_updatevar(int con, struct fb_info *info)
{ {
DPRINTK("entered\n"); /* we don't support panning nor scrolling */
return 0; return 0;
} }
...@@ -1401,34 +1173,14 @@ static int sa1100fb_updatevar(int con, struct fb_info *info) ...@@ -1401,34 +1173,14 @@ static int sa1100fb_updatevar(int con, struct fb_info *info)
* Calculate the PCD value from the clock rate (in picoseconds). * Calculate the PCD value from the clock rate (in picoseconds).
* We take account of the PPCR clock setting. * We take account of the PPCR clock setting.
*/ */
static inline int get_pcd(unsigned int pixclock) static inline unsigned int get_pcd(unsigned int pixclock, unsigned int cpuclock)
{ {
unsigned int pcd; unsigned int pcd = cpuclock / 100;
if (pixclock) { pcd *= pixclock;
pcd = cpufreq_get(0) / 100; pcd /= 10000000;
pcd *= pixclock;
pcd /= 10000000; return pcd + 1; /* make up for integer math truncations */
pcd += 1; /* make up for integer math truncations */
} else {
/*
* People seem to be missing this message. Make it big.
* Make it stand out. Make sure people see it.
*/
printk(KERN_WARNING "******************************************************\n");
printk(KERN_WARNING "** ZERO PIXEL CLOCK DETECTED **\n");
printk(KERN_WARNING "** You are using a zero pixclock. This means that **\n");
printk(KERN_WARNING "** clock scaling will not be able to adjust your **\n");
printk(KERN_WARNING "** your timing parameters appropriately, and the **\n");
printk(KERN_WARNING "** bandwidth calculations will fail to work. This **\n");
printk(KERN_WARNING "** will shortly become an error condition, which **\n");
printk(KERN_WARNING "** will prevent your LCD display working. Please **\n");
printk(KERN_WARNING "** send your patches in as soon as possible to shut **\n");
printk(KERN_WARNING "** this message up. **\n");
printk(KERN_WARNING "******************************************************\n");
pcd = 0;
}
return pcd;
} }
/* /*
...@@ -1439,7 +1191,7 @@ static inline int get_pcd(unsigned int pixclock) ...@@ -1439,7 +1191,7 @@ static inline int get_pcd(unsigned int pixclock)
static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi) static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
{ {
struct sa1100fb_lcd_reg new_regs; struct sa1100fb_lcd_reg new_regs;
u_int half_screen_size, yres, pcd = get_pcd(var->pixclock); u_int half_screen_size, yres, pcd;
u_long flags; u_long flags;
DPRINTK("Configuring SA1100 LCD\n"); DPRINTK("Configuring SA1100 LCD\n");
...@@ -1502,13 +1254,10 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ ...@@ -1502,13 +1254,10 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
LCCR2_BegFrmDel(var->upper_margin) + LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin); LCCR2_EndFrmDel(var->lower_margin);
new_regs.lccr3 = fbi->lccr3 | pcd = get_pcd(var->pixclock, cpufreq_get(0));
new_regs.lccr3 = LCCR3_PixClkDiv(pcd) | fbi->lccr3 |
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) | (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
LCCR3_ACBsCntOff;
if (pcd)
new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0); DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1); DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
...@@ -1547,61 +1296,20 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_ ...@@ -1547,61 +1296,20 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
* to ensure that things happen in the right way 100% of time time. * to ensure that things happen in the right way 100% of time time.
* -- rmk * -- rmk
*/ */
static inline void __sa1100fb_backlight_power(struct sa1100fb_info *fbi, int on)
/*
* FIXME: move LCD power stuff into sa1100fb_power_up_lcd()
* Also, I'm expecting that the backlight stuff should
* be handled differently.
*/
static inline void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
{
DPRINTK("backlight on\n");
if (sa1100fb_backlight_power)
sa1100fb_backlight_power(1);
}
/*
* FIXME: move LCD power stuf into sa1100fb_power_down_lcd()
* Also, I'm expecting that the backlight stuff should
* be handled differently.
*/
static inline void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
{ {
DPRINTK("backlight off\n"); DPRINTK("backlight o%s\n", on ? "n" : "ff");
if (sa1100fb_backlight_power) if (sa1100fb_backlight_power)
sa1100fb_backlight_power(0); sa1100fb_backlight_power(on);
} }
static inline void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi) static inline void __sa1100fb_lcd_power(struct sa1100fb_info *fbi, int on)
{ {
DPRINTK("LCD power on\n"); DPRINTK("LCD power o%s\n", on ? "n" : "ff");
if (sa1100fb_lcd_power) if (sa1100fb_lcd_power)
sa1100fb_lcd_power(1); sa1100fb_lcd_power(on);
#ifdef CONFIG_SA1100_STORK
if (machine_is_stork()) {
storkSetLCDCPLD(0, 1);
storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
}
#endif
}
static inline void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
{
DPRINTK("LCD power off\n");
if (sa1100fb_lcd_power)
sa1100fb_lcd_power(0);
#ifdef CONFIG_SA1100_STORK
if (machine_is_stork()) {
storkSetLCDCPLD(0, 0);
storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
}
#endif
} }
static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
...@@ -1630,38 +1338,9 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi) ...@@ -1630,38 +1338,9 @@ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
} }
if (machine_is_cerf()) { /* GPIO15 is used as a bypass for 3.8" displays */
/* GPIO15 is used as a bypass for 3.8" displays */ if (machine_is_cerf())
mask |= GPIO_GPIO15; mask |= GPIO_GPIO15;
#ifdef CONFIG_SA1100_CERF
#warning Read Me Now!
#endif
#if 0 /* if this causes you problems, mail <rmk@arm.linux.org.uk> please. */
/*
* This was enabled for the 72_A version only, which is a _color_
* _dual_ LCD. Now look at the generic test above, and calculate
* the mask value for a colour dual display...
*
* I therefore conclude that the code below is redundant, and will
* be killed at the start of November 2001.
*/
/* FIXME: why is this? The Cerf's display doesn't seem
* to be dual scan or active. I just leave it here,
* but in my opinion this is definitively wrong.
* -- Erik <J.A.K.Mouw@its.tudelft.nl>
*/
/* REPLY: Umm.. Well to be honest, the 5.7" LCD which
* this was used for does not use these pins, but
* apparently all hell breaks loose if they are not
* set on the Cerf, so we decided to leave them in ;)
* -- Daniel Chemko <dchemko@intrinsyc.com>
*/
/* color {dual/single} passive */
mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
#endif
}
if (mask) { if (mask) {
GPDR |= mask; GPDR |= mask;
...@@ -1733,7 +1412,7 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi) ...@@ -1733,7 +1412,7 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
} }
#endif #endif
#ifdef CONFIG_SA1100_HUW_WEBPANEL #ifdef CONFIG_SA1100_HUW_WEBPANEL
#error Move me into sa1100fb_power_up_lcd and/or sa1100fb_backlight_on #error Move me into __sa1100fb_lcd_power and/or __sa1100fb_backlight_power
if (machine_is_huw_webpanel()) { if (machine_is_huw_webpanel()) {
// dont forget to set the control lines to zero (?) // dont forget to set the control lines to zero (?)
DPRINTK("ShutDown HuW LCD controller\n"); DPRINTK("ShutDown HuW LCD controller\n");
...@@ -1806,10 +1485,10 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state) ...@@ -1806,10 +1485,10 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
if (old_state != C_DISABLE) { if (old_state != C_DISABLE) {
fbi->state = state; fbi->state = state;
sa1100fb_backlight_off(fbi); __sa1100fb_backlight_power(fbi, 0);
if (old_state != C_DISABLE_CLKCHANGE) if (old_state != C_DISABLE_CLKCHANGE)
sa1100fb_disable_controller(fbi); sa1100fb_disable_controller(fbi);
sa1100fb_power_down_lcd(fbi); __sa1100fb_lcd_power(fbi, 0);
} }
break; break;
...@@ -1855,9 +1534,9 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state) ...@@ -1855,9 +1534,9 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
if (old_state != C_ENABLE) { if (old_state != C_ENABLE) {
fbi->state = C_ENABLE; fbi->state = C_ENABLE;
sa1100fb_setup_gpio(fbi); sa1100fb_setup_gpio(fbi);
sa1100fb_power_up_lcd(fbi); __sa1100fb_lcd_power(fbi, 1);
sa1100fb_enable_controller(fbi); sa1100fb_enable_controller(fbi);
sa1100fb_backlight_on(fbi); __sa1100fb_backlight_power(fbi, 1);
} }
break; break;
} }
...@@ -1888,18 +1567,19 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) ...@@ -1888,18 +1567,19 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
int i; int i;
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
struct display *disp = &fb_display[i];
unsigned int period; unsigned int period;
/* /*
* Do we own this display? * Do we own this display?
*/ */
if (fb_display[i].fb_info != &fbi->fb) if (disp->fb_info != &fbi->fb)
continue; continue;
/* /*
* Ok, calculate its DMA period * Ok, calculate its DMA period
*/ */
period = sa1100fb_display_dma_period(get_con_var(&fbi->fb, i)); period = sa1100fb_display_dma_period(&disp->var);
if (period < min_period) if (period < min_period)
min_period = period; min_period = period;
} }
...@@ -1913,33 +1593,42 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi) ...@@ -1913,33 +1593,42 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
* subsystem. * subsystem.
*/ */
static int static int
sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val, sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
void *data) void *data)
{ {
struct sa1100fb_info *fbi = TO_INF(nb, clockchg); struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
struct cpufreq_minmax *mm = data; struct cpufreq_freqs *f = data;
u_int pcd; u_int pcd;
switch (val) { switch (val) {
case CPUFREQ_MINMAX:
printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
mm->cur_freq, mm->new_freq);
/* todo: fill in min/max values */
break;
case CPUFREQ_PRECHANGE: case CPUFREQ_PRECHANGE:
set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE); set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
break; break;
case CPUFREQ_POSTCHANGE: case CPUFREQ_POSTCHANGE:
pcd = get_pcd(fbi->fb.var.pixclock); pcd = get_pcd(fbi->fb.var.pixclock, f->new);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break; break;
} }
return 0; return 0;
} }
static int
sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
void *data)
{
struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
struct cpufreq_policy *policy = data;
if (val == CPUFREQ_INCOMPATIBLE) {
printk(KERN_DEBUG "min dma period: %d ps, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
policy->max);
/* todo: fill in min/max values */
}
return 0;
}
#endif #endif
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -2015,8 +1704,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -2015,8 +1704,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display)); memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
fbi->fb.currcon = -1;
strcpy(fbi->fb.fix.id, SA1100_NAME); strcpy(fbi->fb.fix.id, SA1100_NAME);
fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS; fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
...@@ -2024,6 +1711,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -2024,6 +1711,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->fb.fix.xpanstep = 0; fbi->fb.fix.xpanstep = 0;
fbi->fb.fix.ypanstep = 0; fbi->fb.fix.ypanstep = 0;
fbi->fb.fix.ywrapstep = 0; fbi->fb.fix.ywrapstep = 0;
fbi->fb.fix.line_length = 0;
fbi->fb.fix.accel = FB_ACCEL_NONE; fbi->fb.fix.accel = FB_ACCEL_NONE;
fbi->fb.var.nonstd = 0; fbi->fb.var.nonstd = 0;
...@@ -2038,7 +1726,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -2038,7 +1726,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->fb.fbops = &sa1100fb_ops; fbi->fb.fbops = &sa1100fb_ops;
fbi->fb.changevar = NULL; fbi->fb.changevar = NULL;
fbi->fb.switch_con = sa1100fb_switch; fbi->fb.switch_con = gen_switch;
fbi->fb.updatevar = sa1100fb_updatevar; fbi->fb.updatevar = sa1100fb_updatevar;
fbi->fb.flags = FBINFO_FLAG_DEFAULT; fbi->fb.flags = FBINFO_FLAG_DEFAULT;
fbi->fb.node = NODEV; fbi->fb.node = NODEV;
...@@ -2052,6 +1740,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -2052,6 +1740,16 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
inf = sa1100fb_get_machine_info(fbi); inf = sa1100fb_get_machine_info(fbi);
/*
* People just don't seem to get this. We don't support
* anything but correct entries now, so panic if someone
* does something stupid.
*/
if (inf->lccr3 & (LCCR3_VrtSnchL|LCCR3_HorSnchL|0xff) ||
inf->pixclock == 0)
panic("sa1100fb error: invalid LCCR3 fields set or zero "
"pixclock.");
fbi->max_xres = inf->xres; fbi->max_xres = inf->xres;
fbi->fb.var.xres = inf->xres; fbi->fb.var.xres = inf->xres;
fbi->fb.var.xres_virtual = inf->xres; fbi->fb.var.xres_virtual = inf->xres;
...@@ -2077,6 +1775,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void) ...@@ -2077,6 +1775,7 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->task_state = (u_char)-1; fbi->task_state = (u_char)-1;
fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres * fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
fbi->max_bpp / 8; fbi->max_bpp / 8;
fbi->fb.disp->inverse = inf->cmap_inverse;
init_waitqueue_head(&fbi->ctrlr_wait); init_waitqueue_head(&fbi->ctrlr_wait);
INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi); INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
...@@ -2116,7 +1815,7 @@ int __init sa1100fb_init(void) ...@@ -2116,7 +1815,7 @@ int __init sa1100fb_init(void)
#endif #endif
#ifdef CONFIG_SA1100_FREEBIRD #ifdef CONFIG_SA1100_FREEBIRD
#error Please move this into sa1100fb_power_up_lcd #error Please move this into __sa1100fb_lcd_power
if (machine_is_freebird()) { if (machine_is_freebird()) {
BCR_set(BCR_FREEBIRD_LCD_DISP); BCR_set(BCR_FREEBIRD_LCD_DISP);
mdelay(20); mdelay(20);
...@@ -2141,8 +1840,10 @@ int __init sa1100fb_init(void) ...@@ -2141,8 +1840,10 @@ int __init sa1100fb_init(void)
fbi->pm->data = fbi; fbi->pm->data = fbi;
#endif #endif
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier; fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
cpufreq_register_notifier(&fbi->clockchg); fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
#endif #endif
/* /*
......
...@@ -107,7 +107,8 @@ struct sa1100fb_info { ...@@ -107,7 +107,8 @@ struct sa1100fb_info {
struct pm_dev *pm; struct pm_dev *pm;
#endif #endif
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
struct notifier_block clockchg; struct notifier_block freq_transition;
struct notifier_block freq_policy;
#endif #endif
}; };
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* History: * History:
* *
* 2001-10-?? Andrew Christian Added support for iPAQ H3800 * 2001-10-?? Andrew Christian Added support for iPAQ H3800
* *
*/ */
...@@ -26,6 +26,11 @@ ...@@ -26,6 +26,11 @@
/* generalized support for H3xxx series Compaq Pocket PC's */ /* generalized support for H3xxx series Compaq Pocket PC's */
#define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800()) #define machine_is_h3xxx() (machine_is_h3100() || machine_is_h3600() || machine_is_h3800())
/* Physical memory regions corresponding to chip selects */
#define H3600_EGPIO_PHYS (SA1100_CS5_PHYS + 0x01000000)
#define H3600_BANK_2_PHYS SA1100_CS2_PHYS
#define H3600_BANK_4_PHYS SA1100_CS4_PHYS
/* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */ /* Virtual memory regions corresponding to chip selects 2 & 4 (used on sleeves) */
#define H3600_EGPIO_VIRT 0xf0000000 #define H3600_EGPIO_VIRT 0xf0000000
#define H3600_BANK_2_VIRT 0xf1000000 #define H3600_BANK_2_VIRT 0xf1000000
...@@ -36,8 +41,7 @@ ...@@ -36,8 +41,7 @@
--- these are common across all current iPAQ platforms --- these are common across all current iPAQ platforms
*/ */
#define GPIO_H3600_NPOWER_BUTTON GPIO_GPIO (0) /* Also known as the "off button" */ #define GPIO_H3600_NPOWER_BUTTON GPIO_GPIO (0) /* Also known as the "off button" */
#define GPIO_H3600_MICROCONTROLLER GPIO_GPIO (1) /* From ASIC2 on H3800 */
#define GPIO_H3600_PCMCIA_CD1 GPIO_GPIO (10) #define GPIO_H3600_PCMCIA_CD1 GPIO_GPIO (10)
#define GPIO_H3600_PCMCIA_IRQ1 GPIO_GPIO (11) #define GPIO_H3600_PCMCIA_IRQ1 GPIO_GPIO (11)
...@@ -56,83 +60,105 @@ ...@@ -56,83 +60,105 @@
#define GPIO_H3600_COM_CTS GPIO_GPIO (25) #define GPIO_H3600_COM_CTS GPIO_GPIO (25)
#define GPIO_H3600_COM_RTS GPIO_GPIO (26) #define GPIO_H3600_COM_RTS GPIO_GPIO (26)
#define IRQ_GPIO_H3600_NPOWER_BUTTON IRQ_GPIO0 #define IRQ_GPIO_H3600_NPOWER_BUTTON IRQ_GPIO0
#define IRQ_GPIO_H3600_MICROCONTROLLER IRQ_GPIO1
#define IRQ_GPIO_H3600_PCMCIA_CD1 IRQ_GPIO10 #define IRQ_GPIO_H3600_PCMCIA_CD1 IRQ_GPIO10
#define IRQ_GPIO_H3600_PCMCIA_IRQ1 IRQ_GPIO11 #define IRQ_GPIO_H3600_PCMCIA_IRQ1 IRQ_GPIO11
#define IRQ_GPIO_H3600_PCMCIA_CD0 IRQ_GPIO17 #define IRQ_GPIO_H3600_PCMCIA_CD0 IRQ_GPIO17
#define IRQ_GPIO_H3600_PCMCIA_IRQ0 IRQ_GPIO21 #define IRQ_GPIO_H3600_PCMCIA_IRQ0 IRQ_GPIO21
#define IRQ_GPIO_H3600_COM_DCD IRQ_GPIO23 #define IRQ_GPIO_H3600_COM_DCD IRQ_GPIO23
#define IRQ_GPIO_H3600_OPT_IRQ IRQ_GPIO24 #define IRQ_GPIO_H3600_OPT_IRQ IRQ_GPIO24
#define IRQ_GPIO_H3600_COM_CTS IRQ_GPIO25 #define IRQ_GPIO_H3600_COM_CTS IRQ_GPIO25
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
enum ipaq_model {
IPAQ_H3100,
IPAQ_H3600,
IPAQ_H3800
};
enum ipaq_egpio_type { enum ipaq_egpio_type {
IPAQ_EGPIO_LCD_ON, /* Power to the LCD panel */ IPAQ_EGPIO_LCD_POWER, /* Power to the LCD panel */
IPAQ_EGPIO_CODEC_NRESET, /* Clear to reset the audio codec (remember to return high) */ IPAQ_EGPIO_CODEC_NRESET, /* Clear to reset the audio codec (remember to return high) */
IPAQ_EGPIO_AUDIO_ON, /* Audio power */ IPAQ_EGPIO_AUDIO_ON, /* Audio power */
IPAQ_EGPIO_QMUTE, /* Audio muting */ IPAQ_EGPIO_QMUTE, /* Audio muting */
IPAQ_EGPIO_OPT_NVRAM_ON, /* Non-volatile RAM on extension sleeves (SPI interface) */ IPAQ_EGPIO_OPT_NVRAM_ON, /* Non-volatile RAM on extension sleeves (SPI interface) */
IPAQ_EGPIO_OPT_ON, /* Power to extension sleeves */ IPAQ_EGPIO_OPT_ON, /* Power to extension sleeves */
IPAQ_EGPIO_CARD_RESET, /* Reset PCMCIA cards on extension sleeve (???) */ IPAQ_EGPIO_CARD_RESET, /* Reset PCMCIA cards on extension sleeve (???) */
IPAQ_EGPIO_OPT_RESET, /* Reset option pack (???) */ IPAQ_EGPIO_OPT_RESET, /* Reset option pack (???) */
IPAQ_EGPIO_IR_ON, /* IR sensor/emitter power */ IPAQ_EGPIO_IR_ON, /* IR sensor/emitter power */
IPAQ_EGPIO_IR_FSEL, /* IR speed selection 1->fast, 0->slow */ IPAQ_EGPIO_IR_FSEL, /* IR speed selection 1->fast, 0->slow */
IPAQ_EGPIO_RS232_ON, /* Maxim RS232 chip power */ IPAQ_EGPIO_RS232_ON, /* Maxim RS232 chip power */
IPAQ_EGPIO_VPP_ON, /* Turn on power to flash programming */ IPAQ_EGPIO_VPP_ON, /* Turn on power to flash programming */
IPAQ_EGPIO_LCD_ENABLE, /* Enable/disable LCD controller */
}; };
struct ipaq_model_ops { struct ipaq_model_ops {
enum ipaq_model model;
const char *generic_name; const char *generic_name;
void (*initialize)(void); void (*control)(enum ipaq_egpio_type, int);
void (*control)(enum ipaq_egpio_type, int);
unsigned long (*read)(void); unsigned long (*read)(void);
void (*blank_callback)(int blank);
int (*pm_callback)(int req); /* Primary model callback */
int (*pm_callback_aux)(int req); /* Secondary callback (used by HAL modules) */
}; };
extern struct ipaq_model_ops ipaq_model_ops; extern struct ipaq_model_ops ipaq_model_ops;
static __inline__ enum ipaq_model h3600_model( void ) { static __inline__ const char * h3600_generic_name(void)
return ipaq_model_ops.model; {
}
static __inline__ const char * h3600_generic_name( void ) {
return ipaq_model_ops.generic_name; return ipaq_model_ops.generic_name;
} }
static __inline__ void init_h3600_egpio( void ) { static __inline__ void assign_h3600_egpio(enum ipaq_egpio_type x, int level)
if (ipaq_model_ops.initialize) {
ipaq_model_ops.initialize();
}
static __inline__ void assign_h3600_egpio( enum ipaq_egpio_type x, int level ) {
if (ipaq_model_ops.control) if (ipaq_model_ops.control)
ipaq_model_ops.control(x,level); ipaq_model_ops.control(x,level);
} }
static __inline__ void clr_h3600_egpio( enum ipaq_egpio_type x ) { static __inline__ void clr_h3600_egpio(enum ipaq_egpio_type x)
{
if (ipaq_model_ops.control) if (ipaq_model_ops.control)
ipaq_model_ops.control(x,0); ipaq_model_ops.control(x,0);
} }
static __inline__ void set_h3600_egpio( enum ipaq_egpio_type x ) { static __inline__ void set_h3600_egpio(enum ipaq_egpio_type x)
{
if (ipaq_model_ops.control) if (ipaq_model_ops.control)
ipaq_model_ops.control(x,1); ipaq_model_ops.control(x,1);
} }
static __inline__ unsigned long read_h3600_egpio( void ) { static __inline__ unsigned long read_h3600_egpio(void)
{
if (ipaq_model_ops.read) if (ipaq_model_ops.read)
return ipaq_model_ops.read(); return ipaq_model_ops.read();
return 0; return 0;
} }
static __inline__ int h3600_register_blank_callback(void (*f)(int))
{
ipaq_model_ops.blank_callback = f;
return 0;
}
static __inline__ void h3600_unregister_blank_callback(void (*f)(int))
{
ipaq_model_ops.blank_callback = NULL;
}
static __inline__ int h3600_register_pm_callback(int (*f)(int))
{
ipaq_model_ops.pm_callback_aux = f;
return 0;
}
static __inline__ void h3600_unregister_pm_callback(int (*f)(int))
{
ipaq_model_ops.pm_callback_aux = NULL;
}
static __inline__ int h3600_power_management(int req)
{
if (ipaq_model_ops.pm_callback)
return ipaq_model_ops.pm_callback(req);
return 0;
}
#endif /* ASSEMBLY */ #endif /* ASSEMBLY */
#endif /* _INCLUDE_H3600_H_ */ #endif /* _INCLUDE_H3600_H_ */
...@@ -108,18 +108,18 @@ ...@@ -108,18 +108,18 @@
#define AUDDTS (IRQ_BOARD_END + 40) #define AUDDTS (IRQ_BOARD_END + 40)
#define AUDRDD (IRQ_BOARD_END + 41) #define AUDRDD (IRQ_BOARD_END + 41)
#define AUDSTO (IRQ_BOARD_END + 42) #define AUDSTO (IRQ_BOARD_END + 42)
#define USBPWR (IRQ_BOARD_END + 43) #define IRQ_USBPWR (IRQ_BOARD_END + 43)
#define NIRQHCIM (IRQ_BOARD_END + 44) #define IRQ_NHCIM (IRQ_BOARD_END + 44)
#define IRQHCIBUFFACC (IRQ_BOARD_END + 45) #define IRQ_HCIBUFFACC (IRQ_BOARD_END + 45)
#define IRQHCIRMTWKP (IRQ_BOARD_END + 46) #define IRQ_HCIRMTWKP (IRQ_BOARD_END + 46)
#define NHCIMFCIR (IRQ_BOARD_END + 47) #define IRQ_NHCIMFCIR (IRQ_BOARD_END + 47)
#define USB_PORT_RESUME (IRQ_BOARD_END + 48) #define IRQ_USB_PORT_RESUME (IRQ_BOARD_END + 48)
#define S0_READY_NINT (IRQ_BOARD_END + 49) #define IRQ_S0_READY_NINT (IRQ_BOARD_END + 49)
#define S1_READY_NINT (IRQ_BOARD_END + 50) #define IRQ_S1_READY_NINT (IRQ_BOARD_END + 50)
#define S0_CD_VALID (IRQ_BOARD_END + 51) #define IRQ_S0_CD_VALID (IRQ_BOARD_END + 51)
#define S1_CD_VALID (IRQ_BOARD_END + 52) #define IRQ_S1_CD_VALID (IRQ_BOARD_END + 52)
#define S0_BVD1_STSCHG (IRQ_BOARD_END + 53) #define IRQ_S0_BVD1_STSCHG (IRQ_BOARD_END + 53)
#define S1_BVD1_STSCHG (IRQ_BOARD_END + 54) #define IRQ_S1_BVD1_STSCHG (IRQ_BOARD_END + 54)
/* /*
* Figure out the MAX IRQ number. * Figure out the MAX IRQ number.
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
* Otherwise, we have the standard IRQs only. * Otherwise, we have the standard IRQs only.
*/ */
#ifdef CONFIG_SA1111 #ifdef CONFIG_SA1111
#define NR_IRQS (S1_BVD1_STSCHG + 1) #define NR_IRQS (IRQ_S1_BVD1_STSCHG + 1)
#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ #elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
defined(CONFIG_SA1100_GRAPHICSMASTER) || \ defined(CONFIG_SA1100_GRAPHICSMASTER) || \
defined(CONFIG_SA1100_H3800) defined(CONFIG_SA1100_H3800)
......
...@@ -64,18 +64,10 @@ ...@@ -64,18 +64,10 @@
#define SA1111_SMCR 0x0004 #define SA1111_SMCR 0x0004
#define SA1111_SKID 0x0008 #define SA1111_SKID 0x0008
#define _SBI_SKCR _SA1111(SA1111_SKCR)
#define _SBI_SMCR _SA1111(SA1111_SMCR)
#define _SBI_SKID _SA1111(SA1111_SKID)
#if LANGUAGE == C
#define SBI_SKCR __CCREG(SA1111_SKCR) #define SBI_SKCR __CCREG(SA1111_SKCR)
#define SBI_SMCR __CCREG(SA1111_SMCR) #define SBI_SMCR __CCREG(SA1111_SMCR)
#define SBI_SKID __CCREG(SA1111_SKID) #define SBI_SKID __CCREG(SA1111_SKID)
#endif /* LANGUAGE == C */
#define SKCR_PLL_BYPASS (1<<0) #define SKCR_PLL_BYPASS (1<<0)
#define SKCR_RCLKEN (1<<1) #define SKCR_RCLKEN (1<<1)
#define SKCR_SLEEP (1<<2) #define SKCR_SLEEP (1<<2)
...@@ -135,22 +127,10 @@ ...@@ -135,22 +127,10 @@
#define SA1111_SKPMC 0x020c #define SA1111_SKPMC 0x020c
#define SA1111_SKPTC 0x0210 #define SA1111_SKPTC 0x0210
#define SA1111_SKPEN0 0x0214 #define SA1111_SKPEN0 0x0214
#define SA1111_SKPWN0 0x0218 #define SA1111_SKPWM0 0x0218
#define SA1111_SKPEN1 0x021c #define SA1111_SKPEN1 0x021c
#define SA1111_SKPWM1 0x0220 #define SA1111_SKPWM1 0x0220
#define _SKPCR _SA1111(SA1111_SKPCR)
#define _SKCDR _SA1111(SA1111_SKCDR)
#define _SKAUD _SA1111(SA1111_SKAUD)
#define _SKPMC _SA1111(SA1111_SKPMC)
#define _SKPTC _SA1111(SA1111_SKPTC)
#define _SKPEN0 _SA1111(SA1111_SKPEN0)
#define _SKPWM0 _SA1111(SA1111_SKPWM0)
#define _SKPEN1 _SA1111(SA1111_SKPEN1)
#define _SKPWM1 _SA1111(SA1111_SKPWM1)
#if LANGUAGE == C
#define SKPCR __CCREG(SA1111_SKPCR) #define SKPCR __CCREG(SA1111_SKPCR)
#define SKCDR __CCREG(SA1111_SKCDR) #define SKCDR __CCREG(SA1111_SKCDR)
#define SKAUD __CCREG(SA1111_SKAUD) #define SKAUD __CCREG(SA1111_SKAUD)
...@@ -161,8 +141,6 @@ ...@@ -161,8 +141,6 @@
#define SKPEN1 __CCREG(SA1111_SKPEN1) #define SKPEN1 __CCREG(SA1111_SKPEN1)
#define SKPWM1 __CCREG(SA1111_SKPWM1) #define SKPWM1 __CCREG(SA1111_SKPWM1)
#endif /* LANGUAGE == C */
#define SKPCR_UCLKEN (1<<0) #define SKPCR_UCLKEN (1<<0)
#define SKPCR_ACCLKEN (1<<1) #define SKPCR_ACCLKEN (1<<1)
#define SKPCR_I2SCLKEN (1<<2) #define SKPCR_I2SCLKEN (1<<2)
...@@ -176,21 +154,14 @@ ...@@ -176,21 +154,14 @@
/* /*
* USB Host controller * USB Host controller
*/ */
#define _USB_OHCI_OP_BASE _SA1111( 0x400 ) #define SA1111_USB 0x0400
#define _USB_STATUS _SA1111( 0x518 )
#define _USB_RESET _SA1111( 0x51c )
#define _USB_INTERRUPTEST _SA1111( 0x520 )
#define _USB_EXTENT (_USB_INTERRUPTEST - _USB_OHCI_OP_BASE + 4)
#if LANGUAGE == C
#define USB_OHCI_OP_BASE __CCREG(0x0400)
#define USB_STATUS __CCREG(0x0518)
#define USB_RESET __CCREG(0x051c)
#define USB_INTERRUPTEST __CCReG(0x0520)
#endif /* LANGUAGE == C */ /*
* Offsets from SA1111_USB_BASE
*/
#define SA1111_USB_STATUS 0x0118
#define SA1111_USB_RESET 0x011c
#define SA1111_USB_IRQTEST 0x0120
#define USB_RESET_FORCEIFRESET (1 << 0) #define USB_RESET_FORCEIFRESET (1 << 0)
#define USB_RESET_FORCEHCRESET (1 << 1) #define USB_RESET_FORCEHCRESET (1 << 1)
...@@ -451,82 +422,56 @@ ...@@ -451,82 +422,56 @@
* WAKE_POL0 Wake-up polarity selection 0 * WAKE_POL0 Wake-up polarity selection 0
* WAKE_POL1 Wake-up polarity selection 1 * WAKE_POL1 Wake-up polarity selection 1
*/ */
#define SA1111_INTC 0x1600
#define SA1111_INTTEST0 0x1600 /*
#define SA1111_INTTEST1 0x1604 * These are offsets from the above base.
#define SA1111_INTEN0 0x1608 */
#define SA1111_INTEN1 0x160c #define SA1111_INTTEST0 0x0000
#define SA1111_INTPOL0 0x1610 #define SA1111_INTTEST1 0x0004
#define SA1111_INTPOL1 0x1614 #define SA1111_INTEN0 0x0008
#define SA1111_INTTSTSEL 0x1618 #define SA1111_INTEN1 0x000c
#define SA1111_INTSTATCLR0 0x161c #define SA1111_INTPOL0 0x0010
#define SA1111_INTSTATCLR1 0x1620 #define SA1111_INTPOL1 0x0014
#define SA1111_INTSET0 0x1624 #define SA1111_INTTSTSEL 0x0018
#define SA1111_INTSET1 0x1628 #define SA1111_INTSTATCLR0 0x001c
#define SA1111_WAKE_EN0 0x162c #define SA1111_INTSTATCLR1 0x0020
#define SA1111_WAKE_EN1 0x1630 #define SA1111_INTSET0 0x0024
#define SA1111_WAKE_POL0 0x1634 #define SA1111_INTSET1 0x0028
#define SA1111_WAKE_POL1 0x1638 #define SA1111_WAKEEN0 0x002c
#define SA1111_WAKEEN1 0x0030
#define _INTTEST0 _SA1111(SA1111_INTTEST0) #define SA1111_WAKEPOL0 0x0034
#define _INTTEST1 _SA1111(SA1111_INTTEST1) #define SA1111_WAKEPOL1 0x0038
#define _INTEN0 _SA1111(SA1111_INTEN0)
#define _INTEN1 _SA1111(SA1111_INTEN1) #define INTTEST0 __CCREG(SA1111_INTC + SA1111_INTTEST0)
#define _INTPOL0 _SA1111(SA1111_INTPOL0) #define INTTEST1 __CCREG(SA1111_INTC + SA1111_INTTEST1)
#define _INTPOL1 _SA1111(SA1111_INTPOL1) #define INTEN0 __CCREG(SA1111_INTC + SA1111_INTEN0)
#define _INTTSTSEL _SA1111(SA1111_INTTSTSEL) #define INTEN1 __CCREG(SA1111_INTC + SA1111_INTEN1)
#define _INTSTATCLR0 _SA1111(SA1111_INTSTATCLR0) #define INTPOL0 __CCREG(SA1111_INTC + SA1111_INTPOL0)
#define _INTSTATCLR1 _SA1111(SA1111_INTSTATCLR1) #define INTPOL1 __CCREG(SA1111_INTC + SA1111_INTPOL1)
#define _INTSET0 _SA1111(SA1111_INTSET0) #define INTTSTSEL __CCREG(SA1111_INTC + SA1111_INTTSTSEL)
#define _INTSET1 _SA1111(SA1111_INTSET1) #define INTSTATCLR0 __CCREG(SA1111_INTC + SA1111_INTSTATCLR0)
#define _WAKE_EN0 _SA1111(SA1111_WAKE_EN0) #define INTSTATCLR1 __CCREG(SA1111_INTC + SA1111_INTSTATCLR1)
#define _WAKE_EN1 _SA1111(SA1111_WAKE_EN1) #define INTSET0 __CCREG(SA1111_INTC + SA1111_INTSET0)
#define _WAKE_POL0 _SA1111(SA1111_WAKE_POL0) #define INTSET1 __CCREG(SA1111_INTC + SA1111_INTSET1)
#define _WAKE_POL1 _SA1111(SA1111_WAKE_POL1) #define WAKE_EN0 __CCREG(SA1111_INTC + SA1111_WAKEEN0)
#define WAKE_EN1 __CCREG(SA1111_INTC + SA1111_WAKEEN1)
#if LANGUAGE == C #define WAKE_POL0 __CCREG(SA1111_INTC + SA1111_WAKEPOL0)
#define WAKE_POL1 __CCREG(SA1111_INTC + SA1111_WAKEPOL1)
#define INTTEST0 __CCREG(SA1111_INTTEST0)
#define INTTEST1 __CCREG(SA1111_INTTEST1)
#define INTEN0 __CCREG(SA1111_INTEN0)
#define INTEN1 __CCREG(SA1111_INTEN1)
#define INTPOL0 __CCREG(SA1111_INTPOL0)
#define INTPOL1 __CCREG(SA1111_INTPOL1)
#define INTTSTSEL __CCREG(SA1111_INTTSTSEL)
#define INTSTATCLR0 __CCREG(SA1111_INTSTATCLR0)
#define INTSTATCLR1 __CCREG(SA1111_INTSTATCLR1)
#define INTSET0 __CCREG(SA1111_INTSET0)
#define INTSET1 __CCREG(SA1111_INTSET1)
#define WAKE_EN0 __CCREG(SA1111_WAKE_EN0)
#define WAKE_EN1 __CCREG(SA1111_WAKE_EN1)
#define WAKE_POL0 __CCREG(SA1111_WAKE_POL0)
#define WAKE_POL1 __CCREG(SA1111_WAKE_POL1)
#endif /* LANGUAGE == C */
/* /*
* PS/2 Trackpad and Mouse Interfaces * PS/2 Trackpad and Mouse Interfaces
* *
* Registers (prefix kbd applies to trackpad interface, mse to mouse) * Registers
* KBDCR Control Register * PS2CR Control Register
* KBDSTAT Status Register * PS2STAT Status Register
* KBDDATA Transmit/Receive Data register * PS2DATA Transmit/Receive Data register
* KBDCLKDIV Clock Division Register * PS2CLKDIV Clock Division Register
* KBDPRECNT Clock Precount Register * PS2PRECNT Clock Precount Register
* KBDTEST1 Test register 1 * PS2TEST1 Test register 1
* KBDTEST2 Test register 2 * PS2TEST2 Test register 2
* KBDTEST3 Test register 3 * PS2TEST3 Test register 3
* KBDTEST4 Test register 4 * PS2TEST4 Test register 4
* MSECR
* MSESTAT
* MSEDATA
* MSECLKDIV
* MSEPRECNT
* MSETEST1
* MSETEST2
* MSETEST3
* MSETEST4
*
*/ */
#define SA1111_KBD 0x0a00 #define SA1111_KBD 0x0a00
...@@ -564,17 +509,14 @@ ...@@ -564,17 +509,14 @@
* PCSSR Sleep State Register * PCSSR Sleep State Register
*/ */
#define _PCCR _SA1111( 0x1800 ) #define SA1111_PCMCIA 0x1600
#define _PCSSR _SA1111( 0x1804 )
#define _PCSR _SA1111( 0x1808 )
#if LANGUAGE == C
#define PCCR __CCREG(0x1800)
#define PCSSR __CCREG(0x1804)
#define PCSR __CCREG(0x1808)
#endif /* LANGUAGE == C */ /*
* These are offsets from the above base.
*/
#define SA1111_PCCR 0x0000
#define SA1111_PCSSR 0x0004
#define SA1111_PCSR 0x0008
#define PCSR_S0_READY (1<<0) #define PCSR_S0_READY (1<<0)
#define PCSR_S1_READY (1<<1) #define PCSR_S1_READY (1<<1)
...@@ -603,21 +545,61 @@ ...@@ -603,21 +545,61 @@
#define PCSSR_S0_SLEEP (1<<0) #define PCSSR_S0_SLEEP (1<<0)
#define PCSSR_S1_SLEEP (1<<1) #define PCSSR_S1_SLEEP (1<<1)
struct sa1111_device {
extern struct bus_type sa1111_bus_type;
#define SA1111_DEVID_SBI 0
#define SA1111_DEVID_SK 1
#define SA1111_DEVID_USB 2
#define SA1111_DEVID_SAC 3
#define SA1111_DEVID_SSP 4
#define SA1111_DEVID_PS2 5
#define SA1111_DEVID_GPIO 6
#define SA1111_DEVID_INT 7
#define SA1111_DEVID_PCMCIA 8
struct sa1111_dev {
struct device dev; struct device dev;
struct resource resource; unsigned int devid;
void *base; struct resource res;
void *mapbase;
unsigned int skpcr_mask;
unsigned int irq[6];
}; };
extern struct sa1111_device *sa1111; #define SA1111_DEV(_d) container_of((_d), struct sa1111_dev, dev)
int sa1111_check_dma_bug(dma_addr_t addr); struct sa1111_driver {
struct device_driver drv;
unsigned int devid;
};
#define SA1111_DRV(_d) container_of((_d), struct sa1111_driver, drv)
#define SA1111_DRIVER_NAME(_sadev) ((_sadev)->dev.driver->name)
/*
* Probe for a SA1111 chip.
*/
extern int sa1111_init(unsigned long phys, unsigned int irq);
/* /*
* These frob the SKPCR register. * These frob the SKPCR register.
*/ */
void sa1111_enable_device(unsigned int mask); void sa1111_enable_device(struct sa1111_dev *);
void sa1111_disable_device(unsigned int mask); void sa1111_disable_device(struct sa1111_dev *);
unsigned int sa1111_pll_clock(struct sa1111_dev *);
#define SA1111_AUDIO_ACLINK 0
#define SA1111_AUDIO_I2S 1
void sa1111_select_audio_mode(struct sa1111_dev *sadev, int mode);
int sa1111_set_audio_rate(struct sa1111_dev *sadev, int rate);
int sa1111_get_audio_rate(struct sa1111_dev *sadev);
int sa1111_check_dma_bug(dma_addr_t addr);
#endif /* _ASM_ARCH_SA1111 */ #endif /* _ASM_ARCH_SA1111 */
...@@ -27,15 +27,11 @@ void sa1111_dma_sync_sg(struct pci_dev *, struct scatterlist *, int, int); ...@@ -27,15 +27,11 @@ void sa1111_dma_sync_sg(struct pci_dev *, struct scatterlist *, int, int);
#ifdef CONFIG_SA1111 #ifdef CONFIG_SA1111
#define SA1111_FAKE_PCIDEV ((struct pci_dev *) 1111) #define SA1111_FAKE_PCIDEV ((struct pci_dev *) 1111)
#define dev_is_sa1111(dev) (dev == SA1111_FAKE_PCIDEV)
static inline int dev_is_sa1111(const struct pci_dev *dev)
{
return (dev == SA1111_FAKE_PCIDEV);
}
#else #else
static inline int dev_is_sa1111(const struct pci_dev *dev) { return 0; } #define dev_is_sa1111(dev) (0)
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment