1 /* $NetBSD: lpc_com.c,v 1.2 2008/11/10 04:07:30 cliff Exp $ */
4 * NetBSD: gemini_com.c,v 1.1 2008/10/24 04:23:18 matt Exp
8 * Based on arch/arm/xscale/pxa2x0_com.c
10 * Copyright 2003 Wasabi Systems, Inc.
11 * All rights reserved.
13 * Written by Steve C. Woodford for Wasabi Systems, Inc.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 3. All advertising materials mentioning features or use of this software
24 * must display the following acknowledgement:
25 * This product includes software developed for the NetBSD Project by
26 * Wasabi Systems, Inc.
27 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
28 * or promote products derived from this software without specific prior
31 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
32 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
33 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
34 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
35 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
36 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
37 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGE.
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: lpc_com.c,v 1.2 2008/11/10 04:07:30 cliff Exp $");
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/device.h>
53 #include <sys/termios.h>
54 #include <sys/callout.h>
55 #include <sys/kernel.h>
57 #include <machine/intr.h>
58 #include <machine/bus.h>
60 #include <dev/ic/comreg.h>
61 #include <dev/ic/comvar.h>
63 #include <arm/gemini/gemini_obiovar.h>
64 #include <arm/gemini/gemini_lpchcvar.h>
65 #include <arm/gemini/gemini_lpcvar.h>
66 #include <arm/gemini/gemini_reg.h>
68 #include <arm/gemini/lpc_com.h>
70 typedef struct lpc_com_softc
{
71 struct com_softc sc_com
;
75 bus_space_tag_t sc_iot
;
76 bus_space_handle_t sc_ioh
;
77 struct callout sc_callout
;
80 static int lpc_com_match(device_t
, cfdata_t
, void *);
81 static void lpc_com_attach(device_t
, device_t
, void *);
82 static int lpc_com_intr(void *);
83 static void lpc_com_time(void *);
85 CFATTACH_DECL_NEW(lpc_com
, sizeof(struct lpc_com_softc
),
86 lpc_com_match
, lpc_com_attach
, NULL
, NULL
);
89 lpc_com_match(device_t parent
, cfdata_t cf
, void *aux
)
91 struct gemini_lpc_attach_args
*lpc
= aux
;
94 bus_space_handle_t ioh
;
98 if (lpc
->lpc_addr
== LPCCF_LDN_DEFAULT
99 || lpc
->lpc_addr
== LPCCF_ADDR_DEFAULT
)
100 panic("lpc_com must have ldn and addr"
103 if ((lpc
->lpc_intr
!= LPCCF_INTR_DEFAULT
) && (lpc
->lpc_intr
> 0xff))
104 panic("lpc_com: bad intr %d", lpc
->lpc_intr
);
106 if (lpc
->lpc_size
== LPCCF_SIZE_DEFAULT
)
107 lpc
->lpc_size
= IT8712F_UART_SIZE
;
109 iobase
= lpc
->lpc_base
+ lpc
->lpc_addr
;
110 if (com_is_console(lpc
->lpc_iot
, iobase
, NULL
))
113 lpctag
= lpc
->lpc_tag
;
115 lpc_pnp_enter(lpctag
);
118 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0x30, 0x01);
121 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0x60,
122 (lpc
->lpc_addr
% 0xff00) >> 8);
123 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0x61,
124 (lpc
->lpc_addr
% 0x00ff) >> 0);
126 /* Set Interrupt Level */
127 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0x70, lpc
->lpc_intr
);
129 /* Set Special Configuration Regs */
130 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0xf0, 0x00);
132 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0xf1, 0x50);
134 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0xf1, 0x58); /* LO */
136 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0xf2, 0x00);
137 lpc_pnp_write(lpctag
, lpc
->lpc_ldn
, 0xf3, 0x7f);
139 lpc_pnp_exit(lpctag
);
142 if (bus_space_map(iot
, iobase
, lpc
->lpc_size
, 0, &ioh
))
145 rv
= comprobe1(iot
, ioh
);
147 bus_space_unmap(iot
, ioh
, lpc
->lpc_size
);
153 lpc_com_attach(device_t parent
, device_t self
, void *aux
)
155 struct lpc_com_softc
*sc
= device_private(self
);
156 struct gemini_lpc_attach_args
*lpc
= aux
;
158 bus_space_handle_t ioh
;
161 sc
->sc_com
.sc_dev
= self
;
163 iobase
= lpc
->lpc_base
+ lpc
->lpc_addr
;
164 sc
->sc_com
.sc_frequency
= IT8712F_COM_FREQ
;
165 sc
->sc_com
.sc_type
= COM_TYPE_NORMAL
;
167 if (com_is_console(iot
, iobase
, &ioh
) == 0 &&
168 bus_space_map(iot
, iobase
, lpc
->lpc_size
, 0, &ioh
)) {
169 panic(": can't map registers\n");
173 COM_INIT_REGS(sc
->sc_com
.sc_regs
, iot
, ioh
, iobase
);
175 com_attach_subr(&sc
->sc_com
);
178 if (lpc
->lpc_intr
== LPCCF_INTR_DEFAULT
) {
179 /* callout based polliung */
180 callout_init(&sc
->sc_callout
, 0);
181 callout_setfunc(&sc
->sc_callout
, lpc_com_time
, sc
);
182 callout_schedule(&sc
->sc_callout
, hz
/16);
183 aprint_normal("%s: callout polling mode\n", device_xname(self
));
187 lpc_intr_establish(lpc
->lpc_tag
, lpc
->lpc_intr
,
188 IPL_SERIAL
, IST_LEVEL_HIGH
, comintr
, &sc
->sc_com
);
190 lpc_intr_establish(lpc
->lpc_tag
, lpc
->lpc_intr
,
191 IPL_SERIAL
, IST_LEVEL_LOW
, lpc_com_intr
, &sc
->sc_com
);
197 lpc_com_intr(void *arg
)
204 lpc_com_time(void *arg
)
206 lpc_com_softc_t
*sc
= arg
;
210 (void)comintr(&sc
->sc_com
);
211 callout_schedule(&sc
->sc_callout
, hz
/16);