1 /* $NetBSD: alipm.c,v 1.5 2009/05/11 21:13:09 cegger Exp $ */
2 /* $OpenBSD: alipm.c,v 1.13 2007/05/03 12:19:01 dlg Exp $ */
5 * Copyright (c) 2005 Mark Kettenis
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __KERNEL_RCSID(0, "$NetBSD: alipm.c,v 1.5 2009/05/11 21:13:09 cegger Exp $");
23 #include <sys/param.h>
24 #include <sys/device.h>
25 #include <sys/kernel.h>
26 #include <sys/rwlock.h>
28 #include <sys/systm.h>
30 #include <dev/i2c/i2cvar.h>
32 #include <dev/pci/pcidevs.h>
33 #include <dev/pci/pcireg.h>
34 #include <dev/pci/pcivar.h>
37 * Acer Labs M7101 Power register definitions.
40 /* PCI configuration registers. */
41 #define ALIPM_CONF 0xd0 /* general configuration */
42 #define ALIPM_CONF_SMBEN 0x0400 /* enable SMBus */
43 #define ALIPM_BASE 0xe0 /* ACPI and SMBus base address */
44 #define ALIPM_SMB_HOSTC 0xf0 /* host configuration */
45 #define ALIPM_SMB_HOSTC_HSTEN 0x00000001 /* enable host controller */
46 #define ALIPM_SMB_HOSTC_CLOCK 0x00e00000 /* clock speed */
47 #define ALIPM_SMB_HOSTC_149K 0x00000000 /* 149 KHz clock */
48 #define ALIPM_SMB_HOSTC_74K 0x00200000 /* 74 KHz clock */
49 #define ALIPM_SMB_HOSTC_37K 0x00400000 /* 37 KHz clock */
50 #define ALIPM_SMB_HOSTC_223K 0x00800000 /* 223 KHz clock */
51 #define ALIPM_SMB_HOSTC_111K 0x00a00000 /* 111 KHz clock */
52 #define ALIPM_SMB_HOSTC_55K 0x00c00000 /* 55 KHz clock */
54 #define ALIPM_SMB_SIZE 32 /* SMBus I/O space size */
56 /* SMBus I/O registers */
57 #define ALIPM_SMB_HS 0x00 /* host status */
58 #define ALIPM_SMB_HS_IDLE 0x04
59 #define ALIPM_SMB_HS_BUSY 0x08 /* running a command */
60 #define ALIPM_SMB_HS_DONE 0x10 /* command completed */
61 #define ALIPM_SMB_HS_DEVERR 0x20 /* command error */
62 #define ALIPM_SMB_HS_BUSERR 0x40 /* transaction collision */
63 #define ALIPM_SMB_HS_FAILED 0x80 /* failed bus transaction */
64 #define ALIPM_SMB_HS_BITS \
65 "\020\003IDLE\004BUSY\005DONE\006DEVERR\007BUSERR\010FAILED"
66 #define ALIPM_SMB_HC 0x01 /* host control */
67 #define ALIPM_SMB_HC_KILL 0x04 /* kill command */
68 #define ALIPM_SMB_HC_RESET 0x08 /* reset bus */
69 #define ALIPM_SMB_HC_CMD_QUICK 0x00 /* QUICK command */
70 #define ALIPM_SMB_HC_CMD_BYTE 0x10 /* BYTE command */
71 #define ALIPM_SMB_HC_CMD_BDATA 0x20 /* BYTE DATA command */
72 #define ALIPM_SMB_HC_CMD_WDATA 0x30 /* WORD DATA command */
73 #define ALIPM_SMB_HC_CMD_BLOCK 0x40 /* BLOCK command */
74 #define ALIPM_SMB_START 0x02 /* start command */
75 #define ALIPM_SMB_TXSLVA 0x03 /* transmit slave address */
76 #define ALIPM_SMB_TXSLVA_READ (1 << 0) /* read direction */
77 #define ALIPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1) /* 7-bit address */
78 #define ALIPM_SMB_HD0 0x04 /* host data 0 */
79 #define ALIPM_SMB_HD1 0x05 /* host data 1 */
80 #define ALIPM_SMB_HBDB 0x06 /* host block data byte */
81 #define ALIPM_SMB_HCMD 0x07 /* host command */
84 * Newer chips have a more standard, but different PCI configuration
88 #define ALIPM_SMB_BASE 0x14 /* SMBus base address */
89 #define ALIPM_SMB_HOSTX 0xe0 /* host configuration */
92 #define DPRINTF(x) printf x
97 #define ALIPM_DELAY 100
98 #define ALIPM_TIMEOUT 1
101 struct device sc_dev
;
103 bus_space_tag_t sc_iot
;
104 bus_space_handle_t sc_ioh
;
106 struct i2c_controller sc_smb_tag
;
107 krwlock_t sc_smb_lock
;
110 static int alipm_match(device_t
, cfdata_t
, void *);
111 static void alipm_attach(device_t
, device_t
, void *);
113 int alipm_smb_acquire_bus(void *, int);
114 void alipm_smb_release_bus(void *, int);
115 int alipm_smb_exec(void *, i2c_op_t
, i2c_addr_t
, const void *,
116 size_t, void *, size_t, int);
118 CFATTACH_DECL(alipm
, sizeof(struct alipm_softc
),
119 alipm_match
, alipm_attach
, NULL
, NULL
);
122 alipm_match(device_t parent
, cfdata_t match
, void *aux
)
124 struct pci_attach_args
*pa
= aux
;
126 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ALI
&&
127 (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_ALI_M7101
))
133 alipm_attach(device_t parent
, device_t self
, void *aux
)
135 struct alipm_softc
*sc
= device_private(self
);
136 struct pci_attach_args
*pa
= aux
;
137 struct i2cbus_attach_args iba
;
138 pcireg_t iobase
, reg
;
139 bus_size_t iosize
= ALIPM_SMB_SIZE
;
141 /* Old chips don't have the PCI 2.2 Capabilities List. */
142 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
);
143 if ((reg
& PCI_STATUS_CAPLIST_SUPPORT
) == 0) {
145 iobase
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, ALIPM_BASE
);
146 sc
->sc_iot
= pa
->pa_iot
;
148 bus_space_map(sc
->sc_iot
, iobase
>> 16,
149 iosize
, 0, &sc
->sc_ioh
)) {
150 aprint_error_dev(&sc
->sc_dev
, "can't map I/O space\n");
154 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, ALIPM_CONF
);
155 if ((reg
& ALIPM_CONF_SMBEN
) == 0) {
156 aprint_error_dev(&sc
->sc_dev
, "SMBus disabled\n");
160 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, ALIPM_SMB_HOSTC
);
161 if ((reg
& ALIPM_SMB_HOSTC_HSTEN
) == 0) {
162 aprint_error_dev(&sc
->sc_dev
, "SMBus host disabled\n");
167 if (pci_mapreg_map(pa
, ALIPM_SMB_BASE
, PCI_MAPREG_TYPE_IO
, 0,
168 &sc
->sc_iot
, &sc
->sc_ioh
, NULL
, &iosize
)) {
169 aprint_error_dev(&sc
->sc_dev
, "can't map I/O space\n");
173 reg
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, ALIPM_SMB_HOSTX
);
174 if ((reg
& ALIPM_SMB_HOSTC_HSTEN
) == 0) {
175 aprint_error_dev(&sc
->sc_dev
, "SMBus host disabled\n");
180 switch (reg
& ALIPM_SMB_HOSTC_CLOCK
) {
181 case ALIPM_SMB_HOSTC_149K
:
182 aprint_normal(": 149KHz clock\n");
184 case ALIPM_SMB_HOSTC_74K
:
185 aprint_normal(": 74KHz clock\n");
187 case ALIPM_SMB_HOSTC_37K
:
188 aprint_normal(": 37KHz clock\n");
190 case ALIPM_SMB_HOSTC_223K
:
191 aprint_normal(": 223KHz clock\n");
193 case ALIPM_SMB_HOSTC_111K
:
194 aprint_normal(": 111KHz clock\n");
196 case ALIPM_SMB_HOSTC_55K
:
197 aprint_normal(": 55KHz clock\n");
200 aprint_normal(" unknown clock speed\n");
205 rw_init(&sc
->sc_smb_lock
);
206 sc
->sc_smb_tag
.ic_cookie
= sc
;
207 sc
->sc_smb_tag
.ic_acquire_bus
= alipm_smb_acquire_bus
;
208 sc
->sc_smb_tag
.ic_release_bus
= alipm_smb_release_bus
;
209 sc
->sc_smb_tag
.ic_exec
= alipm_smb_exec
;
211 memset(&iba
, 0, sizeof iba
);
212 iba
.iba_tag
= &sc
->sc_smb_tag
;
213 (void)config_found_ia(&sc
->sc_dev
, "i2cbus", &iba
, iicbus_print
);
218 bus_space_unmap(sc
->sc_iot
, sc
->sc_ioh
, iosize
);
222 alipm_smb_acquire_bus(void *cookie
, int flags
)
224 struct alipm_softc
*sc
= cookie
;
226 if (flags
& I2C_F_POLL
)
229 rw_enter(&sc
->sc_smb_lock
, RW_WRITER
);
234 alipm_smb_release_bus(void *cookie
, int flags
)
236 struct alipm_softc
*sc
= cookie
;
238 if (flags
& I2C_F_POLL
)
241 rw_exit(&sc
->sc_smb_lock
);
245 alipm_smb_exec(void *cookie
, i2c_op_t op
, i2c_addr_t addr
,
246 const void *cmdbuf
, size_t cmdlen
, void *buf
, size_t len
, int flags
)
248 struct alipm_softc
*sc
= cookie
;
251 int retries
, error
= 0;
253 DPRINTF(("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
254 "flags 0x%x\n", device_xname(&sc
->sc_dev
), op
, addr
, cmdlen
,
257 if (!I2C_OP_STOP_P(op
) || cmdlen
> 1 || len
> 2)
260 /* Clear status bits */
261 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
,
262 ALIPM_SMB_HS_DONE
| ALIPM_SMB_HS_FAILED
|
263 ALIPM_SMB_HS_BUSERR
| ALIPM_SMB_HS_DEVERR
);
264 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, 1,
265 BUS_SPACE_BARRIER_READ
| BUS_SPACE_BARRIER_WRITE
);
267 /* Wait until bus is idle */
268 for (retries
= 1000; retries
> 0; retries
--) {
269 st
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
);
270 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, 1,
271 BUS_SPACE_BARRIER_READ
);
272 if (st
& (ALIPM_SMB_HS_IDLE
| ALIPM_SMB_HS_FAILED
|
273 ALIPM_SMB_HS_BUSERR
| ALIPM_SMB_HS_DEVERR
))
278 aprint_error_dev(&sc
->sc_dev
, "timeout st 0x%x\n", st
);
281 if (st
& (ALIPM_SMB_HS_FAILED
|
282 ALIPM_SMB_HS_BUSERR
| ALIPM_SMB_HS_DEVERR
)) {
283 aprint_error_dev(&sc
->sc_dev
, "error st 0x%x\n", st
);
287 /* Set slave address and transfer direction. */
288 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_TXSLVA
,
289 ALIPM_SMB_TXSLVA_ADDR(addr
) |
290 (I2C_OP_READ_P(op
) ? ALIPM_SMB_TXSLVA_READ
: 0));
293 /* Set command byte */
294 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
295 ALIPM_SMB_HCMD
, ((const u_int8_t
*)cmdbuf
)[0]);
297 if (I2C_OP_WRITE_P(op
)) {
301 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
302 ALIPM_SMB_HD0
, b
[0]);
304 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
,
305 ALIPM_SMB_HD1
, b
[1]);
308 /* Set SMBus command */
311 ctl
= ALIPM_SMB_HC_CMD_QUICK
;
313 ctl
= ALIPM_SMB_HC_CMD_BYTE
;
315 ctl
= ALIPM_SMB_HC_CMD_BDATA
;
317 ctl
= ALIPM_SMB_HC_CMD_WDATA
;
318 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HC
, ctl
);
320 /* Start transaction */
321 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, 0, ALIPM_SMB_SIZE
,
322 BUS_SPACE_BARRIER_WRITE
);
323 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_START
, 0xff);
324 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, 0, ALIPM_SMB_SIZE
,
325 BUS_SPACE_BARRIER_READ
| BUS_SPACE_BARRIER_WRITE
);
327 /* Poll for completion */
329 for (retries
= 1000; retries
> 0; retries
--) {
330 st
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
);
331 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, 1,
332 BUS_SPACE_BARRIER_READ
);
333 if (st
& (ALIPM_SMB_HS_IDLE
| ALIPM_SMB_HS_FAILED
|
334 ALIPM_SMB_HS_BUSERR
| ALIPM_SMB_HS_DEVERR
))
339 aprint_error_dev(&sc
->sc_dev
, "timeout st 0x%x, resetting\n",st
);
340 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HC
,
342 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, 0, ALIPM_SMB_SIZE
,
343 BUS_SPACE_BARRIER_READ
| BUS_SPACE_BARRIER_WRITE
);
344 st
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
);
345 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, 1,
346 BUS_SPACE_BARRIER_READ
);
351 if ((st
& ALIPM_SMB_HS_DONE
) == 0) {
352 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HC
,
354 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, 0, ALIPM_SMB_SIZE
,
355 BUS_SPACE_BARRIER_READ
| BUS_SPACE_BARRIER_WRITE
);
356 st
= bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
);
357 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, 1,
358 BUS_SPACE_BARRIER_READ
);
359 if ((st
& ALIPM_SMB_HS_FAILED
) == 0)
360 aprint_error_dev(&sc
->sc_dev
, "error st 0x%x\n", st
);
363 /* Check for errors */
364 if (st
& (ALIPM_SMB_HS_FAILED
|
365 ALIPM_SMB_HS_BUSERR
| ALIPM_SMB_HS_DEVERR
)) {
370 if (I2C_OP_READ_P(op
)) {
374 b
[0] = bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
,
376 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
,
377 ALIPM_SMB_HD0
, 1, BUS_SPACE_BARRIER_READ
);
380 b
[1] = bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
,
382 bus_space_barrier(sc
->sc_iot
, sc
->sc_ioh
,
383 ALIPM_SMB_HD1
, 1, BUS_SPACE_BARRIER_READ
);
388 /* Clear status bits */
389 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ALIPM_SMB_HS
, st
);