Commit 3a630cb6 authored by Russell King's avatar Russell King

Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-rmk

into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-rmk-patchtest
parents d9b863a1 88ae31fc
...@@ -682,7 +682,6 @@ comment 'Kernel hacking' ...@@ -682,7 +682,6 @@ comment 'Kernel hacking'
bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER
bool 'Verbose user fault messages' CONFIG_DEBUG_USER bool 'Verbose user fault messages' CONFIG_DEBUG_USER
bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO
dep_bool 'Disable pgtable cache' CONFIG_NO_PGT_CACHE $CONFIG_CPU_26
bool 'Kernel debugging' CONFIG_DEBUG_KERNEL bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL
......
...@@ -167,10 +167,6 @@ EXPORT_SYMBOL(__virt_to_bus); ...@@ -167,10 +167,6 @@ EXPORT_SYMBOL(__virt_to_bus);
#endif #endif
#ifndef __bus_to_virt__is_a_macro #ifndef __bus_to_virt__is_a_macro
EXPORT_SYMBOL(__bus_to_virt); EXPORT_SYMBOL(__bus_to_virt);
#endif
#ifndef CONFIG_NO_PGT_CACHE
EXPORT_SYMBOL(quicklists);
#endif #endif
/* string / mem functions */ /* string / mem functions */
......
...@@ -95,9 +95,6 @@ void cpu_idle(void) ...@@ -95,9 +95,6 @@ void cpu_idle(void)
idle(); idle();
leds_event(led_idle_end); leds_event(led_idle_end);
schedule(); schedule();
#ifndef CONFIG_NO_PGT_CACHE
check_pgt_cache();
#endif
} }
} }
......
...@@ -78,15 +78,16 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) ...@@ -78,15 +78,16 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
if (!new_pmd) if (!new_pmd)
goto no_pmd; goto no_pmd;
new_pte = pte_alloc(mm, new_pmd, 0); new_pte = pte_alloc_map(mm, new_pmd, 0);
if (!new_pte) if (!new_pte)
goto no_pte; goto no_pte;
init_pgd = pgd_offset_k(0); init_pgd = pgd_offset_k(0);
init_pmd = pmd_offset(init_pgd, 0); init_pmd = pmd_offset(init_pgd, 0);
init_pte = pte_offset(init_pmd, 0); init_pte = pte_offset_map_nested(init_pmd, 0);
set_pte(new_pte, *init_pte); set_pte(new_pte, *init_pte);
pte_unmap_nested(init_pte);
pte_unmap(new_pte);
/* /*
* most of the page table entries are zeroed * most of the page table entries are zeroed
......
...@@ -151,7 +151,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address) ...@@ -151,7 +151,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
if (pmd_bad(*pmd)) if (pmd_bad(*pmd))
goto bad_pmd; goto bad_pmd;
pte = pte_offset(pmd, address); pte = pte_offset_map(pmd, address);
entry = *pte; entry = *pte;
/* /*
...@@ -164,6 +164,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address) ...@@ -164,6 +164,7 @@ static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
set_pte(pte, entry); set_pte(pte, entry);
flush_tlb_page(vma, address); flush_tlb_page(vma, address);
} }
pte_unmap(pte);
return; return;
bad_pgd: bad_pgd:
......
...@@ -83,10 +83,14 @@ void show_pte(struct mm_struct *mm, unsigned long addr) ...@@ -83,10 +83,14 @@ void show_pte(struct mm_struct *mm, unsigned long addr)
break; break;
} }
pte = pte_offset(pmd, addr); #ifndef CONFIG_HIGHMEM
/* We must not map this if we have highmem enabled */
pte = pte_offset_map(pmd, addr);
printk(", *pte = %08lx", pte_val(*pte)); printk(", *pte = %08lx", pte_val(*pte));
#ifdef CONFIG_CPU_32 #ifdef CONFIG_CPU_32
printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE])); printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
#endif
pte_unmap(pte);
#endif #endif
} while(0); } while(0);
......
...@@ -64,38 +64,6 @@ static struct meminfo meminfo __initdata = { 0, }; ...@@ -64,38 +64,6 @@ static struct meminfo meminfo __initdata = { 0, };
*/ */
struct page *empty_zero_page; struct page *empty_zero_page;
#ifndef CONFIG_NO_PGT_CACHE
struct pgtable_cache_struct quicklists;
int do_check_pgt_cache(int low, int high)
{
int freed = 0;
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist) {
free_pgd_slow(get_pgd_fast());
freed++;
}
if(pmd_quicklist) {
pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
freed++;
}
if(pte_quicklist) {
pte_free_slow(pte_alloc_one_fast(NULL, 0));
freed++;
}
} while(pgtable_cache_size > low);
}
return freed;
}
#else
int do_check_pgt_cache(int low, int high)
{
return 0;
}
#endif
/* This is currently broken /* This is currently broken
* PG_skip is used on sparc/sparc64 architectures to "skip" certain * PG_skip is used on sparc/sparc64 architectures to "skip" certain
* parts of the address space. * parts of the address space.
...@@ -145,9 +113,6 @@ void show_mem(void) ...@@ -145,9 +113,6 @@ void show_mem(void)
printk("%d slab pages\n", slab); printk("%d slab pages\n", slab);
printk("%d pages shared\n", shared); printk("%d pages shared\n", shared);
printk("%d pages swap cached\n", cached); printk("%d pages swap cached\n", cached);
#ifndef CONFIG_NO_PGT_CACHE
printk("%ld page tables cached\n", pgtable_cache_size);
#endif
show_buffers(); show_buffers();
} }
......
...@@ -58,7 +58,7 @@ static int __init minicache_init(void) ...@@ -58,7 +58,7 @@ static int __init minicache_init(void)
pmd = pmd_alloc(&init_mm, pgd, minicache_address); pmd = pmd_alloc(&init_mm, pgd, minicache_address);
if (!pmd) if (!pmd)
BUG(); BUG();
minicache_pte = pte_alloc(&init_mm, pmd, minicache_address); minicache_pte = pte_alloc_kernel(&init_mm, pmd, minicache_address);
if (!minicache_pte) if (!minicache_pte)
BUG(); BUG();
......
...@@ -98,11 +98,15 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) ...@@ -98,11 +98,15 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
if (!new_pmd) if (!new_pmd)
goto no_pmd; goto no_pmd;
new_pte = pte_alloc(mm, new_pmd, 0); new_pte = pte_alloc_map(mm, new_pmd, 0);
if (!new_pte) if (!new_pte)
goto no_pte; goto no_pte;
init_pmd = pmd_offset(init_pgd, 0);
init_pte = pte_offset_map_nested(init_pmd, 0);
set_pte(new_pte, *init_pte); set_pte(new_pte, *init_pte);
pte_unmap_nested(init_pte);
pte_unmap(new_pte);
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
} }
...@@ -138,7 +142,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm) ...@@ -138,7 +142,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
void free_pgd_slow(pgd_t *pgd) void free_pgd_slow(pgd_t *pgd)
{ {
pmd_t *pmd; pmd_t *pmd;
pte_t *pte; struct page *pte;
if (!pgd) if (!pgd)
return; return;
...@@ -153,7 +157,7 @@ void free_pgd_slow(pgd_t *pgd) ...@@ -153,7 +157,7 @@ void free_pgd_slow(pgd_t *pgd)
goto free; goto free;
} }
pte = pte_offset(pmd, 0); pte = pmd_page(*pmd);
pmd_clear(pmd); pmd_clear(pmd);
pte_free(pte); pte_free(pte);
pmd_free(pmd); pmd_free(pmd);
...@@ -198,7 +202,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot) ...@@ -198,7 +202,7 @@ alloc_init_page(unsigned long virt, unsigned long phys, int domain, int prot)
set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain))); set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
} }
ptep = pte_offset(pmdp, virt); ptep = pte_offset_kernel(pmdp, virt);
set_pte(ptep, mk_pte_phys(phys, __pgprot(prot))); set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
} }
...@@ -225,6 +229,20 @@ static void __init create_mapping(struct map_desc *md) ...@@ -225,6 +229,20 @@ static void __init create_mapping(struct map_desc *md)
int prot_sect, prot_pte; int prot_sect, prot_pte;
long off; long off;
if (md->prot_read && md->prot_write &&
!md->cacheable && !md->bufferable) {
printk(KERN_WARNING "Security risk: creating user "
"accessible mapping for 0x%08lx at 0x%08lx\n",
md->physical, md->virtual);
}
if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) {
printk(KERN_WARNING "MM: not creating mapping for "
"0x%08lx at 0x%08lx in user region\n",
md->physical, md->virtual);
return;
}
prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
(md->prot_read ? L_PTE_USER : 0) | (md->prot_read ? L_PTE_USER : 0) |
(md->prot_write ? L_PTE_WRITE : 0) | (md->prot_write ? L_PTE_WRITE : 0) |
......
...@@ -24,5 +24,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then ...@@ -24,5 +24,6 @@ if [ "$CONFIG_PCMCIA" != "n" ]; then
dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA dep_tristate ' HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
fi fi
fi fi
dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
endmenu endmenu
...@@ -62,22 +62,24 @@ endif ...@@ -62,22 +62,24 @@ endif
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
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 sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.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_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_XP860) += sa1100_xp860.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_YOPY) += sa1100_yopy.o sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o
sa1100_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o
sa1100_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o
sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o
sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o
sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o
sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o
sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o
sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o
sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -85,7 +87,7 @@ pcmcia_core.o: $(pcmcia_core-objs) ...@@ -85,7 +87,7 @@ pcmcia_core.o: $(pcmcia_core-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs) $(LD) $(LD_RFLAG) -r -o $@ $(pcmcia_core-objs)
sa1100_cs.o: $(sa1100_cs-objs-y) sa1100_cs.o: $(sa1100_cs-objs-y)
$(LD) -r -o $@ $(sa1100_cs-objs-y) $(LD) -r -o $@ $(sort $(sa1100_cs-objs-y))
yenta_socket.o: $(yenta_socket-objs) yenta_socket.o: $(yenta_socket-objs)
$(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs) $(LD) $(LD_RFLAG) -r -o $@ $(yenta_socket-objs)
...@@ -38,9 +38,7 @@ ...@@ -38,9 +38,7 @@
#include <pcmcia/bulkmem.h> #include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h> #include <pcmcia/cistpl.h>
#include "cs_internal.h" #include "cs_internal.h"
#include "sa1100_generic.h"
#include <asm/arch/pcmcia.h>
/* MECR: Expansion Memory Configuration Register /* MECR: Expansion Memory Configuration Register
* (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24) * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
...@@ -157,15 +155,24 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz, ...@@ -157,15 +155,24 @@ static inline unsigned int sa1100_pcmcia_cmd_time(unsigned int cpu_clock_khz,
* use when responding to a Card Services query of some kind. * use when responding to a Card Services query of some kind.
*/ */
struct sa1100_pcmcia_socket { struct sa1100_pcmcia_socket {
/*
* Core PCMCIA state
*/
socket_state_t cs_state; socket_state_t cs_state;
struct pcmcia_state k_state;
unsigned int irq;
void (*handler)(void *, unsigned int);
void *handler_info;
pccard_io_map io_map[MAX_IO_WIN]; pccard_io_map io_map[MAX_IO_WIN];
pccard_mem_map mem_map[MAX_WIN]; pccard_mem_map mem_map[MAX_WIN];
ioaddr_t virt_io, phys_attr, phys_mem; void (*handler)(void *, unsigned int);
void *handler_info;
struct pcmcia_state k_state;
ioaddr_t phys_attr, phys_mem;
void *virt_io;
unsigned short speed_io, speed_attr, speed_mem; unsigned short speed_io, speed_attr, speed_mem;
/*
* Info from low level handler
*/
unsigned int irq;
}; };
...@@ -180,23 +187,57 @@ struct sa1100_pcmcia_socket { ...@@ -180,23 +187,57 @@ struct sa1100_pcmcia_socket {
/* /*
* Declaration for all implementation specific low_level operations. * Declaration for all machine specific init/exit functions.
*/ */
extern struct pcmcia_low_level assabet_pcmcia_ops; extern int pcmcia_adsbitsy_init(void);
extern struct pcmcia_low_level neponset_pcmcia_ops; extern void pcmcia_adsbitsy_exit(void);
extern struct pcmcia_low_level h3600_pcmcia_ops;
extern struct pcmcia_low_level cerf_pcmcia_ops; extern int pcmcia_assabet_init(void);
extern struct pcmcia_low_level gcplus_pcmcia_ops; extern void pcmcia_assabet_exit(void);
extern struct pcmcia_low_level xp860_pcmcia_ops;
extern struct pcmcia_low_level yopy_pcmcia_ops; extern int pcmcia_badge4_init(void);
extern struct pcmcia_low_level pangolin_pcmcia_ops; extern void pcmcia_badge4_exit(void);
extern struct pcmcia_low_level freebird_pcmcia_ops;
extern struct pcmcia_low_level pfs168_pcmcia_ops; extern int pcmcia_cerf_init(void);
extern struct pcmcia_low_level jornada720_pcmcia_ops; extern void pcmcia_cerf_exit(void);
extern struct pcmcia_low_level flexanet_pcmcia_ops;
extern struct pcmcia_low_level simpad_pcmcia_ops; extern int pcmcia_flexanet_init(void);
extern struct pcmcia_low_level graphicsmaster_pcmcia_ops; extern void pcmcia_flexanet_exit(void);
extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
extern struct pcmcia_low_level stork_pcmcia_ops; extern int pcmcia_freebird_init(void);
extern void pcmcia_freebird_exit(void);
extern int pcmcia_gcplus_init(void);
extern void pcmcia_gcplus_exit(void);
extern int pcmcia_graphicsmaster_init(void);
extern void pcmcia_graphicsmaster_exit(void);
extern int pcmcia_jornada720_init(void);
extern void pcmcia_jornada720_exit(void);
extern int pcmcia_neponset_init(void);
extern void pcmcia_neponset_exit(void);
extern int pcmcia_pangolin_init(void);
extern void pcmcia_pangolin_exit(void);
extern int pcmcia_pfs168_init(void);
extern void pcmcia_pfs168_exit(void);
extern int pcmcia_shannon_init(void);
extern void pcmcia_shannon_exit(void);
extern int pcmcia_simpad_init(void);
extern void pcmcia_simpad_exit(void);
extern int pcmcia_stork_init(void);
extern void pcmcia_stork_exit(void);
extern int pcmcia_xp860_init(void);
extern void pcmcia_xp860_exit(void);
extern int pcmcia_yopy_init(void);
extern void pcmcia_yopy_exit(void);
#endif /* !defined(_PCMCIA_SA1100_H) */ #endif /* !defined(_PCMCIA_SA1100_H) */
...@@ -11,206 +11,97 @@ ...@@ -11,206 +11,97 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
static int adsbitsy_pcmcia_init(struct pcmcia_init *init) static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
{ {
int return_val=0;
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* Disable Power 3.3V/5V for PCMCIA/CF */ /* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | /* Why? */
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master CF (1) BVD1", NULL);
MECR = 0x09430943; MECR = 0x09430943;
return (return_val<0) ? -1 : 2; return sa1111_pcmcia_init(init);
}
static int adsbitsy_pcmcia_shutdown(void)
{
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
} }
static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state_array) static int
adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long status; unsigned int pa_dwr_mask, pa_dwr_set;
int return_val=1; int ret;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; switch (conf->sock) {
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
}
static int adsbitsy_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
case 0: case 0:
info->irq=S0_READY_NINT; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
break;
case 1:
info->irq=S1_READY_NINT;
break;
switch (conf->vcc) {
default: default:
return -1; case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
return 0;
}
static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
unsigned long pccr=PCCR, gpio=PA_DWR;
switch(configure->sock){
case 0:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio |= GPIO_GPIO0 | GPIO_GPIO1;
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio &= ~GPIO_GPIO0;
break; break;
case 50: case 1:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio |= GPIO_GPIO0;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO2; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO3; break;
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break;
case 1:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO2;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO3;
break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1; return -1;
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){ if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
configure->vpp); __FUNCTION__, conf->vpp);
return -1; return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
break; unsigned long flags;
default: local_irq_save(flags);
return -1; PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
} }
PCCR = pccr; return ret;
PA_DWR = gpio;
return 0;
} }
struct pcmcia_low_level adsbitsy_pcmcia_ops = { static struct pcmcia_low_level adsbitsy_pcmcia_ops = {
adsbitsy_pcmcia_init, init: adsbitsy_pcmcia_init,
adsbitsy_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
adsbitsy_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
adsbitsy_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
adsbitsy_pcmcia_configure_socket configure_socket: adsbitsy_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_adsbitsy_init(void)
{
int ret = -ENODEV;
if (machine_is_adsbitsy())
ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops);
return ret;
}
void __exit pcmcia_adsbitsy_exit(void)
{
sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops);
}
...@@ -4,113 +4,114 @@ ...@@ -4,113 +4,114 @@
* PCMCIA implementation routines for Assabet * PCMCIA implementation routines for Assabet
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h> #include <asm/arch/assabet.h>
static int assabet_pcmcia_init(struct pcmcia_init *init){ #include "sa1100_generic.h"
int irq, res;
/* Enable CF bus: */ static struct irqs {
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); int irq;
const char *str;
} irqs[] = {
{ ASSABET_IRQ_GPIO_CF_CD, "CF_CD" },
{ ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" },
{ ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" },
};
/* All those are inputs */ static int assabet_pcmcia_init(struct pcmcia_init *init)
GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ); {
int i, res;
/* Set transition detect */ /* Set transition detect */
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_irq_type(ASSABET_IRQ_GPIO_CF_IRQ, IRQT_FALLING);
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
/* Register interrupts */ /* Register interrupts */
irq = ASSABET_IRQ_GPIO_CF_CD; for (i = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); set_irq_type(irqs[i].irq, IRQT_NOEDGE);
if( res < 0 ) goto irq_err; res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irq = ASSABET_IRQ_GPIO_CF_BVD2; irqs[i].str, NULL);
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); if (res)
if( res < 0 ) goto irq_err; goto irq_err;
irq = ASSABET_IRQ_GPIO_CF_BVD1; }
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
if( res < 0 ) goto irq_err;
/* There's only one slot, but it's "Slot 1": */ /* There's only one slot, but it's "Slot 1": */
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
} }
/*
* Release all resources.
*/
static int assabet_pcmcia_shutdown(void) static int assabet_pcmcia_shutdown(void)
{ {
/* disable IRQs */ int i;
free_irq( ASSABET_IRQ_GPIO_CF_CD, NULL );
free_irq( ASSABET_IRQ_GPIO_CF_BVD2, NULL );
free_irq( ASSABET_IRQ_GPIO_CF_BVD1, NULL );
/* Disable CF bus: */ for (i = 0; i < ARRAY_SIZE(irqs); i++)
ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF); free_irq(irqs[i].irq, NULL);
return 0; return 0;
} }
static int assabet_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ assabet_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long levels; unsigned long levels;
if(state_array->size<2) return -1; if (state_array->size < 2)
return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR;
state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0;
state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0;
state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0;
state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0;
state_array->state[1].wrprot=0; /* Not available on Assabet. */
state_array->state[1].vs_3v=1; /* Can only apply 3.3V on Assabet. */ levels = GPLR;
state_array->state[1].vs_Xv=0; state_array->state[1].detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1;
state_array->state[1].ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0;
state_array->state[1].bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0;
state_array->state[1].bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0;
state_array->state[1].wrprot = 0; /* Not available on Assabet. */
state_array->state[1].vs_3v = 1; /* Can only apply 3.3V on Assabet. */
state_array->state[1].vs_Xv = 0;
return 1; return 1;
} }
static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if(info->sock>1) return -1; if (info->sock > 1)
return -1;
if(info->sock==1) if (info->sock == 1)
info->irq=ASSABET_IRQ_GPIO_CF_IRQ; info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
return 0; return 0;
} }
static int assabet_pcmcia_configure_socket(const struct pcmcia_configure static int
*configure) assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{ {
unsigned long value, flags; unsigned int mask;
if(configure->sock>1) return -1;
if(configure->sock==0) return 0;
save_flags_cli(flags); if (configure->sock > 1)
return -1;
value = BCR_value; if (configure->sock == 0)
return 0;
switch(configure->vcc){ switch (configure->vcc) {
case 0: case 0:
value &= ~ASSABET_BCR_CF_PWR; mask = 0;
break; break;
case 50: case 50:
...@@ -118,32 +119,106 @@ static int assabet_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -118,32 +119,106 @@ static int assabet_pcmcia_configure_socket(const struct pcmcia_configure
__FUNCTION__); __FUNCTION__);
case 33: /* Can only apply 3.3V to the CF slot. */ case 33: /* Can only apply 3.3V to the CF slot. */
value |= ASSABET_BCR_CF_PWR; mask = ASSABET_BCR_CF_PWR;
break; break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags);
return -1; return -1;
} }
value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST);
/* Silently ignore Vpp, output enable, speaker enable. */ /* Silently ignore Vpp, output enable, speaker enable. */
ASSABET_BCR = BCR_value = value; if (configure->reset)
mask |= ASSABET_BCR_CF_RST;
restore_flags(flags); ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
/*
* Handle suspend mode properly. This prevents a
* flood of IRQs from the CF device.
*/
if (configure->irq)
enable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
else
disable_irq(ASSABET_IRQ_GPIO_CF_IRQ);
return 0; return 0;
} }
struct pcmcia_low_level assabet_pcmcia_ops = { /*
assabet_pcmcia_init, * Enable card status IRQs on (re-)initialisation. This can
assabet_pcmcia_shutdown, * be called at initialisation, power management event, or
assabet_pcmcia_socket_state, * pcmcia event.
assabet_pcmcia_get_irq_info, */
assabet_pcmcia_configure_socket static int assabet_pcmcia_socket_init(int sock)
{
int i;
if (sock == 1) {
/*
* Enable CF bus
*/
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
}
return 0;
}
/*
* Disable card status IRQs on suspend.
*/
static int assabet_pcmcia_socket_suspend(int sock)
{
int i;
if (sock == 1) {
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
/*
* Tristate the CF bus signals. Also assert CF
* reset as per user guide page 4-11.
*/
ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST);
}
return 0;
}
static struct pcmcia_low_level assabet_pcmcia_ops = {
init: assabet_pcmcia_init,
shutdown: assabet_pcmcia_shutdown,
socket_state: assabet_pcmcia_socket_state,
get_irq_info: assabet_pcmcia_get_irq_info,
configure_socket: assabet_pcmcia_configure_socket,
socket_init: assabet_pcmcia_socket_init,
socket_suspend: assabet_pcmcia_socket_suspend,
}; };
int __init pcmcia_assabet_init(void)
{
int ret = -ENODEV;
if (machine_is_assabet()) {
if (!machine_has_neponset())
ret = sa1100_register_pcmcia(&assabet_pcmcia_ops);
#ifndef CONFIG_ASSABET_NEPONSET
else
printk(KERN_ERR "Card Services disabled: missing "
"Neponset support\n");
#endif
}
return ret;
}
void __exit pcmcia_assabet_exit(void)
{
sa1100_unregister_pcmcia(&assabet_pcmcia_ops);
}
/*
* linux/drivers/pcmcia/sa1100_badge4.c
*
* BadgePAD 4 PCMCIA specific routines
*
* Christopher Hoover <ch@hpl.hp.com>
*
* Copyright (C) 2002 Hewlett-Packard Company
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/arch/badge4.h>
#include <asm/hardware/sa1111.h>
#include "sa1100_generic.h"
#include "sa1111_generic.h"
/*
* BadgePAD 4 Details
*
* PCM Vcc:
*
* PCM Vcc on BadgePAD 4 can be jumpered for 3.3V (short pins 1 and 3
* on JP6) or 5V (short pins 3 and 5 on JP6). N.B., 5V supply rail
* is enabled by the SA-1110's BADGE4_GPIO_PCMEN5V (GPIO 24).
*
* PCM Vpp:
*
* PCM Vpp on BadgePAD 4 can be jumpered for 12V (short pins 2 and 4
* on JP6) or tied to PCM Vcc (short pins 4 and 6 on JP6). N.B., 12V
* operation requires that the power supply actually supply 12V.
*
* CF Vcc:
*
* CF Vcc on BadgePAD 4 can be jumpered either for 3.3V (short pins 1
* and 2 on JP10) or 5V (short pins 2 and 3 on JP10). The note above
* about the 5V supply rail applies.
*
* There's no way programmatically to determine how a given board is
* jumpered. This code assumes a default jumpering: 5V PCM Vcc (pins
* 3 and 5 shorted) and PCM Vpp = PCM Vcc (pins 4 and 6 shorted) and
* no jumpering for CF Vcc. If this isn't correct, Override these
* defaults with a pcmv setup argument: pcmv=<pcm vcc>,<pcm vpp>,<cf
* vcc>. E.g. pcmv=33,120,50 indicates 3.3V PCM Vcc, 12.0V PCM Vpp,
* and 5.0V CF Vcc.
*
*/
static int badge4_pcmvcc = 50;
static int badge4_pcmvpp = 50;
static int badge4_cfvcc = 0;
static int badge4_pcmcia_init(struct pcmcia_init *init)
{
printk(KERN_INFO __FUNCTION__
": badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
return sa1111_pcmcia_init(init);
}
static int badge4_pcmcia_shutdown(void)
{
int rc = sa1111_pcmcia_shutdown();
/* be sure to disable 5V use */
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0);
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0);
return rc;
}
static void complain_about_jumpering(const char *whom,
const char *supply,
int given, int wanted)
{
printk(KERN_ERR
"%s: %s %d.%dV wanted but board is jumpered for %s %d.%dV operation"
"; re-jumper the board and/or use pcmv=xx,xx,xx\n",
whom, supply,
wanted / 10, wanted % 10,
supply,
given / 10, given % 10);
}
static unsigned badge4_need_5V_bitmap = 0;
static int
badge4_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{
int ret;
switch (conf->sock) {
case 0:
if ((conf->vcc != 0) &&
(conf->vcc != badge4_pcmvcc)) {
complain_about_jumpering(__FUNCTION__, "pcmvcc",
badge4_pcmvcc, conf->vcc);
return -1;
}
if ((conf->vpp != 0) &&
(conf->vpp != badge4_pcmvpp)) {
complain_about_jumpering(__FUNCTION__, "pcmvpp",
badge4_pcmvpp, conf->vpp);
return -1;
}
break;
case 1:
if ((conf->vcc != 0) &&
(conf->vcc != badge4_cfvcc)) {
complain_about_jumpering(__FUNCTION__, "cfvcc",
badge4_cfvcc, conf->vcc);
return -1;
}
break;
default:
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
int need5V;
local_irq_save(flags);
need5V = ((conf->vcc == 50) || (conf->vpp == 50));
badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V);
local_irq_restore(flags);
}
return 0;
}
static struct pcmcia_low_level badge4_pcmcia_ops = {
init: badge4_pcmcia_init,
shutdown: badge4_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
configure_socket: badge4_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
};
int __init pcmcia_badge4_init(void)
{
int ret = -ENODEV;
if (machine_is_badge4())
ret = sa1100_register_pcmcia(&badge4_pcmcia_ops);
return ret;
}
void __exit pcmcia_badge4_exit(void)
{
sa1100_unregister_pcmcia(&badge4_pcmcia_ops);
}
static int __init pcmv_setup(char *s)
{
int v[4];
s = get_options(s, ARRAY_SIZE(v), v);
if (v[0] >= 1) badge4_pcmvcc = v[1];
if (v[0] >= 2) badge4_pcmvpp = v[2];
if (v[0] >= 3) badge4_cfvcc = v[3];
return 1;
}
__setup("pcmv=", pcmv_setup);
...@@ -5,45 +5,62 @@ ...@@ -5,45 +5,62 @@
* Based off the Assabet. * Based off the Assabet.
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#ifdef CONFIG_SA1100_CERF_CPLD
#define CERF_SOCKET 0
#else
#define CERF_SOCKET 1
#endif
static int cerf_pcmcia_init(struct pcmcia_init *init){ static struct irqs {
int irq, res; int irq;
const char *str;
} irqs[] = {
{ IRQ_GPIO_CF_CD, "CF_CD" },
{ IRQ_GPIO_CF_BVD2, "CF_BVD2" },
{ IRQ_GPIO_CF_BVD1, "CF_BVD1" }
};
GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ); static int cerf_pcmcia_init(struct pcmcia_init *init)
GPDR |= (GPIO_CF_RESET); {
int i, res;
set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_irq_type(IRQ_GPIO_CF_IRQ, IRQT_FALLING);
set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
irq = IRQ_GPIO_CF_CD; for (i = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); set_irq_type(irqs[i].irq, IRQT_NOEDGE);
if( res < 0 ) goto irq_err; res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irq = IRQ_GPIO_CF_BVD2; irqs[i].str, NULL);
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL ); if (res)
if( res < 0 ) goto irq_err; goto irq_err;
irq = IRQ_GPIO_CF_BVD1; }
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL );
if( res < 0 ) goto irq_err;
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
} }
static int cerf_pcmcia_shutdown(void) static int cerf_pcmcia_shutdown(void)
{ {
free_irq( IRQ_GPIO_CF_CD, NULL ); int i;
free_irq( IRQ_GPIO_CF_BVD2, NULL );
free_irq( IRQ_GPIO_CF_BVD1, NULL ); for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0; return 0;
} }
...@@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void) ...@@ -51,31 +68,18 @@ static int cerf_pcmcia_shutdown(void)
static int cerf_pcmcia_socket_state(struct pcmcia_state_array static int cerf_pcmcia_socket_state(struct pcmcia_state_array
*state_array){ *state_array){
unsigned long levels; unsigned long levels;
#ifdef CONFIG_SA1100_CERF_CPLD int i = CERF_SOCKET;
int i = 0;
#else
int i = 1;
#endif
if(state_array->size<2) return -1; if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR; levels=GPLR;
state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0; state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0; state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0; state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0; state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
state_array->state[i].wrprot=0; state_array->state[i].wrprot=0;
state_array->state[i].vs_3v=1; state_array->state[i].vs_3v=1;
state_array->state[i].vs_Xv=0; state_array->state[i].vs_Xv=0;
return 1; return 1;
...@@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -85,11 +89,7 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
if(info->sock>1) return -1; if(info->sock>1) return -1;
#ifdef CONFIG_SA1100_CERF_CPLD if (info->sock == CERF_SOCKET)
if(info->sock==0)
#else
if(info->sock==1)
#endif
info->irq=IRQ_GPIO_CF_IRQ; info->irq=IRQ_GPIO_CF_IRQ;
return 0; return 0;
...@@ -98,20 +98,12 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -98,20 +98,12 @@ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
static int cerf_pcmcia_configure_socket(const struct pcmcia_configure static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
*configure) *configure)
{ {
unsigned long flags;
if(configure->sock>1) if(configure->sock>1)
return -1; return -1;
#ifdef CONFIG_SA1100_CERF_CPLD if (configure->sock != CERF_SOCKET)
if(configure->sock==1)
#else
if(configure->sock==0)
#endif
return 0; return 0;
save_flags_cli(flags);
switch(configure->vcc){ switch(configure->vcc){
case 0: case 0:
break; break;
...@@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -119,43 +111,76 @@ static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
case 50: case 50:
case 33: case 33:
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_PWR_SHUTDOWN; GPCR = GPIO_PWR_SHUTDOWN;
GPCR |= GPIO_PWR_SHUTDOWN;
#endif #endif
break; break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags);
return -1; return -1;
} }
if(configure->reset) if(configure->reset)
{ {
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET; GPSR = GPIO_CF_RESET;
GPSR |= GPIO_CF_RESET;
#endif #endif
} }
else else
{ {
#ifdef CONFIG_SA1100_CERF_CPLD #ifdef CONFIG_SA1100_CERF_CPLD
GPDR |= GPIO_CF_RESET; GPCR = GPIO_CF_RESET;
GPCR |= GPIO_CF_RESET;
#endif #endif
} }
restore_flags(flags); return 0;
}
static int cerf_pcmcia_socket_init(int sock)
{
int i;
if (sock == CERF_SOCKET)
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
return 0; return 0;
} }
struct pcmcia_low_level cerf_pcmcia_ops = { static int cerf_pcmcia_socket_suspend(int sock)
cerf_pcmcia_init, {
cerf_pcmcia_shutdown, int i;
cerf_pcmcia_socket_state,
cerf_pcmcia_get_irq_info, if (sock == CERF_SOCKET)
cerf_pcmcia_configure_socket for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
return 0;
}
static struct pcmcia_low_level cerf_pcmcia_ops = {
init: cerf_pcmcia_init,
shutdown: cerf_pcmcia_shutdown,
socket_state: cerf_pcmcia_socket_state,
get_irq_info: cerf_pcmcia_get_irq_info,
configure_socket: cerf_pcmcia_configure_socket,
socket_init: cerf_pcmcia_socket_init,
socket_suspend: cerf_pcmcia_socket_suspend,
}; };
int __init pcmcia_cerf_init(void)
{
int ret = -ENODEV;
if (machine_is_cerf())
ret = sa1100_register_pcmcia(&cerf_pcmcia_ops);
return ret;
}
void __exit pcmcia_cerf_exit(void)
{
sa1100_unregister_pcmcia(&cerf_pcmcia_ops);
}
...@@ -4,16 +4,25 @@ ...@@ -4,16 +4,25 @@
* PCMCIA implementation routines for Flexanet. * PCMCIA implementation routines for Flexanet.
* by Jordi Colomer, 09/05/2001 * by Jordi Colomer, 09/05/2001
* *
* Yet to be defined.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct {
int irq;
const char *name;
} irqs[] = {
{ IRQ_GPIO_CF1_CD, "CF1_CD" },
{ IRQ_GPIO_CF1_BVD1, "CF1_BVD1" },
{ IRQ_GPIO_CF2_CD, "CF2_CD" },
{ IRQ_GPIO_CF2_BVD1, "CF2_BVD1" }
};
/* /*
* Socket initialization. * Socket initialization.
...@@ -22,9 +31,37 @@ ...@@ -22,9 +31,37 @@
* Must return the number of slots. * Must return the number of slots.
* *
*/ */
static int flexanet_pcmcia_init(struct pcmcia_init *init){ static int flexanet_pcmcia_init(struct pcmcia_init *init)
{
return 0; int i, res;
/* Configure the GPIOs as inputs (BVD2 is not implemented) */
GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ |
GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ );
/* Set IRQ edge */
set_irq_type(IRQ_GPIO_CF1_IRQ, IRQT_FALLING);
set_irq_type(IRQ_GPIO_CF2_IRQ, IRQT_FALLING);
/* Register the socket interrupts (not the card interrupts) */
for (i = 0; i < ARRAY_SIZE(irqs); i++) {
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].name, NULL);
if (res < 0)
break;
}
/* If we failed, then free all interrupts requested thus far. */
if (res < 0) {
printk(KERN_ERR "%s: request for IRQ%d failed: %d\n",
__FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
}
return 2;
} }
...@@ -34,6 +71,12 @@ static int flexanet_pcmcia_init(struct pcmcia_init *init){ ...@@ -34,6 +71,12 @@ static int flexanet_pcmcia_init(struct pcmcia_init *init){
*/ */
static int flexanet_pcmcia_shutdown(void) static int flexanet_pcmcia_shutdown(void)
{ {
int i;
/* disable IRQs */
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
return 0; return 0;
} }
...@@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void) ...@@ -46,7 +89,33 @@ static int flexanet_pcmcia_shutdown(void)
*/ */
static int flexanet_pcmcia_socket_state(struct pcmcia_state_array static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
*state_array){ *state_array){
unsigned long levels;
if (state_array->size < 2)
return -1; return -1;
/* Sense the GPIOs, asynchronously */
levels = GPLR;
/* Socket 0 */
state_array->state[0].detect = ((levels & GPIO_CF1_NCD)==0)?1:0;
state_array->state[0].ready = (levels & GPIO_CF1_IRQ)?1:0;
state_array->state[0].bvd1 = (levels & GPIO_CF1_BVD1)?1:0;
state_array->state[0].bvd2 = 1;
state_array->state[0].wrprot = 0;
state_array->state[0].vs_3v = 1;
state_array->state[0].vs_Xv = 0;
/* Socket 1 */
state_array->state[1].detect = ((levels & GPIO_CF2_NCD)==0)?1:0;
state_array->state[1].ready = (levels & GPIO_CF2_IRQ)?1:0;
state_array->state[1].bvd1 = (levels & GPIO_CF2_BVD1)?1:0;
state_array->state[1].bvd2 = 1;
state_array->state[1].wrprot = 0;
state_array->state[1].vs_3v = 1;
state_array->state[1].vs_Xv = 0;
return 1;
} }
...@@ -56,7 +125,16 @@ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array ...@@ -56,7 +125,16 @@ static int flexanet_pcmcia_socket_state(struct pcmcia_state_array
*/ */
static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
/* check the socket index */
if (info->sock > 1)
return -1; return -1;
if (info->sock == 0)
info->irq = IRQ_GPIO_CF1_IRQ;
else if (info->sock == 1)
info->irq = IRQ_GPIO_CF2_IRQ;
return 0;
} }
...@@ -66,19 +144,105 @@ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -66,19 +144,105 @@ static int flexanet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure static int flexanet_pcmcia_configure_socket(const struct pcmcia_configure
*configure) *configure)
{ {
unsigned long value, flags, mask;
if (configure->sock > 1)
return -1; return -1;
/* Ignore the VCC level since it is 3.3V and always on */
switch (configure->vcc)
{
case 0:
printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__);
break;
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
__FUNCTION__);
case 33:
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
/* Reset the slot(s) using the controls in the BCR */
mask = 0;
switch (configure->sock)
{
case 0 : mask = FHH_BCR_CF1_RST; break;
case 1 : mask = FHH_BCR_CF2_RST; break;
}
local_irq_save(flags);
value = flexanet_BCR;
value = (configure->reset) ? (value | mask) : (value & ~mask);
FHH_BCR = flexanet_BCR = value;
local_irq_restore(flags);
return 0;
} }
static int flexanet_pcmcia_socket_init(int sock)
{
if (sock == 0) {
set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE);
} else if (sock == 1) {
set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE);
}
return 0;
}
static int flexanet_pcmcia_socket_suspend(int sock)
{
if (sock == 0) {
set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE);
} else if (sock == 1) {
set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE);
}
return 0;
}
/* /*
* The set of socket operations * The set of socket operations
* *
*/ */
struct pcmcia_low_level flexanet_pcmcia_ops = { static struct pcmcia_low_level flexanet_pcmcia_ops = {
flexanet_pcmcia_init, init: flexanet_pcmcia_init,
flexanet_pcmcia_shutdown, shutdown: flexanet_pcmcia_shutdown,
flexanet_pcmcia_socket_state, socket_state: flexanet_pcmcia_socket_state,
flexanet_pcmcia_get_irq_info, get_irq_info: flexanet_pcmcia_get_irq_info,
flexanet_pcmcia_configure_socket configure_socket: flexanet_pcmcia_configure_socket,
socket_init: flexanet_pcmcia_socket_init,
socket_suspend: flexanet_pcmcia_socket_suspend,
}; };
int __init pcmcia_flexanet_init(void)
{
int ret = -ENODEV;
if (machine_is_flexanet())
ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops);
return ret;
}
void __exit pcmcia_flexanet_exit(void)
{
sa1100_unregister_pcmcia(&flexanet_pcmcia_ops);
}
...@@ -6,14 +6,22 @@ ...@@ -6,14 +6,22 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct irqs {
int irq;
const char *str;
} irqs[] = {
{ IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" },
{ IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" },
};
static int freebird_pcmcia_init(struct pcmcia_init *init){ static int freebird_pcmcia_init(struct pcmcia_init *init){
int irq, res; int i, res;
/* Enable Linkup CF card */ /* Enable Linkup CF card */
LINKUP_PRC = 0xc0; LINKUP_PRC = 0xc0;
...@@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){ ...@@ -26,37 +34,38 @@ static int freebird_pcmcia_init(struct pcmcia_init *init){
mdelay(100); mdelay(100);
LINKUP_PRC = 0xc0; LINKUP_PRC = 0xc0;
/* All those are inputs */
////GPDR &= ~(GPIO_CF_CD | GPIO_CF_BVD2 | GPIO_CF_BVD1 | GPIO_CF_IRQ);
GPDR &= ~(GPIO_FREEBIRD_CF_CD | GPIO_FREEBIRD_CF_IRQ | GPIO_FREEBIRD_CF_BVD);
/* Set transition detect */ /* Set transition detect */
//set_GPIO_IRQ_edge( GPIO_CF_CD|GPIO_CF_BVD2|GPIO_CF_BVD1, GPIO_BOTH_EDGES ); set_irq_type(IRQ_GPIO_FREEBIRD_CF_IRQ, IRQT_FALLING);
//set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_CD|GPIO_FREEBIRD_CF_BVD,GPIO_BOTH_EDGES);
set_GPIO_IRQ_edge(GPIO_FREEBIRD_CF_IRQ, GPIO_FALLING_EDGE);
/* Register interrupts */ /* Register interrupts */
irq = IRQ_GPIO_FREEBIRD_CF_CD; for (i = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); set_irq_type(irqs[i].irq, IRQT_NOEDGE);
if( res < 0 ) goto irq_err; res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irq = IRQ_GPIO_FREEBIRD_CF_BVD; irqs[i].str, NULL);
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD1", NULL ); if (res)
if( res < 0 ) goto irq_err; goto irq_err;
}
/* There's only one slot, but it's "Slot 1": */ /* There's only one slot, but it's "Slot 1": */
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irqs[i].irq, res);
while (i--)
free_irq(irqs[i].irq, NULL);
return res;
} }
static int freebird_pcmcia_shutdown(void) static int freebird_pcmcia_shutdown(void)
{ {
int i;
/* disable IRQs */ /* disable IRQs */
free_irq( IRQ_GPIO_FREEBIRD_CF_CD, NULL ); for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq( IRQ_GPIO_FREEBIRD_CF_BVD, NULL ); free_irq(irqs[i].irq, NULL);
/* Disable CF card */ /* Disable CF card */
LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */
...@@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array ...@@ -75,7 +84,7 @@ static int freebird_pcmcia_socket_state(struct pcmcia_state_array
(state_array->size)*sizeof(struct pcmcia_state)); (state_array->size)*sizeof(struct pcmcia_state));
levels = LINKUP_PRS; levels = LINKUP_PRS;
//printk("LINKUP_PRS=%x \n",levels); //printk("LINKUP_PRS=%x\n",levels);
state_array->state[0].detect= state_array->state[0].detect=
((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0;
...@@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -114,7 +123,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock==1) return 0; if(configure->sock==1) return 0;
save_flags_cli(flags); local_irq_save(flags);
value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ value = 0xc0; /* SSP=1 SOE=1 CFE=1 */
...@@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -134,7 +143,7 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
...@@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -145,16 +154,51 @@ static int freebird_pcmcia_configure_socket(const struct pcmcia_configure
LINKUP_PRC = value; LINKUP_PRC = value;
//printk("LINKUP_PRC=%x\n",value); //printk("LINKUP_PRC=%x\n",value);
restore_flags(flags); local_irq_restore(flags);
return 0;
}
static int freebird_pcmcia_socket_init(int sock)
{
if (sock == 1) {
set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
}
return 0;
}
static int freebird_pcmcia_socket_suspend(int sock)
{
if (sock == 1) {
set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE);
set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE);
}
return 0; return 0;
} }
struct pcmcia_low_level freebird_pcmcia_ops = { static struct pcmcia_low_level freebird_pcmcia_ops = {
freebird_pcmcia_init, init: freebird_pcmcia_init,
freebird_pcmcia_shutdown, shutdown: freebird_pcmcia_shutdown,
freebird_pcmcia_socket_state, socket_state: freebird_pcmcia_socket_state,
freebird_pcmcia_get_irq_info, get_irq_info: freebird_pcmcia_get_irq_info,
freebird_pcmcia_configure_socket configure_socket: freebird_pcmcia_configure_socket,
socket_init: freebird_pcmcia_socket_init,
socket_suspend: freebird_pcmcia_socket_suspend,
}; };
int __init pcmcia_freebird_init(void)
{
int ret = -ENODEV;
if (machine_is_freebird())
ret = sa1100_register_pcmcia(&freebird_pcmcia_ops);
return ret;
}
void __exit pcmcia_freebird_exit(void)
{
sa1100_unregister_pcmcia(&freebird_pcmcia_ops);
}
This diff is collapsed.
/*
* linux/include/asm/arch/pcmcia.h
*
* Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
*
* This file contains definitions for the low-level SA-1100 kernel PCMCIA
* interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details.
*/
#ifndef _ASM_ARCH_PCMCIA
#define _ASM_ARCH_PCMCIA
/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only
* has support for two. This shows up in lots of hardwired ways, such
* as the fact that MECR only has enough bits to configure two sockets.
* Since it's so entrenched in the hardware, limiting the software
* in this way doesn't seem too terrible.
*/
#define SA1100_PCMCIA_MAX_SOCK (2)
struct pcmcia_init {
void (*handler)(int irq, void *dev, struct pt_regs *regs);
};
struct pcmcia_state {
unsigned detect: 1,
ready: 1,
bvd1: 1,
bvd2: 1,
wrprot: 1,
vs_3v: 1,
vs_Xv: 1;
};
struct pcmcia_state_array {
unsigned int size;
struct pcmcia_state *state;
};
struct pcmcia_configure {
unsigned sock: 8,
vcc: 8,
vpp: 8,
output: 1,
speaker: 1,
reset: 1,
irq: 1;
};
struct pcmcia_irq_info {
unsigned int sock;
unsigned int irq;
};
struct pcmcia_low_level {
int (*init)(struct pcmcia_init *);
int (*shutdown)(void);
int (*socket_state)(struct pcmcia_state_array *);
int (*get_irq_info)(struct pcmcia_irq_info *);
int (*configure_socket)(const struct pcmcia_configure *);
/*
* Enable card status IRQs on (re-)initialisation. This can
* be called at initialisation, power management event, or
* pcmcia event.
*/
int (*socket_init)(int sock);
/*
* Disable card status IRQs and PCMCIA bus on suspend.
*/
int (*socket_suspend)(int sock);
};
extern int sa1100_register_pcmcia(struct pcmcia_low_level *);
extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *);
#endif
...@@ -14,10 +14,13 @@ ...@@ -14,10 +14,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#error This is broken!
#define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ #define S0_CD_IRQ 60 // Socket 0 Card Detect IRQ
#define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ #define S0_STS_IRQ 55 // Socket 0 PCMCIA IRQ
...@@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init) ...@@ -47,8 +50,9 @@ static int gcplus_pcmcia_init(struct pcmcia_init *init)
irq = S0_CD_IRQ; irq = S0_CD_IRQ;
res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL); res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
if (res < 0) { if (res < 0) {
printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irq, res);
return res;
} }
return 1; // 1 PCMCIA Slot return 1; // 1 PCMCIA Slot
...@@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -106,7 +110,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock>1) return -1; if(configure->sock>1) return -1;
save_flags_cli(flags); local_irq_save(flags);
switch (configure->vcc) { switch (configure->vcc) {
case 0: case 0:
...@@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -126,7 +130,7 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
...@@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -139,16 +143,44 @@ static int gcplus_pcmcia_configure_socket(const struct pcmcia_configure
*PCMCIA_Power |= ADS_CS_PR_A_RESET; *PCMCIA_Power |= ADS_CS_PR_A_RESET;
mdelay(30); mdelay(30);
restore_flags(flags); local_irq_restore(flags);
return 0;
}
static int gcplus_pcmcia_socket_init(int sock)
{
return 0;
}
static int gcplus_pcmcia_socket_suspend(int sock)
{
return 0; return 0;
} }
struct pcmcia_low_level gcplus_pcmcia_ops = { static struct pcmcia_low_level gcplus_pcmcia_ops = {
gcplus_pcmcia_init, init: gcplus_pcmcia_init,
gcplus_pcmcia_shutdown, shutdown: gcplus_pcmcia_shutdown,
gcplus_pcmcia_socket_state, socket_state: gcplus_pcmcia_socket_state,
gcplus_pcmcia_get_irq_info, get_irq_info: gcplus_pcmcia_get_irq_info,
gcplus_pcmcia_configure_socket configure_socket: gcplus_pcmcia_configure_socket,
socket_init: gcplus_pcmcia_socket_init,
socket_suspend: gcplus_pcmcia_socket_suspend,
}; };
int __init pcmcia_gcplus_init(void)
{
int ret = -ENODEV;
if (machine_is_gcplus())
ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops);
return ret;
}
void __exit pcmcia_gcplus_exit(void)
{
sa1100_unregister_pcmcia(&gcplus_pcmcia_ops);
}
...@@ -10,11 +10,12 @@ ...@@ -10,11 +10,12 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
{ {
...@@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) ...@@ -26,190 +27,82 @@ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
/* Disable Power 3.3V/5V for PCMCIA/CF */ /* Disable Power 3.3V/5V for PCMCIA/CF */
PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
INTPOL1 |= (1 << (S0_READY_NINT - SA1111_IRQ(32))) | /* why? */
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"GC Master CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"GC Master CF (1) BVD1", NULL);
MECR = 0x09430943; MECR = 0x09430943;
return (return_val<0) ? -1 : 2; return sa1111_pcmcia_init(init);
}
static int graphicsmaster_pcmcia_shutdown(void)
{
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &= ~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
}
static int graphicsmaster_pcmcia_socket_state(struct pcmcia_state_array *state_array)
{
unsigned long status;
int return_val=1;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
} }
static int graphicsmaster_pcmcia_get_irq_info(struct pcmcia_irq_info *info) static int
graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
switch(info->sock){ switch (conf->sock) {
case 0: case 0:
info->irq=S0_READY_NINT; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
break;
case 1:
info->irq=S1_READY_NINT;
break;
switch (conf->vcc) {
default: default:
return -1; case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
return 0;
}
static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
unsigned long pccr=PCCR, gpio=PA_DWR;
switch(configure->sock){
case 0:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio |= GPIO_GPIO0 | GPIO_GPIO1;
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio &= ~GPIO_GPIO0;
break;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio &= ~(GPIO_GPIO0 | GPIO_GPIO1);
gpio |= GPIO_GPIO0;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio |= GPIO_GPIO2 | GPIO_GPIO3;
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio &= ~GPIO_GPIO2;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio &= ~(GPIO_GPIO2 | GPIO_GPIO3);
gpio |= GPIO_GPIO2;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO3; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO2; break;
}
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){ if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp); conf->vpp);
return -1; return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
break; local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
default: local_irq_restore(flags);
return -1;
} }
PCCR = pccr; return ret;
PA_DWR = gpio;
return 0;
} }
struct pcmcia_low_level graphicsmaster_pcmcia_ops = { static struct pcmcia_low_level graphicsmaster_pcmcia_ops = {
graphicsmaster_pcmcia_init, init: graphicsmaster_pcmcia_init,
graphicsmaster_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
graphicsmaster_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
graphicsmaster_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
graphicsmaster_pcmcia_configure_socket configure_socket: graphicsmaster_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_graphicsmaster_init(void)
{
int ret = -ENODEV;
if (machine_is_graphicsmaster())
ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops);
return ret;
}
void __exit pcmcia_graphicsmaster_exit(void)
{
sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops);
}
...@@ -6,92 +6,106 @@ ...@@ -6,92 +6,106 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static struct irqs {
static int h3600_pcmcia_init(struct pcmcia_init *init){ int irq;
int irq, res; const char *str;
} irqs[] = {
{ IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
{ IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
};
/* Enable CF bus: */ static int h3600_pcmcia_init(struct pcmcia_init *init)
set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON); {
clr_h3600_egpio(EGPIO_H3600_OPT_RESET); int i, res;
/* All those are inputs */ /*
GPDR &= ~(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1 | GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1); * Set transition detect
*/
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ0, IRQT_FALLING);
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ1, IRQT_FALLING);
/* Set transition detect */ /*
set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES ); * Register interrupts
set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE ); */
for (i = res = 0; i < ARRAY_SIZE(irqs); i++) {
res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
irqs[i].str, NULL);
if (res)
break;
}
/* Register interrupts */ if (res) {
irq = IRQ_GPIO_H3600_PCMCIA_CD0; printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL ); __FUNCTION__, irqs[i].irq, res);
if( res < 0 ) goto irq_err;
irq = IRQ_GPIO_H3600_PCMCIA_CD1;
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD1", NULL );
if( res < 0 ) goto irq_err;
return 2; while (i--)
free_irq(irqs[i].irq, NULL);
}
irq_err: return res ? res : 2;
printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq );
return -1;
} }
static int h3600_pcmcia_shutdown(void) static int h3600_pcmcia_shutdown(void)
{ {
/* disable IRQs */ int i;
free_irq( IRQ_GPIO_H3600_PCMCIA_CD0, NULL );
free_irq( IRQ_GPIO_H3600_PCMCIA_CD1, NULL ); /*
* disable IRQs
*/
for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
/* Disable CF bus: */ /* Disable CF bus: */
clr_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON|EGPIO_H3600_OPT_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
set_h3600_egpio(EGPIO_H3600_OPT_RESET); clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
return 0; return 0;
} }
static int h3600_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ h3600_pcmcia_socket_state(struct pcmcia_state_array *state)
{
unsigned long levels; unsigned long levels;
if(state_array->size<2) return -1; if (state->size < 2)
return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR; levels = GPLR;
state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0; state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0; state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
state_array->state[0].bvd1= 0; state->state[0].bvd1 = 0;
state_array->state[0].bvd2= 0; state->state[0].bvd2 = 0;
state_array->state[0].wrprot=0; /* Not available on H3600. */ state->state[0].wrprot = 0; /* Not available on H3600. */
state_array->state[0].vs_3v=0; state->state[0].vs_3v = 0;
state_array->state[0].vs_Xv=0; state->state[0].vs_Xv = 0;
state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
state_array->state[1].bvd1=0; state->state[1].bvd1 = 0;
state_array->state[1].bvd2=0; state->state[1].bvd2 = 0;
state_array->state[1].wrprot=0; /* Not available on H3600. */ state->state[1].wrprot = 0; /* Not available on H3600. */
state_array->state[1].vs_3v=0; state->state[1].vs_3v = 0;
state_array->state[1].vs_Xv=0; state->state[1].vs_Xv = 0;
return 1; return 1;
} }
static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch (info->sock) { switch (info->sock) {
case 0: case 0:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ0; info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ0;
break; break;
case 1: case 1:
info->irq=IRQ_GPIO_H3600_PCMCIA_IRQ1; info->irq = IRQ_GPIO_H3600_PCMCIA_IRQ1;
break; break;
default: default:
return -1; return -1;
...@@ -99,49 +113,85 @@ static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ ...@@ -99,49 +113,85 @@ static int h3600_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
return 0; return 0;
} }
static int h3600_pcmcia_configure_socket(const struct pcmcia_configure static int
*configure) h3600_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long flags; if (conf->sock > 1)
return -1;
if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) {
printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n",
conf->vcc / 10, conf->vcc % 10);
return -1;
}
if (conf->reset)
set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
else
clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
if(configure->sock>1) return -1; /* Silently ignore Vpp, output enable, speaker enable. */
return 0;
}
static int h3600_pcmcia_socket_init(int sock)
{
/* Enable CF bus: */
set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
set_h3600_egpio(IPAQ_EGPIO_OPT_ON);
clr_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
save_flags_cli(flags); set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(10*HZ / 1000);
switch (configure->vcc) { switch (sock) {
case 0: case 0:
clr_h3600_egpio(EGPIO_H3600_OPT_ON); set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE);
break; break;
case 1:
case 33: set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE);
case 50:
set_h3600_egpio(EGPIO_H3600_OPT_ON);
break; break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
restore_flags(flags);
return -1;
} }
if (configure->reset) return 0;
set_h3600_egpio(EGPIO_H3600_CARD_RESET); }
else
clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
/* Silently ignore Vpp, output enable, speaker enable. */ static int h3600_pcmcia_socket_suspend(int sock)
{
switch (sock) {
case 0:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE);
break;
case 1:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE);
break;
}
restore_flags(flags); /*
* FIXME: This doesn't fit well. We don't have the mechanism in
* the generic PCMCIA layer to deal with the idea of two sockets
* on one bus. We rely on the cs.c behaviour shutting down
* socket 0 then socket 1.
*/
if (sock == 1) {
clr_h3600_egpio(IPAQ_EGPIO_OPT_ON);
clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON);
/* hmm, does this suck power? */
set_h3600_egpio(IPAQ_EGPIO_OPT_RESET);
}
return 0; return 0;
} }
struct pcmcia_low_level h3600_pcmcia_ops = { struct pcmcia_low_level h3600_pcmcia_ops = {
h3600_pcmcia_init, init: h3600_pcmcia_init,
h3600_pcmcia_shutdown, shutdown: h3600_pcmcia_shutdown,
h3600_pcmcia_socket_state, socket_state: h3600_pcmcia_socket_state,
h3600_pcmcia_get_irq_info, get_irq_info: h3600_pcmcia_get_irq_info,
h3600_pcmcia_configure_socket configure_socket: h3600_pcmcia_configure_socket,
socket_init: h3600_pcmcia_socket_init,
socket_suspend: h3600_pcmcia_socket_suspend,
}; };
...@@ -6,21 +6,24 @@ ...@@ -6,21 +6,24 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
#include "sa1111_generic.h"
#define SOCKET0_POWER GPIO_GPIO0 #define SOCKET0_POWER GPIO_GPIO0
#define SOCKET0_3V GPIO_GPIO2 #define SOCKET0_3V GPIO_GPIO2
#define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3) #define SOCKET1_POWER (GPIO_GPIO1 | GPIO_GPIO3)
#warning *** Does SOCKET1_3V actually do anything?
#define SOCKET1_3V GPIO_GPIO3 #define SOCKET1_3V GPIO_GPIO3
static int jornada720_pcmcia_init(struct pcmcia_init *init) static int jornada720_pcmcia_init(struct pcmcia_init *init)
{ {
int return_val=0; /*
* What is all this crap for?
*/
GRER |= 0x00000002; GRER |= 0x00000002;
/* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */ /* Set GPIO_A<3:1> to be outputs for PCMCIA/CF power controller: */
PA_DDR = 0; PA_DDR = 0;
...@@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init) ...@@ -38,178 +41,82 @@ static int jornada720_pcmcia_init(struct pcmcia_init *init)
PC_SDR = 0; PC_SDR = 0;
PC_SSR = 0; PC_SSR = 0;
INTPOL1 |= return sa1111_pcmcia_init(init);
(1 << (S0_READY_NINT - SA1111_IRQ(32))) |
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"Jornada720 PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"Jornada720 CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Jornada720 PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Jornada720 CF (1) BVD1", NULL);
return (return_val<0) ? -1 : 2;
} }
static int jornada720_pcmcia_shutdown(void) static int
jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
free_irq(S0_CD_VALID, NULL); unsigned int pa_dwr_mask, pa_dwr_set;
free_irq(S1_CD_VALID, NULL); int ret;
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &=
~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
}
static int jornada720_pcmcia_socket_state(struct pcmcia_state_array printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
*state_array) conf->sock, conf->vcc, conf->vpp);
{
unsigned long status;
int return_val=1;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
}
static int jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info) switch (conf->sock) {
{
switch(info->sock){
case 0: case 0:
info->irq=S0_READY_NINT; pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
break;
case 1:
info->irq=S1_READY_NINT;
break;
switch (conf->vcc) {
default: default:
return -1; case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break;
case 50: pa_dwr_set = SOCKET0_POWER; break;
} }
return 0;
}
static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure
*configure)
{
unsigned long pccr=PCCR, gpio=PA_DWR;
printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
configure->sock, configure->vcc, configure->vpp);
switch(configure->sock){
case 0:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S0_FLT);
gpio&=~(SOCKET0_POWER | SOCKET0_3V);
break;
case 33:
pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio |= SOCKET0_POWER | SOCKET0_3V;
break; break;
case 50: case 1:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN); pa_dwr_mask = SOCKET1_POWER;
gpio = (gpio & ~SOCKET0_3V) | SOCKET0_POWER;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = SOCKET1_POWER; break;
return -1; case 50: pa_dwr_set = SOCKET1_POWER; break;
} }
switch(configure->vpp){
case 0:
break;
case 50:
printk(KERN_ERR "%s(): 5.0 Vpp %u\n", __FUNCTION__,
configure->vpp);
break;
case 120:
printk(KERN_ERR "%s(): 12 Vpp %u\n", __FUNCTION__,
configure->vpp);
break; break;
default:
printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break;
case 1:
switch(configure->vcc){
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio &= ~(SOCKET1_POWER);
break;
case 33: if (conf->vpp != conf->vcc && conf->vpp != 0) {
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN; printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
gpio |= SOCKET1_POWER; __FUNCTION__, conf->vpp);
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_POWER;
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1; return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break; ret = sa1111_pcmcia_configure_socket(conf);
default: if (ret == 0) {
return -1; unsigned long flags;
local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
locla_irq_restore(flags);
} }
PCCR = pccr;
PA_DWR = gpio; return ret;
return 0;
} }
struct pcmcia_low_level jornada720_pcmcia_ops = { static struct pcmcia_low_level jornada720_pcmcia_ops = {
jornada720_pcmcia_init, init: jornada720_pcmcia_init,
jornada720_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
jornada720_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
jornada720_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
jornada720_pcmcia_configure_socket configure_socket: jornada720_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_jornada720_init(void)
{
int ret = -ENODEV;
if (machine_is_jornada720())
ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops);
return ret;
}
void __exit pcmcia_jornada720_exit(void)
{
sa1100_unregister_pcmcia(&jornada720_pcmcia_ops);
}
/* /*
* drivers/pcmcia/sa1100_neponset.c * linux/drivers/pcmcia/sa1100_neponset.c
* *
* Neponset PCMCIA specific routines * Neponset PCMCIA specific routines
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/delay.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/arch/pcmcia.h>
#include <asm/arch/assabet.h> #include <asm/arch/assabet.h>
#include <asm/hardware/sa1111.h>
static int neponset_pcmcia_init(struct pcmcia_init *init){ #include "sa1100_generic.h"
int return_val=0; #include "sa1111_generic.h"
static int neponset_pcmcia_init(struct pcmcia_init *init)
{
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
...@@ -23,109 +23,18 @@ static int neponset_pcmcia_init(struct pcmcia_init *init){ ...@@ -23,109 +23,18 @@ static int neponset_pcmcia_init(struct pcmcia_init *init){
PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
INTPOL1 |= return sa1111_pcmcia_init(init);
(1 << (S0_READY_NINT - SA1111_IRQ(32))) |
(1 << (S1_READY_NINT - SA1111_IRQ(32))) |
(1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32)));
return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
"Neponset PCMCIA (0) CD", NULL);
return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
"Neponset CF (1) CD", NULL);
return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Neponset PCMCIA (0) BVD1", NULL);
return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
"Neponset CF (1) BVD1", NULL);
return (return_val<0) ? -1 : 2;
}
static int neponset_pcmcia_shutdown(void){
free_irq(S0_CD_VALID, NULL);
free_irq(S1_CD_VALID, NULL);
free_irq(S0_BVD1_STSCHG, NULL);
free_irq(S1_BVD1_STSCHG, NULL);
INTPOL1 &=
~((1 << (S0_CD_VALID - SA1111_IRQ(32))) |
(1 << (S1_CD_VALID - SA1111_IRQ(32))) |
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0;
}
static int neponset_pcmcia_socket_state(struct pcmcia_state_array
*state_array){
unsigned long status;
int return_val=1;
if(state_array->size<2) return -1;
memset(state_array->state, 0,
(state_array->size)*sizeof(struct pcmcia_state));
status=PCSR;
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
return return_val;
} }
static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static int
neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
switch(info->sock){ {
case 0: unsigned int ncr_mask, pa_dwr_mask;
info->irq=S0_READY_NINT; unsigned int ncr_set, pa_dwr_set;
break; int ret;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
}
static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
*configure){
unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR;
/* Neponset uses the Maxim MAX1600, with the following connections: /* Neponset uses the Maxim MAX1600, with the following connections:
*
* MAX1600 Neponset * MAX1600 Neponset
* *
* A0VCC SA-1111 GPIO A<1> * A0VCC SA-1111 GPIO A<1>
...@@ -147,103 +56,90 @@ static int neponset_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -147,103 +56,90 @@ static int neponset_pcmcia_configure_socket(const struct pcmcia_configure
* the corresponding truth table. * the corresponding truth table.
*/ */
switch(configure->sock){ switch (conf->sock) {
case 0: case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
ncr_mask = NCR_A0VPP | NCR_A1VPP;
switch(configure->vcc){ switch (conf->vcc) {
case 0:
pccr=(pccr & ~PCCR_S0_FLT);
gpio&=~(GPIO_GPIO0 | GPIO_GPIO1);
break;
case 33:
pccr=(pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO1;
break;
case 50:
pccr=(pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
gpio=(gpio & ~(GPIO_GPIO0 | GPIO_GPIO1)) | GPIO_GPIO0;
break;
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO1; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
switch(configure->vpp){ switch (conf->vpp) {
case 0: case 0: ncr_set = 0; break;
ncr&=~(NCR_A0VPP | NCR_A1VPP); case 120: ncr_set = NCR_A1VPP; break;
break;
case 120:
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
break;
default: default:
if(configure->vpp == configure->vcc) if (conf->vpp == conf->vcc)
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP; ncr_set = NCR_A0VPP;
else { else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized VPP %u\n",
configure->vpp); __FUNCTION__, conf->vpp);
return -1; return -1;
} }
} }
pccr=(configure->reset)?(pccr | PCCR_S0_RST):(pccr & ~PCCR_S0_RST);
break; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
case 0: ncr_mask = 0;
pccr=(pccr & ~PCCR_S1_FLT); ncr_set = 0;
gpio&=~(GPIO_GPIO2 | GPIO_GPIO3);
break;
case 33:
pccr=(pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO2;
break;
case 50:
pccr=(pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio=(gpio & ~(GPIO_GPIO2 | GPIO_GPIO3)) | GPIO_GPIO3;
break;
switch (conf->vcc) {
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = 0; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO2; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO3; break;
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){ if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
configure->vpp); __FUNCTION__, conf->vpp);
return -1; return -1;
} }
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break; break;
default: default:
return -1; return -1;
} }
PCCR = pccr; ret = sa1111_pcmcia_configure_socket(conf);
NCR_0 = ncr; if (ret == 0) {
PA_DWR = gpio; unsigned long flags;
local_irq_save(flags);
NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set;
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return 0; return 0;
} }
struct pcmcia_low_level neponset_pcmcia_ops = { static struct pcmcia_low_level neponset_pcmcia_ops = {
neponset_pcmcia_init, init: neponset_pcmcia_init,
neponset_pcmcia_shutdown, shutdown: sa1111_pcmcia_shutdown,
neponset_pcmcia_socket_state, socket_state: sa1111_pcmcia_socket_state,
neponset_pcmcia_get_irq_info, get_irq_info: sa1111_pcmcia_get_irq_info,
neponset_pcmcia_configure_socket configure_socket: neponset_pcmcia_configure_socket,
socket_init: sa1111_pcmcia_socket_init,
socket_suspend: sa1111_pcmcia_socket_suspend,
}; };
int __init pcmcia_neponset_init(void)
{
int ret = -ENODEV;
if (machine_is_assabet() && machine_has_neponset())
ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
return ret;
}
void __exit pcmcia_neponset_exit(void)
{
sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
}
...@@ -4,48 +4,45 @@ ...@@ -4,48 +4,45 @@
* PCMCIA implementation routines for Pangolin * PCMCIA implementation routines for Pangolin
* *
*/ */
#include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
static int pangolin_pcmcia_init(struct pcmcia_init *init){ static int pangolin_pcmcia_init(struct pcmcia_init *init){
int irq, res; int res;
/* set GPIO_PCMCIA_CD & GPIO_PCMCIA_IRQ as inputs */
GPDR &= ~(GPIO_PCMCIA_CD|GPIO_PCMCIA_IRQ);
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
/* set GPIO pins GPIO_PCMCIA_BUS_ON & GPIO_PCMCIA_RESET as output */
GPDR |= (GPIO_PCMCIA_BUS_ON|GPIO_PCMCIA_RESET);
/* Enable PCMCIA bus: */ /* Enable PCMCIA bus: */
GPCR = GPIO_PCMCIA_BUS_ON; GPCR = GPIO_PCMCIA_BUS_ON;
#else
/* set GPIO pin GPIO_PCMCIA_RESET as output */
GPDR |= GPIO_PCMCIA_RESET;
#endif #endif
/* Set transition detect */ /* Set transition detect */
set_GPIO_IRQ_edge( GPIO_PCMCIA_CD, GPIO_BOTH_EDGES ); set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE);
set_GPIO_IRQ_edge( GPIO_PCMCIA_IRQ, GPIO_FALLING_EDGE ); set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING);
/* Register interrupts */ /* Register interrupts */
irq = IRQ_PCMCIA_CD; res = request_irq(IRQ_PCMCIA_CD, init->handler, SA_INTERRUPT,
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD", NULL ); "PCMCIA_CD", NULL);
if( res < 0 ) goto irq_err; if (res >= 0)
/* There's only one slot, but it's "Slot 1": */ /* There's only one slot, but it's "Slot 1": */
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, IRQ_PCMCIA_CD, res);
return res;
} }
static int pangolin_pcmcia_shutdown(void) static int pangolin_pcmcia_shutdown(void)
{ {
/* disable IRQs */ /* disable IRQs */
free_irq( IRQ_PCMCIA_CD, NULL ); free_irq(IRQ_PCMCIA_CD, NULL);
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
/* Disable PCMCIA bus: */ /* Disable PCMCIA bus: */
GPSR = GPIO_PCMCIA_BUS_ON; GPSR = GPIO_PCMCIA_BUS_ON;
...@@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -105,7 +102,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
if(configure->sock==0) return 0; if(configure->sock==0) return 0;
#endif #endif
save_flags_cli(flags); local_irq_save(flags);
/* Murphy: BUS_ON different from POWER ? */ /* Murphy: BUS_ON different from POWER ? */
...@@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -129,7 +126,7 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
default: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
#ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
...@@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -143,15 +140,47 @@ static int pangolin_pcmcia_configure_socket(const struct pcmcia_configure
} }
#endif #endif
/* Silently ignore Vpp, output enable, speaker enable. */ /* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags); local_irq_restore(flags);
return 0;
}
static int pangolin_pcmcia_socket_init(int sock)
{
if (sock == 1)
set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE);
return 0;
}
static int pangolin_pcmcia_socket_suspend(int sock)
{
if (sock == 1)
set_irq_type(IRQ_PCmCIA_CD, IRQT_NOEDGE);
return 0; return 0;
} }
struct pcmcia_low_level pangolin_pcmcia_ops = { static struct pcmcia_low_level pangolin_pcmcia_ops = {
pangolin_pcmcia_init, init: pangolin_pcmcia_init,
pangolin_pcmcia_shutdown, shutdown: pangolin_pcmcia_shutdown,
pangolin_pcmcia_socket_state, socket_state: pangolin_pcmcia_socket_state,
pangolin_pcmcia_get_irq_info, get_irq_info: pangolin_pcmcia_get_irq_info,
pangolin_pcmcia_configure_socket configure_socket: pangolin_pcmcia_configure_socket,
socket_init: pangolin_pcmcia_socket_init,
socket_suspend, pangolin_pcmcia_socket_suspend,
}; };
int __init pcmcia_pangolin_init(void)
{
int ret = -ENODEV;
if (machine_is_pangolin())
ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops);
return ret;
}
void __exit pcmcia_pangolin_exit(void)
{
sa1100_unregister_pcmcia(&pangolin_pcmcia_ops);
}
This diff is collapsed.
This diff is collapsed.
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/init.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/arch/pcmcia.h> #include "sa1100_generic.h"
extern long get_cs3_shadow(void); extern long get_cs3_shadow(void);
extern void set_cs3_bit(int value); extern void set_cs3_bit(int value);
...@@ -19,9 +20,6 @@ extern void clear_cs3_bit(int value); ...@@ -19,9 +20,6 @@ extern void clear_cs3_bit(int value);
static int simpad_pcmcia_init(struct pcmcia_init *init){ static int simpad_pcmcia_init(struct pcmcia_init *init){
int irq, res; int irq, res;
/* set GPIO_CF_CD & GPIO_CF_IRQ as inputs */
GPDR &= ~(GPIO_CF_CD|GPIO_CF_IRQ);
set_cs3_bit(PCMCIA_RESET); set_cs3_bit(PCMCIA_RESET);
clear_cs3_bit(PCMCIA_BUFF_DIS); clear_cs3_bit(PCMCIA_BUFF_DIS);
clear_cs3_bit(PCMCIA_RESET); clear_cs3_bit(PCMCIA_RESET);
...@@ -29,8 +27,8 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){ ...@@ -29,8 +27,8 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){
clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
/* Set transition detect */ /* Set transition detect */
set_GPIO_IRQ_edge( GPIO_CF_CD, GPIO_BOTH_EDGES ); set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE );
set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE ); set_irq_type( IRQ_GPIO_CF_IRQ, IRQT_FALLING );
/* Register interrupts */ /* Register interrupts */
irq = IRQ_GPIO_CF_CD; irq = IRQ_GPIO_CF_CD;
...@@ -41,8 +39,9 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){ ...@@ -41,8 +39,9 @@ static int simpad_pcmcia_init(struct pcmcia_init *init){
return 2; return 2;
irq_err: irq_err:
printk( KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq ); printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n",
return -1; __FUNCTION__, irq, res);
return res;
} }
static int simpad_pcmcia_shutdown(void) static int simpad_pcmcia_shutdown(void)
...@@ -112,7 +111,7 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -112,7 +111,7 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure
if(configure->sock==0) return 0; if(configure->sock==0) return 0;
save_flags_cli(flags); local_irq_save(flags);
/* Murphy: see table of MIC2562a-1 */ /* Murphy: see table of MIC2562a-1 */
...@@ -135,22 +134,51 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure ...@@ -135,22 +134,51 @@ static int simpad_pcmcia_configure_socket(const struct pcmcia_configure
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc); configure->vcc);
clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
restore_flags(flags); local_irq_restore(flags);
return -1; return -1;
} }
/* Silently ignore Vpp, output enable, speaker enable. */ /* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags); local_irq_restore(flags);
return 0;
}
static int simpad_pcmcia_socket_init(int sock)
{
set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE);
return 0;
}
static int simpad_pcmcia_socket_suspend(int sock)
{
set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE);
return 0; return 0;
} }
struct pcmcia_low_level simpad_pcmcia_ops = { static struct pcmcia_low_level simpad_pcmcia_ops = {
simpad_pcmcia_init, init: simpad_pcmcia_init,
simpad_pcmcia_shutdown, shutdown: simpad_pcmcia_shutdown,
simpad_pcmcia_socket_state, socket_state: simpad_pcmcia_socket_state,
simpad_pcmcia_get_irq_info, get_irq_info: simpad_pcmcia_get_irq_info,
simpad_pcmcia_configure_socket configure_socket: simpad_pcmcia_configure_socket,
socket_init: simpad_pcmcia_socket_init,
socket_suspend: simpad_pcmcia_socket_suspend,
}; };
int __init pcmcia_simpad_init(void)
{
int ret = -ENODEV;
if (machine_is_simpad())
ret = sa1100_register_pcmcia(&simpad_pcmcia_ops);
return ret;
}
void __exit pcmcia_simpad_exit(void)
{
sa1100_unregister_pcmcia(&simpad_pcmcia_ops);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
extern int sa1111_pcmcia_init(struct pcmcia_init *);
extern int sa1111_pcmcia_shutdown(void);
extern int sa1111_pcmcia_socket_state(struct pcmcia_state_array *);
extern int sa1111_pcmcia_get_irq_info(struct pcmcia_irq_info *);
extern int sa1111_pcmcia_configure_socket(const struct pcmcia_configure *);
extern int sa1111_pcmcia_socket_init(int);
extern int sa1111_pcmcia_socket_suspend(int);
This diff is collapsed.
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/arch/memory.h> #include <asm/arch/memory.h>
#include <asm/arch/vmalloc.h> #include <asm/arch/vmalloc.h>
#include <asm/proc-fns.h>
/* /*
* PMD_SHIFT determines the size of the area a second-level page table can map * PMD_SHIFT determines the size of the area a second-level page table can map
...@@ -146,8 +145,16 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) ...@@ -146,8 +145,16 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
#define pmd_offset(dir, addr) ((pmd_t *)(dir)) #define pmd_offset(dir, addr) ((pmd_t *)(dir))
/* Find an entry in the third-level page table.. */ /* Find an entry in the third-level page table.. */
#define __pte_offset(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) #define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset(dir, addr) ((pte_t *)pmd_page(*(dir)) + __pte_offset(addr))
#define pmd_page(dir) ((struct page *)__pmd_page(dir))
#define __pte_offset(dir, addr) ((pte_t *)__pmd_page(*(dir)) + __pte_index(addr))
#define pte_offset_kernel __pte_offset
#define pte_offset_map __pte_offset
#define pte_offset_map_nested __pte_offset
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
#include <asm/proc/pgtable.h> #include <asm/proc/pgtable.h>
......
This diff is collapsed.
...@@ -125,7 +125,7 @@ static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot) ...@@ -125,7 +125,7 @@ static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
return pmd; return pmd;
} }
static inline unsigned long pmd_page(pmd_t pmd) static inline unsigned long __pmd_page(pmd_t pmd)
{ {
unsigned long ptr; unsigned long ptr;
......
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