1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 */ 8 9#include <linux/init.h> 10#include <linux/kernel.h> 11#include <asm/bootinfo.h> 12#include <linux/platform_device.h> 13#include <bcm63xx_cs.h> 14#include <bcm63xx_cpu.h> 15#include <bcm63xx_dev_pcmcia.h> 16#include <bcm63xx_io.h> 17#include <bcm63xx_regs.h> 18 19static struct resource pcmcia_resources[] = { 20 /* pcmcia registers */ 21 { 22 /* start & end filled at runtime */ 23 .flags = IORESOURCE_MEM, 24 }, 25 26 /* pcmcia memory zone resources */ 27 { 28 .start = BCM_PCMCIA_COMMON_BASE_PA, 29 .end = BCM_PCMCIA_COMMON_END_PA, 30 .flags = IORESOURCE_MEM, 31 }, 32 { 33 .start = BCM_PCMCIA_ATTR_BASE_PA, 34 .end = BCM_PCMCIA_ATTR_END_PA, 35 .flags = IORESOURCE_MEM, 36 }, 37 { 38 .start = BCM_PCMCIA_IO_BASE_PA, 39 .end = BCM_PCMCIA_IO_END_PA, 40 .flags = IORESOURCE_MEM, 41 }, 42 43 /* PCMCIA irq */ 44 { 45 /* start filled at runtime */ 46 .flags = IORESOURCE_IRQ, 47 }, 48 49 /* declare PCMCIA IO resource also */ 50 { 51 .start = BCM_PCMCIA_IO_BASE_PA, 52 .end = BCM_PCMCIA_IO_END_PA, 53 .flags = IORESOURCE_IO, 54 }, 55}; 56 57static struct bcm63xx_pcmcia_platform_data pd; 58 59static struct platform_device bcm63xx_pcmcia_device = { 60 .name = "bcm63xx_pcmcia", 61 .id = 0, 62 .num_resources = ARRAY_SIZE(pcmcia_resources), 63 .resource = pcmcia_resources, 64 .dev = { 65 .platform_data = &pd, 66 }, 67}; 68 69static int __init config_pcmcia_cs(unsigned int cs, 70 u32 base, unsigned int size) 71{ 72 int ret; 73 74 ret = bcm63xx_set_cs_status(cs, 0); 75 if (!ret) 76 ret = bcm63xx_set_cs_base(cs, base, size); 77 if (!ret) 78 ret = bcm63xx_set_cs_status(cs, 1); 79 return ret; 80} 81 82static const struct { 83 unsigned int cs; 84 unsigned int base; 85 unsigned int size; 86} pcmcia_cs[3] __initconst = { 87 { 88 .cs = MPI_CS_PCMCIA_COMMON, 89 .base = BCM_PCMCIA_COMMON_BASE_PA, 90 .size = BCM_PCMCIA_COMMON_SIZE 91 }, 92 { 93 .cs = MPI_CS_PCMCIA_ATTR, 94 .base = BCM_PCMCIA_ATTR_BASE_PA, 95 .size = BCM_PCMCIA_ATTR_SIZE 96 }, 97 { 98 .cs = MPI_CS_PCMCIA_IO, 99 .base = BCM_PCMCIA_IO_BASE_PA, 100 .size = BCM_PCMCIA_IO_SIZE 101 }, 102}; 103 104int __init bcm63xx_pcmcia_register(void) 105{ 106 int ret, i; 107 108 if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358()) 109 return 0; 110 111 /* use correct pcmcia ready gpio depending on processor */ 112 switch (bcm63xx_get_cpu_id()) { 113 case BCM6348_CPU_ID: 114 pd.ready_gpio = 22; 115 break; 116 117 case BCM6358_CPU_ID: 118 pd.ready_gpio = 18; 119 break; 120 121 default: 122 return -ENODEV; 123 } 124 125 pcmcia_resources[0].start = bcm63xx_regset_address(RSET_PCMCIA); 126 pcmcia_resources[0].end = pcmcia_resources[0].start + 127 RSET_PCMCIA_SIZE - 1; 128 pcmcia_resources[4].start = bcm63xx_get_irq_number(IRQ_PCMCIA); 129 130 /* configure pcmcia chip selects */ 131 for (i = 0; i < 3; i++) { 132 ret = config_pcmcia_cs(pcmcia_cs[i].cs, 133 pcmcia_cs[i].base, 134 pcmcia_cs[i].size); 135 if (ret) 136 goto out_err; 137 } 138 139 return platform_device_register(&bcm63xx_pcmcia_device); 140 141out_err: 142 printk(KERN_ERR "unable to set pcmcia chip select\n"); 143 return ret; 144} 145