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; switch (conf->sock) {
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 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;
default:
return -1;
}
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;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
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 = GPIO_GPIO0 | GPIO_GPIO1; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO1; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
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_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){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break;
default: default:
return -1; return -1;
} }
PCCR = pccr; if (conf->vpp != conf->vcc && conf->vpp != 0) {
PA_DWR = gpio; printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
unsigned long flags;
return 0; local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return ret;
} }
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,146 +4,221 @@ ...@@ -4,146 +4,221 @@
* 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" },
};
static int assabet_pcmcia_init(struct pcmcia_init *init)
{
int i, res;
/* Set transition detect */
set_irq_type(ASSABET_IRQ_GPIO_CF_IRQ, IRQT_FALLING);
/* All those are inputs */ /* Register interrupts */
GPDR &= ~(ASSABET_GPIO_CF_CD | ASSABET_GPIO_CF_BVD2 | ASSABET_GPIO_CF_BVD1 | ASSABET_GPIO_CF_IRQ); 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].str, NULL);
if (res)
goto irq_err;
}
/* Set transition detect */ /* There's only one slot, but it's "Slot 1": */
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_CD|ASSABET_GPIO_CF_BVD2|ASSABET_GPIO_CF_BVD1, GPIO_BOTH_EDGES ); return 2;
set_GPIO_IRQ_edge( ASSABET_GPIO_CF_IRQ, GPIO_FALLING_EDGE );
/* Register interrupts */ irq_err:
irq = ASSABET_IRQ_GPIO_CF_CD; printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n",
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_CD", NULL ); __FUNCTION__, irqs[i].irq, res);
if( res < 0 ) goto irq_err;
irq = ASSABET_IRQ_GPIO_CF_BVD2;
res = request_irq( irq, init->handler, SA_INTERRUPT, "CF_BVD2", NULL );
if( res < 0 ) 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": */ while (i--)
return 2; free_irq(irqs[i].irq, NULL);
irq_err: return res;
printk( KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq );
return -1;
} }
/*
* 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: */
ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF);
return 0; for (i = 0; i < ARRAY_SIZE(irqs); i++)
free_irq(irqs[i].irq, NULL);
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, levels = GPLR;
(state_array->size)*sizeof(struct pcmcia_state));
levels=GPLR; 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;
state_array->state[1].detect=((levels & ASSABET_GPIO_CF_CD)==0)?1:0; return 1;
}
state_array->state[1].ready=(levels & ASSABET_GPIO_CF_IRQ)?1:0; static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
if (info->sock > 1)
return -1;
state_array->state[1].bvd1=(levels & ASSABET_GPIO_CF_BVD1)?1:0; if (info->sock == 1)
info->irq = ASSABET_IRQ_GPIO_CF_IRQ;
state_array->state[1].bvd2=(levels & ASSABET_GPIO_CF_BVD2)?1:0; return 0;
}
state_array->state[1].wrprot=0; /* Not available on Assabet. */ static int
assabet_pcmcia_configure_socket(const struct pcmcia_configure *configure)
{
unsigned int mask;
state_array->state[1].vs_3v=1; /* Can only apply 3.3V on Assabet. */ if (configure->sock > 1)
return -1;
state_array->state[1].vs_Xv=0; if (configure->sock == 0)
return 0;
return 1; switch (configure->vcc) {
} case 0:
mask = 0;
break;
static int assabet_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
__FUNCTION__);
if(info->sock>1) return -1; case 33: /* Can only apply 3.3V to the CF slot. */
mask = ASSABET_BCR_CF_PWR;
break;
if(info->sock==1) default:
info->irq=ASSABET_IRQ_GPIO_CF_IRQ; printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
return 0; /* Silently ignore Vpp, output enable, speaker enable. */
}
static int assabet_pcmcia_configure_socket(const struct pcmcia_configure if (configure->reset)
*configure) mask |= ASSABET_BCR_CF_RST;
{
unsigned long value, flags;
if(configure->sock>1) return -1; ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask);
if(configure->sock==0) return 0; /*
* 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);
save_flags_cli(flags); return 0;
}
value = BCR_value; /*
* Enable card status IRQs on (re-)initialisation. This can
* be called at initialisation, power management event, or
* pcmcia event.
*/
static int assabet_pcmcia_socket_init(int sock)
{
int i;
switch(configure->vcc){ if (sock == 1) {
case 0: /*
value &= ~ASSABET_BCR_CF_PWR; * Enable CF bus
break; */
ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF);
case 50: for (i = 0; i < ARRAY_SIZE(irqs); i++)
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", set_irq_type(irqs[i].irq, IRQT_BOTHEDGE);
__FUNCTION__); }
case 33: /* Can only apply 3.3V to the CF slot. */ return 0;
value |= ASSABET_BCR_CF_PWR; }
break;
default: /*
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, * Disable card status IRQs on suspend.
configure->vcc); */
restore_flags(flags); static int assabet_pcmcia_socket_suspend(int sock)
return -1; {
} int i;
value = (configure->reset) ? (value | ASSABET_BCR_CF_RST) : (value & ~ASSABET_BCR_CF_RST); if (sock == 1) {
for (i = 0; i < ARRAY_SIZE(irqs); i++)
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
/* Silently ignore Vpp, output enable, speaker enable. */ /*
* 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);
}
ASSABET_BCR = BCR_value = value; 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,
restore_flags(flags); socket_init: assabet_pcmcia_socket_init,
socket_suspend: assabet_pcmcia_socket_suspend,
};
return 0; 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;
} }
struct pcmcia_low_level assabet_pcmcia_ops = { void __exit pcmcia_assabet_exit(void)
assabet_pcmcia_init, {
assabet_pcmcia_shutdown, sa1100_unregister_pcmcia(&assabet_pcmcia_ops);
assabet_pcmcia_socket_state, }
assabet_pcmcia_get_irq_info,
assabet_pcmcia_configure_socket
};
/*
* 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){
return -1; unsigned long levels;
if (state_array->size < 2)
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){
return -1; /* check the socket index */
if (info->sock > 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)
{ {
return -1; unsigned long value, flags, mask;
if (configure->sock > 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; return 0;
} }
struct pcmcia_low_level freebird_pcmcia_ops = { static int freebird_pcmcia_socket_init(int sock)
freebird_pcmcia_init, {
freebird_pcmcia_shutdown, if (sock == 1) {
freebird_pcmcia_socket_state, set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE);
freebird_pcmcia_get_irq_info, set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE);
freebird_pcmcia_configure_socket }
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;
}
static struct pcmcia_low_level freebird_pcmcia_ops = {
init: freebird_pcmcia_init,
shutdown: freebird_pcmcia_shutdown,
socket_state: freebird_pcmcia_socket_state,
get_irq_info: freebird_pcmcia_get_irq_info,
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; return 0;
} }
struct pcmcia_low_level gcplus_pcmcia_ops = { static int gcplus_pcmcia_socket_init(int sock)
gcplus_pcmcia_init, {
gcplus_pcmcia_shutdown, return 0;
gcplus_pcmcia_socket_state, }
gcplus_pcmcia_get_irq_info,
gcplus_pcmcia_configure_socket static int gcplus_pcmcia_socket_suspend(int sock)
{
return 0;
}
static struct pcmcia_low_level gcplus_pcmcia_ops = {
init: gcplus_pcmcia_init,
shutdown: gcplus_pcmcia_shutdown,
socket_state: gcplus_pcmcia_socket_state,
get_irq_info: gcplus_pcmcia_get_irq_info,
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)
{
switch(info->sock){
case 0:
info->irq=S0_READY_NINT;
break;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
} }
static int graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *configure) static int
graphicsmaster_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long pccr=PCCR, gpio=PA_DWR; unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
switch(configure->sock){ switch (conf->sock) {
case 0: case 0:
pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
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_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: default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break;
configure->vcc); case 33: pa_dwr_set = GPIO_GPIO1; break;
return -1; case 50: pa_dwr_set = GPIO_GPIO0; break;
} }
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){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
} }
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST); if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
break; conf->vpp);
default:
return -1; return -1;
} }
PCCR = pccr; ret = sa1111_pcmcia_configure_socket(conf);
PA_DWR = gpio; if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
local_irq_restore(flags);
}
return 0; return ret;
} }
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,142 +6,192 @@ ...@@ -6,142 +6,192 @@
*/ */
#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[] = {
/* Enable CF bus: */ { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" },
set_h3600_egpio(EGPIO_H3600_OPT_NVRAM_ON); { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" }
clr_h3600_egpio(EGPIO_H3600_OPT_RESET); };
/* 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_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1, GPIO_BOTH_EDGES );
set_GPIO_IRQ_edge( GPIO_H3600_PCMCIA_IRQ0| GPIO_H3600_PCMCIA_IRQ1, GPIO_FALLING_EDGE );
/* Register interrupts */
irq = IRQ_GPIO_H3600_PCMCIA_CD0;
res = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA_CD0", NULL );
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;
irq_err: static int h3600_pcmcia_init(struct pcmcia_init *init)
printk( KERN_ERR __FUNCTION__ ": Request for IRQ %u failed\n", irq ); {
return -1; int i, res;
/*
* Set transition detect
*/
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ0, IRQT_FALLING);
set_irq_type(IRQ_GPIO_H3600_PCMCIA_IRQ1, IRQT_FALLING);
/*
* Register interrupts
*/
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;
}
if (res) {
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 ? res : 2;
} }
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)
memset(state_array->state, 0, return -1;
(state_array->size)*sizeof(struct pcmcia_state));
levels = GPLR;
levels=GPLR;
state->state[0].detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1;
state_array->state[0].detect=((levels & GPIO_H3600_PCMCIA_CD0)==0)?1:0; state->state[0].ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0;
state_array->state[0].ready=(levels & GPIO_H3600_PCMCIA_IRQ0)?1:0; state->state[0].bvd1 = 0;
state_array->state[0].bvd1= 0; state->state[0].bvd2 = 0;
state_array->state[0].bvd2= 0; state->state[0].wrprot = 0; /* Not available on H3600. */
state_array->state[0].wrprot=0; /* Not available on H3600. */ state->state[0].vs_3v = 0;
state_array->state[0].vs_3v=0; state->state[0].vs_Xv = 0;
state_array->state[0].vs_Xv=0;
state->state[1].detect = levels & GPIO_H3600_PCMCIA_CD1 ? 0 : 1;
state_array->state[1].detect=((levels & GPIO_H3600_PCMCIA_CD1)==0)?1:0; state->state[1].ready = levels & GPIO_H3600_PCMCIA_IRQ1 ? 1 : 0;
state_array->state[1].ready=(levels & GPIO_H3600_PCMCIA_IRQ1)?1:0; state->state[1].bvd1 = 0;
state_array->state[1].bvd1=0; state->state[1].bvd2 = 0;
state_array->state[1].bvd2=0; state->state[1].wrprot = 0; /* Not available on H3600. */
state_array->state[1].wrprot=0; /* Not available on H3600. */ state->state[1].vs_3v = 0;
state_array->state[1].vs_3v=0; state->state[1].vs_Xv = 0;
state_array->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;
} }
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(configure->sock>1) return -1;
save_flags_cli(flags); 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;
}
switch (configure->vcc) { if (conf->reset)
case 0: set_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
clr_h3600_egpio(EGPIO_H3600_OPT_ON); else
break; clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET);
case 33: /* Silently ignore Vpp, output enable, speaker enable. */
case 50:
set_h3600_egpio(EGPIO_H3600_OPT_ON);
break;
default: return 0;
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, }
configure->vcc);
restore_flags(flags);
return -1;
}
if (configure->reset)
set_h3600_egpio(EGPIO_H3600_CARD_RESET);
else
clr_h3600_egpio(EGPIO_H3600_CARD_RESET);
/* Silently ignore Vpp, output enable, speaker enable. */
restore_flags(flags); 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);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(10*HZ / 1000);
switch (sock) {
case 0:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE);
break;
case 1:
set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE);
break;
}
return 0;
}
return 0; 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;
}
/*
* 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;
} }
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)
#define SOCKET1_3V GPIO_GPIO3 #warning *** Does SOCKET1_3V actually do anything?
#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)
{
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 jornada720_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 jornada720_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
{
switch(info->sock){
case 0:
info->irq=S0_READY_NINT;
break;
case 1:
info->irq=S1_READY_NINT;
break;
default:
return -1;
}
return 0;
} }
static int jornada720_pcmcia_configure_socket(const struct pcmcia_configure static int
*configure) jornada720_pcmcia_configure_socket(const struct pcmcia_configure *conf)
{ {
unsigned long pccr=PCCR, gpio=PA_DWR; unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
configure->sock, configure->vcc, configure->vpp); conf->sock, conf->vcc, conf->vpp);
switch(configure->sock){
switch (conf->sock) {
case 0: case 0:
switch(configure->vcc){ pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V;
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;
case 50:
pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
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 = SOCKET0_POWER | SOCKET0_3V; break;
return -1; case 50: pa_dwr_set = SOCKET0_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;
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; break;
case 1: case 1:
switch(configure->vcc){ pa_dwr_mask = SOCKET1_POWER;
case 0:
pccr = (pccr & ~PCCR_S1_FLT);
gpio &= ~(SOCKET1_POWER);
break;
case 33:
pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
gpio |= SOCKET1_POWER;
break;
case 50:
pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
gpio = (gpio & ~(SOCKET1_POWER)) | SOCKET1_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;
} }
if(configure->vpp!=configure->vcc && configure->vpp!=0){
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__,
configure->vpp);
return -1;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break; break;
default: }
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1; return -1;
} }
PCCR = pccr;
PA_DWR = gpio; ret = sa1111_pcmcia_configure_socket(conf);
return 0; if (ret == 0) {
unsigned long flags;
local_irq_save(flags);
PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
locla_irq_restore(flags);
}
return ret;
} }
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"
/* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
/* MAX1600 to standby mode: */
PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
INTPOL1 |=
(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); static int neponset_pcmcia_init(struct pcmcia_init *init)
free_irq(S1_CD_VALID, NULL); {
free_irq(S0_BVD1_STSCHG, NULL); /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
free_irq(S1_BVD1_STSCHG, NULL); PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
INTPOL1 &= /* MAX1600 to standby mode: */
~((1 << (S0_CD_VALID - SA1111_IRQ(32))) | PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
(1 << (S1_CD_VALID - SA1111_IRQ(32))) | NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP);
(1 << (S0_BVD1_STSCHG - SA1111_IRQ(32))) |
(1 << (S1_BVD1_STSCHG - SA1111_IRQ(32))));
return 0; return sa1111_pcmcia_init(init);
} }
static int neponset_pcmcia_socket_state(struct pcmcia_state_array static int
*state_array){ neponset_pcmcia_configure_socket(const struct pcmcia_configure *conf)
unsigned long status; {
int return_val=1; unsigned int ncr_mask, pa_dwr_mask;
unsigned int ncr_set, pa_dwr_set;
if(state_array->size<2) return -1; int ret;
memset(state_array->state, 0, /* Neponset uses the Maxim MAX1600, with the following connections:
(state_array->size)*sizeof(struct pcmcia_state));
* MAX1600 Neponset
status=PCSR; *
* A0VCC SA-1111 GPIO A<1>
state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0; * A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1; * A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1; * B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1; * B1VPP ground (slot B is CF)
*
state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1; * VX VCC (5V)
* VY VCC3_3 (3.3V)
state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0; * 12INA 12V
* 12INB ground (slot B is CF)
state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0; *
* The MAX1600 CODE pin is tied to ground, placing the device in
state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0; * "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1; */
state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1; switch (conf->sock) {
case 0:
state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1; pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
ncr_mask = NCR_A0VPP | NCR_A1VPP;
state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
switch (conf->vcc) {
state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0; default:
case 0: pa_dwr_set = 0; break;
state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0; case 33: pa_dwr_set = GPIO_GPIO1; break;
case 50: pa_dwr_set = GPIO_GPIO0; break;
return return_val; }
switch (conf->vpp) {
case 0: ncr_set = 0; break;
case 120: ncr_set = NCR_A1VPP; break;
default:
if (conf->vpp == conf->vcc)
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
}
break;
case 1:
pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
ncr_mask = 0;
ncr_set = 0;
switch (conf->vcc) {
default:
case 0: pa_dwr_set = 0; break;
case 33: pa_dwr_set = GPIO_GPIO2; break;
case 50: pa_dwr_set = GPIO_GPIO3; break;
}
if (conf->vpp != conf->vcc && conf->vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
__FUNCTION__, conf->vpp);
return -1;
}
break;
default:
return -1;
}
ret = sa1111_pcmcia_configure_socket(conf);
if (ret == 0) {
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;
} }
static int neponset_pcmcia_get_irq_info(struct pcmcia_irq_info *info){ static struct pcmcia_low_level neponset_pcmcia_ops = {
init: neponset_pcmcia_init,
shutdown: sa1111_pcmcia_shutdown,
socket_state: sa1111_pcmcia_socket_state,
get_irq_info: sa1111_pcmcia_get_irq_info,
configure_socket: neponset_pcmcia_configure_socket,
switch(info->sock){ socket_init: sa1111_pcmcia_socket_init,
case 0: socket_suspend: sa1111_pcmcia_socket_suspend,
info->irq=S0_READY_NINT; };
break;
case 1: int __init pcmcia_neponset_init(void)
info->irq=S1_READY_NINT; {
break; int ret = -ENODEV;
default: if (machine_is_assabet() && machine_has_neponset())
return -1; ret = sa1100_register_pcmcia(&neponset_pcmcia_ops);
}
return 0; return ret;
} }
static int neponset_pcmcia_configure_socket(const struct pcmcia_configure void __exit pcmcia_neponset_exit(void)
*configure){ {
unsigned long pccr=PCCR, ncr=NCR_0, gpio=PA_DWR; sa1100_unregister_pcmcia(&neponset_pcmcia_ops);
/* Neponset uses the Maxim MAX1600, with the following connections:
*
* MAX1600 Neponset
*
* A0VCC SA-1111 GPIO A<1>
* A1VCC SA-1111 GPIO A<0>
* A0VPP CPLD NCR A0VPP
* A1VPP CPLD NCR A1VPP
* B0VCC SA-1111 GPIO A<2>
* B1VCC SA-1111 GPIO A<3>
* B0VPP ground (slot B is CF)
* B1VPP ground (slot B is CF)
*
* VX VCC (5V)
* VY VCC3_3 (3.3V)
* 12INA 12V
* 12INB ground (slot B is CF)
*
* The MAX1600 CODE pin is tied to ground, placing the device in
* "Standard Intel code" mode. Refer to the Maxim data sheet for
* the corresponding truth table.
*/
switch(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 & ~(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:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
configure->vcc);
return -1;
}
switch(configure->vpp){
case 0:
ncr&=~(NCR_A0VPP | NCR_A1VPP);
break;
case 120:
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A1VPP;
break;
default:
if(configure->vpp == configure->vcc)
ncr=(ncr & ~(NCR_A0VPP | NCR_A1VPP)) | NCR_A0VPP;
else {
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&=~(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;
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;
}
pccr=(configure->reset)?(pccr | PCCR_S1_RST):(pccr & ~PCCR_S1_RST);
break;
default:
return -1;
}
PCCR = pccr;
NCR_0 = ncr;
PA_DWR = gpio;
return 0;
} }
struct pcmcia_low_level neponset_pcmcia_ops = {
neponset_pcmcia_init,
neponset_pcmcia_shutdown,
neponset_pcmcia_socket_state,
neponset_pcmcia_get_irq_info,
neponset_pcmcia_configure_socket
};
...@@ -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; return 0;
} }
struct pcmcia_low_level pangolin_pcmcia_ops = { static int pangolin_pcmcia_socket_init(int sock)
pangolin_pcmcia_init, {
pangolin_pcmcia_shutdown, if (sock == 1)
pangolin_pcmcia_socket_state, set_irq_type(IRQ_PCmCIA_CD, IRQT_BOTHEDGE);
pangolin_pcmcia_get_irq_info, return 0;
pangolin_pcmcia_configure_socket }
static int pangolin_pcmcia_socket_suspend(int sock)
{
if (sock == 1)
set_irq_type(IRQ_PCmCIA_CD, IRQT_NOEDGE);
return 0;
}
static struct pcmcia_low_level pangolin_pcmcia_ops = {
init: pangolin_pcmcia_init,
shutdown: pangolin_pcmcia_shutdown,
socket_state: pangolin_pcmcia_socket_state,
get_irq_info: pangolin_pcmcia_get_irq_info,
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.
This diff is collapsed.
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.
This diff is collapsed.
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