1 /* $NetBSD: gemini_lpc.c,v 1.2 2008/11/10 04:05:35 cliff Exp $ */
3 #include "opt_gemini.h"
7 __KERNEL_RCSID(0, "$NetBSD: gemini_lpc.c,v 1.2 2008/11/10 04:05:35 cliff Exp $");
10 #include <sys/systm.h>
11 #include <sys/device.h>
12 #include <arch/arm/gemini/gemini_lpcvar.h>
13 #include <arch/arm/gemini/gemini_lpchcvar.h>
14 #include <arch/arm/gemini/gemini_reg.h>
17 /* XXX these should be in lpcreg.h or it8721reg.h */
18 #define IT8712_CFGCTL 0x02
19 # define CFGCTL_WAITKEY __BIT(1)
20 #define IT8712_LDN 0x07
21 #define IT8712_CHIPID1 0x20
22 #define IT8712_CHIPID2 0x21
23 #define IT8712_CSCV 0x22
24 # define CSCV_VERSION __BITS(3,0);
25 #define IT8712_CLKSEL 0x23
26 #define IT8712_SWSUSPEND 0x24
27 #define IT8712_ADDR 0x2e
28 #define IT8712_DATA 0x2f
30 static int gemini_lpc_match(struct device
*, struct cfdata
*, void *);
31 static void gemini_lpc_attach(struct device
*, struct device
*, void *);
32 static int gemini_lpc_search(device_t
, cfdata_t
, const int *, void *);
33 static int gemini_lpc_busprint(void *, const char *);
35 static uint8_t it8712_pnp_read(lpctag_t
, int, uint
);
36 static void it8712_pnp_write(lpctag_t
, int, uint
, uint8_t);
37 static void it8712_pnp_enter(lpctag_t
);
38 static void it8712_pnp_exit(lpctag_t
);
39 static void *it8712_intr_establish(lpctag_t
, uint
, int, int, int (*)(void *), void *);
40 static void it8712_intr_disestablish(lpctag_t
, void *);
42 CFATTACH_DECL_NEW(lpc
, sizeof(struct gemini_lpc_softc
),
43 gemini_lpc_match
, gemini_lpc_attach
, NULL
, NULL
);
45 gemini_lpc_bus_ops_t gemini_lpc_bus_ops
= {
50 it8712_intr_establish
,
51 it8712_intr_disestablish
,
56 gemini_lpc_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
58 struct gemini_lpc_attach_args
*lpc
= aux
;
60 if (lpc
->lpc_addr
== LPCCF_ADDR_DEFAULT
)
61 panic("lpc must have addr specified in config.");
67 gemini_lpc_attach(struct device
*parent
, struct device
*self
, void *aux
)
69 gemini_lpc_softc_t
*sc
= device_private(self
);
70 struct gemini_lpchc_attach_args
*lpchc
= aux
;
72 bus_space_handle_t ioh
;
73 uint8_t id1
, id2
, vers
, clk
, susp
;
75 sc
->sc_addr
= lpchc
->lpchc_addr
;
77 sc
->sc_size
= lpchc
->lpchc_size
;
80 * we just map the configuration registers
81 * child devices can map their own I/O
86 iot
= lpchc
->lpchc_iot
;
87 if (bus_space_map(iot
, sc
->sc_addr
, sc
->sc_size
, 0, &ioh
))
88 panic("%s: Cannot map registers", device_xname(self
));
93 id1
= it8712_pnp_read(sc
, GEMINI_LPC_LDN_ALL
, IT8712_CHIPID1
);
94 id2
= it8712_pnp_read(sc
, GEMINI_LPC_LDN_ALL
, IT8712_CHIPID2
);
95 vers
= it8712_pnp_read(sc
, GEMINI_LPC_LDN_ALL
, IT8712_CSCV
);
97 clk
= it8712_pnp_read(sc
, GEMINI_LPC_LDN_ALL
, IT8712_CLKSEL
);
98 susp
= it8712_pnp_read(sc
, GEMINI_LPC_LDN_ALL
, IT8712_SWSUSPEND
);
101 aprint_normal("\n%s: chip ID %x%x, version %d",
102 device_xname(self
), id1
, id2
, vers
);
103 aprint_normal("\n%s: clksel %#x, susp %#x ",
104 device_xname(self
), clk
, susp
);
106 sc
->sc_lpchctag
= lpchc
->lpchc_tag
;
107 sc
->sc_bus_ops
= &gemini_lpc_bus_ops
;
113 * attach the rest of our devices
115 config_search_ia(gemini_lpc_search
, self
, "lpc", NULL
);
119 gemini_lpc_search(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
121 gemini_lpc_softc_t
*sc
= device_private(parent
);
122 gemini_lpc_attach_args_t lpc
;
124 lpc
.lpc_ldn
= cf
->cf_loc
[LPCCF_LDN
];
125 lpc
.lpc_addr
= cf
->cf_loc
[LPCCF_ADDR
];
126 lpc
.lpc_size
= cf
->cf_loc
[LPCCF_SIZE
];
127 lpc
.lpc_intr
= cf
->cf_loc
[LPCCF_INTR
];
128 lpc
.lpc_iot
= sc
->sc_iot
;
130 lpc
.lpc_base
= sc
->sc_addr
;
132 if (config_match(parent
, cf
, &lpc
)) {
133 config_attach(parent
, cf
, &lpc
, gemini_lpc_busprint
);
134 return 0; /* love it */
137 return UNCONF
; /* hate it */
141 gemini_lpc_busprint(void *aux
, const char *name
)
143 struct gemini_lpc_attach_args
*lpc
= aux
;
145 if (lpc
->lpc_ldn
!= LPCCF_LDN_DEFAULT
)
146 aprint_normal(" ldn %d", lpc
->lpc_ldn
);
147 if (lpc
->lpc_addr
!= LPCCF_ADDR_DEFAULT
)
148 aprint_normal(" addr %#lx", lpc
->lpc_addr
);
149 if (lpc
->lpc_size
!= LPCCF_SIZE_DEFAULT
)
150 aprint_normal(" size %#lx", lpc
->lpc_size
);
151 if (lpc
->lpc_intr
!= LPCCF_INTR_DEFAULT
)
152 aprint_normal(" intr %d", lpc
->lpc_intr
);
162 it8712_pnp_read(lpctag_t tag
, int ldn
, uint index
)
164 gemini_lpc_softc_t
*sc
= tag
;
165 bus_space_tag_t iot
= sc
->sc_iot
;
166 bus_space_handle_t ioh
= sc
->sc_ioh
;
168 if (ldn
!= GEMINI_LPC_LDN_ALL
) {
169 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, IT8712_LDN
);
170 bus_space_write_1(iot
, ioh
, IT8712_DATA
, ldn
);
172 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, index
);
173 return bus_space_read_1(iot
, ioh
, IT8712_DATA
);
177 it8712_pnp_write(lpctag_t tag
, int ldn
, uint index
, uint8_t val
)
179 gemini_lpc_softc_t
*sc
= tag
;
180 bus_space_tag_t iot
= sc
->sc_iot
;
181 bus_space_handle_t ioh
= sc
->sc_ioh
;
183 if (ldn
!= GEMINI_LPC_LDN_ALL
) {
184 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, IT8712_LDN
);
185 bus_space_write_1(iot
, ioh
, IT8712_DATA
, ldn
);
187 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, index
);
188 bus_space_write_1(iot
, ioh
, IT8712_DATA
, val
);
192 it8712_pnp_enter(lpctag_t tag
)
194 gemini_lpc_softc_t
*sc
= tag
;
195 bus_space_tag_t iot
= sc
->sc_iot
;
196 bus_space_handle_t ioh
= sc
->sc_ioh
;
198 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, 0x87);
199 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, 0x01);
200 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, 0x55);
201 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, 0x55);
205 it8712_pnp_exit(lpctag_t tag
)
207 gemini_lpc_softc_t
*sc
= tag
;
208 bus_space_tag_t iot
= sc
->sc_iot
;
209 bus_space_handle_t ioh
= sc
->sc_ioh
;
211 bus_space_write_1(iot
, ioh
, IT8712_ADDR
, IT8712_CFGCTL
);
212 bus_space_write_1(iot
, ioh
, IT8712_DATA
, CFGCTL_WAITKEY
);
216 it8712_intr_establish(lpctag_t tag
, uint intr
, int ipl
, int ist
,
217 int (*func
)(void *), void *arg
)
219 gemini_lpc_softc_t
*sc
= tag
;
222 ih
= gemini_lpchc_intr_establish(sc
->sc_lpchctag
, intr
, ipl
, ist
, func
, arg
);
228 it8712_intr_disestablish(lpctag_t tag
, void *ih
)
230 gemini_lpc_softc_t
*sc
= tag
;
232 gemini_lpchc_intr_disestablish(sc
->sc_lpchctag
, ih
);