diff options
Diffstat (limited to 'include/asm-sparc64/parport.h')
-rw-r--r-- | include/asm-sparc64/parport.h | 233 |
1 files changed, 133 insertions, 100 deletions
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h index 23cc63f049a8..600afe5ae2e3 100644 --- a/include/asm-sparc64/parport.h +++ b/include/asm-sparc64/parport.h | |||
@@ -8,8 +8,9 @@ | |||
8 | #define _ASM_SPARC64_PARPORT_H 1 | 8 | #define _ASM_SPARC64_PARPORT_H 1 |
9 | 9 | ||
10 | #include <asm/ebus.h> | 10 | #include <asm/ebus.h> |
11 | #include <asm/isa.h> | ||
12 | #include <asm/ns87303.h> | 11 | #include <asm/ns87303.h> |
12 | #include <asm/of_device.h> | ||
13 | #include <asm/prom.h> | ||
13 | 14 | ||
14 | #define PARPORT_PC_MAX_PORTS PARPORT_MAX | 15 | #define PARPORT_PC_MAX_PORTS PARPORT_MAX |
15 | 16 | ||
@@ -35,8 +36,12 @@ static struct sparc_ebus_info { | |||
35 | unsigned int addr; | 36 | unsigned int addr; |
36 | unsigned int count; | 37 | unsigned int count; |
37 | int lock; | 38 | int lock; |
39 | |||
40 | struct parport *port; | ||
38 | } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; | 41 | } sparc_ebus_dmas[PARPORT_PC_MAX_PORTS]; |
39 | 42 | ||
43 | static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS); | ||
44 | |||
40 | static __inline__ int request_dma(unsigned int dmanr, const char *device_id) | 45 | static __inline__ int request_dma(unsigned int dmanr, const char *device_id) |
41 | { | 46 | { |
42 | if (dmanr >= PARPORT_PC_MAX_PORTS) | 47 | if (dmanr >= PARPORT_PC_MAX_PORTS) |
@@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr) | |||
98 | return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); | 103 | return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info); |
99 | } | 104 | } |
100 | 105 | ||
101 | static int ebus_ecpp_p(struct linux_ebus_device *edev) | 106 | static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match) |
102 | { | 107 | { |
103 | if (!strcmp(edev->prom_node->name, "ecpp")) | 108 | unsigned long base = op->resource[0].start; |
104 | return 1; | 109 | unsigned long config = op->resource[1].start; |
105 | if (!strcmp(edev->prom_node->name, "parallel")) { | 110 | unsigned long d_base = op->resource[2].start; |
106 | const char *compat; | 111 | unsigned long d_len; |
107 | 112 | struct device_node *parent; | |
108 | compat = of_get_property(edev->prom_node, | 113 | struct parport *p; |
109 | "compatible", NULL); | 114 | int slot, err; |
110 | if (compat && | 115 | |
111 | (!strcmp(compat, "ecpp") || | 116 | parent = op->node->parent; |
112 | !strcmp(compat, "ns87317-ecpp") || | 117 | if (!strcmp(parent->name, "dma")) { |
113 | !strcmp(compat + 13, "ecpp"))) | 118 | p = parport_pc_probe_port(base, base + 0x400, |
114 | return 1; | 119 | op->irqs[0], PARPORT_DMA_NOFIFO, |
120 | op->dev.parent); | ||
121 | if (!p) | ||
122 | return -ENOMEM; | ||
123 | dev_set_drvdata(&op->dev, p); | ||
124 | return 0; | ||
115 | } | 125 | } |
126 | |||
127 | for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) { | ||
128 | if (!test_and_set_bit(slot, dma_slot_map)) | ||
129 | break; | ||
130 | } | ||
131 | err = -ENODEV; | ||
132 | if (slot >= PARPORT_PC_MAX_PORTS) | ||
133 | goto out_err; | ||
134 | |||
135 | spin_lock_init(&sparc_ebus_dmas[slot].info.lock); | ||
136 | |||
137 | d_len = (op->resource[2].end - d_base) + 1UL; | ||
138 | sparc_ebus_dmas[slot].info.regs = | ||
139 | of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA"); | ||
140 | |||
141 | if (!sparc_ebus_dmas[slot].info.regs) | ||
142 | goto out_clear_map; | ||
143 | |||
144 | sparc_ebus_dmas[slot].info.flags = 0; | ||
145 | sparc_ebus_dmas[slot].info.callback = NULL; | ||
146 | sparc_ebus_dmas[slot].info.client_cookie = NULL; | ||
147 | sparc_ebus_dmas[slot].info.irq = 0xdeadbeef; | ||
148 | strcpy(sparc_ebus_dmas[slot].info.name, "parport"); | ||
149 | if (ebus_dma_register(&sparc_ebus_dmas[slot].info)) | ||
150 | goto out_unmap_regs; | ||
151 | |||
152 | ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1); | ||
153 | |||
154 | /* Configure IRQ to Push Pull, Level Low */ | ||
155 | /* Enable ECP, set bit 2 of the CTR first */ | ||
156 | outb(0x04, base + 0x02); | ||
157 | ns87303_modify(config, PCR, | ||
158 | PCR_EPP_ENABLE | | ||
159 | PCR_IRQ_ODRAIN, | ||
160 | PCR_ECP_ENABLE | | ||
161 | PCR_ECP_CLK_ENA | | ||
162 | PCR_IRQ_POLAR); | ||
163 | |||
164 | /* CTR bit 5 controls direction of port */ | ||
165 | ns87303_modify(config, PTR, | ||
166 | 0, PTR_LPT_REG_DIR); | ||
167 | |||
168 | p = parport_pc_probe_port(base, base + 0x400, | ||
169 | op->irqs[0], | ||
170 | slot, | ||
171 | op->dev.parent); | ||
172 | err = -ENOMEM; | ||
173 | if (!p) | ||
174 | goto out_disable_irq; | ||
175 | |||
176 | dev_set_drvdata(&op->dev, p); | ||
177 | |||
116 | return 0; | 178 | return 0; |
179 | |||
180 | out_disable_irq: | ||
181 | ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); | ||
182 | ebus_dma_unregister(&sparc_ebus_dmas[slot].info); | ||
183 | |||
184 | out_unmap_regs: | ||
185 | of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len); | ||
186 | |||
187 | out_clear_map: | ||
188 | clear_bit(slot, dma_slot_map); | ||
189 | |||
190 | out_err: | ||
191 | return err; | ||
117 | } | 192 | } |
118 | 193 | ||
119 | static int parport_isa_probe(int count) | 194 | static int __devexit ecpp_remove(struct of_device *op) |
120 | { | 195 | { |
121 | struct sparc_isa_bridge *isa_br; | 196 | struct parport *p = dev_get_drvdata(&op->dev); |
122 | struct sparc_isa_device *isa_dev; | 197 | int slot = p->dma; |
123 | 198 | ||
124 | for_each_isa(isa_br) { | 199 | parport_pc_unregister_port(p); |
125 | for_each_isadev(isa_dev, isa_br) { | 200 | |
126 | struct sparc_isa_device *child; | 201 | if (slot != PARPORT_DMA_NOFIFO) { |
127 | unsigned long base; | 202 | unsigned long d_base = op->resource[2].start; |
128 | 203 | unsigned long d_len; | |
129 | if (strcmp(isa_dev->prom_node->name, "dma")) | 204 | |
130 | continue; | 205 | d_len = (op->resource[2].end - d_base) + 1UL; |
131 | 206 | ||
132 | child = isa_dev->child; | 207 | ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0); |
133 | while (child) { | 208 | ebus_dma_unregister(&sparc_ebus_dmas[slot].info); |
134 | if (!strcmp(child->prom_node->name, "parallel")) | 209 | of_iounmap(&op->resource[2], |
135 | break; | 210 | sparc_ebus_dmas[slot].info.regs, |
136 | child = child->next; | 211 | d_len); |
137 | } | 212 | clear_bit(slot, dma_slot_map); |
138 | if (!child) | ||
139 | continue; | ||
140 | |||
141 | base = child->resource.start; | ||
142 | |||
143 | /* No DMA, see commentary in | ||
144 | * asm-sparc64/floppy.h:isa_floppy_init() | ||
145 | */ | ||
146 | if (parport_pc_probe_port(base, base + 0x400, | ||
147 | child->irq, PARPORT_DMA_NOFIFO, | ||
148 | &child->bus->self->dev)) | ||
149 | count++; | ||
150 | } | ||
151 | } | 213 | } |
152 | 214 | ||
153 | return count; | 215 | return 0; |
154 | } | 216 | } |
155 | 217 | ||
156 | static int parport_pc_find_nonpci_ports (int autoirq, int autodma) | 218 | static struct of_device_id ecpp_match[] = { |
219 | { | ||
220 | .name = "ecpp", | ||
221 | }, | ||
222 | { | ||
223 | .name = "parallel", | ||
224 | .compatible = "ecpp", | ||
225 | }, | ||
226 | { | ||
227 | .name = "parallel", | ||
228 | .compatible = "ns87317-ecpp", | ||
229 | }, | ||
230 | {}, | ||
231 | }; | ||
232 | |||
233 | static struct of_platform_driver ecpp_driver = { | ||
234 | .name = "ecpp", | ||
235 | .match_table = ecpp_match, | ||
236 | .probe = ecpp_probe, | ||
237 | .remove = __devexit_p(ecpp_remove), | ||
238 | }; | ||
239 | |||
240 | static int parport_pc_find_nonpci_ports(int autoirq, int autodma) | ||
157 | { | 241 | { |
158 | struct linux_ebus *ebus; | 242 | of_register_driver(&ecpp_driver, &of_bus_type); |
159 | struct linux_ebus_device *edev; | ||
160 | int count = 0; | ||
161 | |||
162 | for_each_ebus(ebus) { | ||
163 | for_each_ebusdev(edev, ebus) { | ||
164 | if (ebus_ecpp_p(edev)) { | ||
165 | unsigned long base = edev->resource[0].start; | ||
166 | unsigned long config = edev->resource[1].start; | ||
167 | unsigned long d_base = edev->resource[2].start; | ||
168 | unsigned long d_len; | ||
169 | |||
170 | spin_lock_init(&sparc_ebus_dmas[count].info.lock); | ||
171 | d_len = (edev->resource[2].end - | ||
172 | d_base) + 1; | ||
173 | sparc_ebus_dmas[count].info.regs = | ||
174 | ioremap(d_base, d_len); | ||
175 | if (!sparc_ebus_dmas[count].info.regs) | ||
176 | continue; | ||
177 | sparc_ebus_dmas[count].info.flags = 0; | ||
178 | sparc_ebus_dmas[count].info.callback = NULL; | ||
179 | sparc_ebus_dmas[count].info.client_cookie = NULL; | ||
180 | sparc_ebus_dmas[count].info.irq = 0xdeadbeef; | ||
181 | strcpy(sparc_ebus_dmas[count].info.name, "parport"); | ||
182 | if (ebus_dma_register(&sparc_ebus_dmas[count].info)) | ||
183 | continue; | ||
184 | ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1); | ||
185 | |||
186 | /* Configure IRQ to Push Pull, Level Low */ | ||
187 | /* Enable ECP, set bit 2 of the CTR first */ | ||
188 | outb(0x04, base + 0x02); | ||
189 | ns87303_modify(config, PCR, | ||
190 | PCR_EPP_ENABLE | | ||
191 | PCR_IRQ_ODRAIN, | ||
192 | PCR_ECP_ENABLE | | ||
193 | PCR_ECP_CLK_ENA | | ||
194 | PCR_IRQ_POLAR); | ||
195 | |||
196 | /* CTR bit 5 controls direction of port */ | ||
197 | ns87303_modify(config, PTR, | ||
198 | 0, PTR_LPT_REG_DIR); | ||
199 | |||
200 | if (parport_pc_probe_port(base, base + 0x400, | ||
201 | edev->irqs[0], | ||
202 | count, | ||
203 | &ebus->self->dev)) | ||
204 | count++; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | 243 | ||
209 | count = parport_isa_probe(count); | 244 | return 0; |
210 | |||
211 | return count; | ||
212 | } | 245 | } |
213 | 246 | ||
214 | #endif /* !(_ASM_SPARC64_PARPORT_H */ | 247 | #endif /* !(_ASM_SPARC64_PARPORT_H */ |