1 /* $NetBSD: ipaq_pcic.c,v 1.18 2008/04/28 20:23:21 martin Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ichiro FUKUHARA (ichiro@ichiro.org).
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ipaq_pcic.c,v 1.18 2008/04/28 20:23:21 martin Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/types.h>
40 #include <sys/device.h>
41 #include <sys/kernel.h>
42 #include <sys/kthread.h>
43 #include <sys/malloc.h>
45 #include <machine/bus.h>
46 #include <dev/pcmcia/pcmciachip.h>
47 #include <dev/pcmcia/pcmciavar.h>
49 #include <hpcarm/dev/ipaq_saipvar.h>
50 #include <hpcarm/dev/ipaq_pcicreg.h>
51 #include <hpcarm/dev/ipaq_gpioreg.h>
53 #include <arm/sa11x0/sa11x0_gpioreg.h>
54 #include <arm/sa11x0/sa11x0_var.h>
55 #include <arm/sa11x0/sa11xx_pcicvar.h>
59 static int ipaqpcic_match(device_t
, cfdata_t
, void *);
60 static void ipaqpcic_attach(device_t
, device_t
, void *);
61 static int ipaqpcic_print(void *, const char *);
63 static int ipaqpcic_read(struct sapcic_socket
*, int);
64 static void ipaqpcic_write(struct sapcic_socket
*, int, int);
65 static void ipaqpcic_set_power(struct sapcic_socket
*, int);
66 static void ipaqpcic_clear_intr(int);
67 static void *ipaqpcic_intr_establish(struct sapcic_socket
*, int,
68 int (*)(void *), void *);
69 static void ipaqpcic_intr_disestablish(struct sapcic_socket
*, void *);
71 struct ipaqpcic_softc
{
72 struct sapcic_softc sc_pc
;
73 bus_space_handle_t sc_ioh
;
74 struct ipaq_softc
*sc_parent
;
75 struct sapcic_socket sc_socket
[2];
78 static void ipaqpcic_init(struct ipaqpcic_softc
*);
80 static struct sapcic_tag ipaqpcic_functions
= {
85 ipaqpcic_intr_establish
,
86 ipaqpcic_intr_disestablish
89 CFATTACH_DECL_NEW(ipaqpcic
, sizeof(struct ipaqpcic_softc
),
90 ipaqpcic_match
, ipaqpcic_attach
, NULL
, NULL
);
93 ipaqpcic_match(device_t parent
, cfdata_t cf
, void *aux
)
99 ipaqpcic_attach(device_t parent
, device_t self
, void *aux
)
102 struct pcmciabus_attach_args paa
;
103 struct ipaqpcic_softc
*sc
= device_private(self
);
104 struct ipaq_softc
*psc
= device_private(parent
);
108 sc
->sc_pc
.sc_dev
= self
;
109 sc
->sc_pc
.sc_iot
= psc
->sc_iot
;
110 sc
->sc_ioh
= psc
->sc_ioh
;
115 for(i
= 0; i
< 2; i
++) {
116 sc
->sc_socket
[i
].sc
= (struct sapcic_softc
*)sc
;
117 sc
->sc_socket
[i
].socket
= i
;
118 sc
->sc_socket
[i
].pcictag_cookie
= psc
;
119 sc
->sc_socket
[i
].pcictag
= &ipaqpcic_functions
;
120 sc
->sc_socket
[i
].event_thread
= NULL
;
121 sc
->sc_socket
[i
].event
= 0;
122 sc
->sc_socket
[i
].laststatus
= SAPCIC_CARD_INVALID
;
123 sc
->sc_socket
[i
].shutdown
= 0;
125 paa
.paa_busname
= "pcmcia";
126 paa
.pct
= (pcmcia_chipset_tag_t
)&sa11x0_pcmcia_functions
;
127 paa
.pch
= (pcmcia_chipset_handle_t
)&sc
->sc_socket
[i
];
129 paa
.iosize
= 0x4000000;
131 sc
->sc_socket
[i
].pcmcia
=
132 config_found_ia(sc
->sc_pc
.sc_dev
, "pcmciabus",
133 &paa
, ipaqpcic_print
);
135 sa11x0_intr_establish((sa11x0_chipset_tag_t
)psc
,
136 i
? IRQ_CD1
: IRQ_CD0
,
137 1, IPL_BIO
, sapcic_intr
,
140 /* schedule kthread creation */
141 sapcic_kthread_create(&sc
->sc_socket
[i
]);
144 /* establish_intr should be after creating the kthread */
145 config_interrupt(&sc
->sc_socket
[i
], ipaqpcic_config_intr
);
151 ipaqpcic_print(void *aux
, const char *name
)
157 ipaqpcic_init(struct ipaqpcic_softc
*sc
)
161 /* All those are inputs */
162 cr
= bus_space_read_4(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_gpioh
, SAGPIO_PDR
);
163 cr
&= ~(GPIO_H3600_PCMCIA_CD0
| GPIO_H3600_PCMCIA_CD1
| GPIO_H3600_PCMCIA_IRQ0
|
164 GPIO_H3600_PCMCIA_IRQ1
);
165 bus_space_write_4(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_gpioh
, SAGPIO_PDR
, cr
);
167 sc
->sc_parent
->ipaq_egpio
|=
168 EGPIO_H3600_OPT_NVRAM_ON
| EGPIO_H3600_OPT_ON
;
169 sc
->sc_parent
->ipaq_egpio
&=
170 ~(EGPIO_H3600_CARD_RESET
| EGPIO_H3600_OPT_RESET
);
171 bus_space_write_2(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_egpioh
,
172 0, sc
->sc_parent
->ipaq_egpio
);
176 ipaqpcic_read(struct sapcic_socket
*so
, int reg
)
179 struct ipaqpcic_softc
*sc
= (struct ipaqpcic_softc
*)so
->sc
;
181 cr
= bus_space_read_4(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_gpioh
, SAGPIO_PLR
);
184 case SAPCIC_STATUS_CARD
:
185 bit
= (so
->socket
? GPIO_H3600_PCMCIA_CD0
:
186 GPIO_H3600_PCMCIA_CD1
) & cr
;
188 return SAPCIC_CARD_INVALID
;
190 return SAPCIC_CARD_VALID
;
191 case SAPCIC_STATUS_VS1
:
192 case SAPCIC_STATUS_VS2
:
193 case SAPCIC_STATUS_READY
:
194 bit
= (so
->socket
? GPIO_H3600_PCMCIA_IRQ0
:
195 GPIO_H3600_PCMCIA_IRQ1
);
198 panic("ipaqpcic_read: bogus register");
203 ipaqpcic_write(struct sapcic_socket
*so
, int reg
, int arg
)
206 struct ipaqpcic_softc
*sc
= (struct ipaqpcic_softc
*)so
->sc
;
210 case SAPCIC_CONTROL_RESET
:
211 sc
->sc_parent
->ipaq_egpio
|= EGPIO_H3600_CARD_RESET
;
213 case SAPCIC_CONTROL_LINEENABLE
:
214 case SAPCIC_CONTROL_WAITENABLE
:
215 case SAPCIC_CONTROL_POWERSELECT
:
220 panic("ipaqpcic_write: bogus register");
222 bus_space_write_2(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_egpioh
, 0,
223 sc
->sc_parent
->ipaq_egpio
);
228 ipaqpcic_set_power(struct sapcic_socket
*so
, int arg
)
231 struct ipaqpcic_softc
*sc
= (struct ipaqpcic_softc
*)so
->sc
;
235 case SAPCIC_POWER_OFF
:
236 sc
->sc_parent
->ipaq_egpio
&=
237 ~(EGPIO_H3600_OPT_NVRAM_ON
| EGPIO_H3600_OPT_ON
);
239 case SAPCIC_POWER_3V
:
240 case SAPCIC_POWER_5V
:
241 sc
->sc_parent
->ipaq_egpio
|=
242 EGPIO_H3600_OPT_NVRAM_ON
| EGPIO_H3600_OPT_ON
;
245 panic("ipaqpcic_set_power: bogus arg");
247 bus_space_write_2(sc
->sc_pc
.sc_iot
, sc
->sc_parent
->sc_egpioh
,
248 0, sc
->sc_parent
->ipaq_egpio
);
253 ipaqpcic_clear_intr(int arg
)
258 ipaqpcic_intr_establish(struct sapcic_socket
*so
, int level
,
259 int (*ih_fun
)(void *), void *ih_arg
)
263 irq
= so
->socket
? IRQ_IRQ0
: IRQ_IRQ1
;
264 return (sa11x0_intr_establish((sa11x0_chipset_tag_t
)so
->pcictag_cookie
,
265 irq
-16, 1, level
, ih_fun
, ih_arg
));
269 ipaqpcic_intr_disestablish(struct sapcic_socket
*so
, void *ih
)
271 sa11x0_intr_disestablish((sa11x0_chipset_tag_t
)so
->pcictag_cookie
, ih
);