diff options
Diffstat (limited to 'drivers/pcmcia/sa1111_generic.c')
-rw-r--r-- | drivers/pcmcia/sa1111_generic.c | 58 |
1 files changed, 45 insertions, 13 deletions
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index a6793e30cf71..98c791537cac 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c | |||
@@ -30,9 +30,6 @@ static struct pcmcia_irqs irqs[] = { | |||
30 | 30 | ||
31 | int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | 31 | int sa1111_pcmcia_hw_init(struct soc_pcmcia_socket *skt) |
32 | { | 32 | { |
33 | if (skt->irq == NO_IRQ) | ||
34 | skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; | ||
35 | |||
36 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 33 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
37 | } | 34 | } |
38 | 35 | ||
@@ -43,8 +40,8 @@ void sa1111_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | |||
43 | 40 | ||
44 | void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) | 41 | void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) |
45 | { | 42 | { |
46 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | 43 | struct sa1111_pcmcia_socket *s = to_skt(skt); |
47 | unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); | 44 | unsigned long status = sa1111_readl(s->dev->mapbase + SA1111_PCSR); |
48 | 45 | ||
49 | switch (skt->nr) { | 46 | switch (skt->nr) { |
50 | case 0: | 47 | case 0: |
@@ -71,7 +68,7 @@ void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_sta | |||
71 | 68 | ||
72 | int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) | 69 | int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) |
73 | { | 70 | { |
74 | struct sa1111_dev *sadev = SA1111_DEV(skt->dev); | 71 | struct sa1111_pcmcia_socket *s = to_skt(skt); |
75 | unsigned int pccr_skt_mask, pccr_set_mask, val; | 72 | unsigned int pccr_skt_mask, pccr_set_mask, val; |
76 | unsigned long flags; | 73 | unsigned long flags; |
77 | 74 | ||
@@ -100,10 +97,10 @@ int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_s | |||
100 | pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; | 97 | pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; |
101 | 98 | ||
102 | local_irq_save(flags); | 99 | local_irq_save(flags); |
103 | val = sa1111_readl(sadev->mapbase + SA1111_PCCR); | 100 | val = sa1111_readl(s->dev->mapbase + SA1111_PCCR); |
104 | val &= ~pccr_skt_mask; | 101 | val &= ~pccr_skt_mask; |
105 | val |= pccr_set_mask & pccr_skt_mask; | 102 | val |= pccr_set_mask & pccr_skt_mask; |
106 | sa1111_writel(val, sadev->mapbase + SA1111_PCCR); | 103 | sa1111_writel(val, s->dev->mapbase + SA1111_PCCR); |
107 | local_irq_restore(flags); | 104 | local_irq_restore(flags); |
108 | 105 | ||
109 | return 0; | 106 | return 0; |
@@ -119,10 +116,45 @@ void sa1111_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | |||
119 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); | 116 | soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); |
120 | } | 117 | } |
121 | 118 | ||
119 | int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, | ||
120 | int (*add)(struct soc_pcmcia_socket *)) | ||
121 | { | ||
122 | struct sa1111_pcmcia_socket *s; | ||
123 | int i, ret = 0; | ||
124 | |||
125 | s = kzalloc(sizeof(*s) * ops->nr, GFP_KERNEL); | ||
126 | if (!s) | ||
127 | return -ENODEV; | ||
128 | |||
129 | for (i = 0; i < ops->nr; i++) { | ||
130 | s = kzalloc(sizeof(*s), GFP_KERNEL); | ||
131 | if (!s) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | s->soc.nr = ops->first + i; | ||
135 | s->soc.irq = s->soc.nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; | ||
136 | s->soc.ops = ops; | ||
137 | s->soc.socket.owner = ops->owner; | ||
138 | s->soc.socket.dev.parent = &dev->dev; | ||
139 | s->dev = dev; | ||
140 | |||
141 | ret = add(&s->soc); | ||
142 | if (ret == 0) { | ||
143 | s->next = dev_get_drvdata(&dev->dev); | ||
144 | dev_set_drvdata(&dev->dev, s); | ||
145 | } else | ||
146 | kfree(s); | ||
147 | } | ||
148 | |||
149 | return ret; | ||
150 | } | ||
151 | |||
122 | static int pcmcia_probe(struct sa1111_dev *dev) | 152 | static int pcmcia_probe(struct sa1111_dev *dev) |
123 | { | 153 | { |
124 | void __iomem *base; | 154 | void __iomem *base; |
125 | 155 | ||
156 | dev_set_drvdata(&dev->dev, NULL); | ||
157 | |||
126 | if (!request_mem_region(dev->res.start, 512, | 158 | if (!request_mem_region(dev->res.start, 512, |
127 | SA1111_DRIVER_NAME(dev))) | 159 | SA1111_DRIVER_NAME(dev))) |
128 | return -EBUSY; | 160 | return -EBUSY; |
@@ -152,15 +184,15 @@ static int pcmcia_probe(struct sa1111_dev *dev) | |||
152 | 184 | ||
153 | static int __devexit pcmcia_remove(struct sa1111_dev *dev) | 185 | static int __devexit pcmcia_remove(struct sa1111_dev *dev) |
154 | { | 186 | { |
155 | struct skt_dev_info *sinfo = dev_get_drvdata(&dev->dev); | 187 | struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev); |
156 | int i; | ||
157 | 188 | ||
158 | dev_set_drvdata(&dev->dev, NULL); | 189 | dev_set_drvdata(&dev->dev, NULL); |
159 | 190 | ||
160 | for (i = 0; i < sinfo->nskt; i++) | 191 | for (; next = s->next, s; s = next) { |
161 | soc_pcmcia_remove_one(&sinfo->skt[i]); | 192 | soc_pcmcia_remove_one(&s->soc); |
193 | kfree(s); | ||
194 | } | ||
162 | 195 | ||
163 | kfree(sinfo); | ||
164 | release_mem_region(dev->res.start, 512); | 196 | release_mem_region(dev->res.start, 512); |
165 | return 0; | 197 | return 0; |
166 | } | 198 | } |