1f495ec29SRui Paulo /*-
2f495ec29SRui Paulo * Copyright (c) 1998, 1999, 2001 Nicolas Souchu
3f495ec29SRui Paulo * All rights reserved.
4f495ec29SRui Paulo *
5f495ec29SRui Paulo * Redistribution and use in source and binary forms, with or without
6f495ec29SRui Paulo * modification, are permitted provided that the following conditions
7f495ec29SRui Paulo * are met:
8f495ec29SRui Paulo * 1. Redistributions of source code must retain the above copyright
9f495ec29SRui Paulo * notice, this list of conditions and the following disclaimer.
10f495ec29SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright
11f495ec29SRui Paulo * notice, this list of conditions and the following disclaimer in the
12f495ec29SRui Paulo * documentation and/or other materials provided with the distribution.
13f495ec29SRui Paulo *
14f495ec29SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15f495ec29SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16f495ec29SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17f495ec29SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18f495ec29SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19f495ec29SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20f495ec29SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21f495ec29SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22f495ec29SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23f495ec29SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24f495ec29SRui Paulo * SUCH DAMAGE.
25f495ec29SRui Paulo */
26f495ec29SRui Paulo
27f495ec29SRui Paulo /*
28f495ec29SRui Paulo * Power Management support for the Acer M15x3 chipsets
29f495ec29SRui Paulo */
30f495ec29SRui Paulo
31f495ec29SRui Paulo #include <sys/param.h>
32f495ec29SRui Paulo #include <sys/bus.h>
33f495ec29SRui Paulo #include <sys/kernel.h>
34f495ec29SRui Paulo #include <sys/lock.h>
35f495ec29SRui Paulo #include <sys/module.h>
36f495ec29SRui Paulo #include <sys/mutex.h>
37f495ec29SRui Paulo #include <sys/systm.h>
38f495ec29SRui Paulo
39f495ec29SRui Paulo #include <machine/bus.h>
40f495ec29SRui Paulo #include <machine/resource.h>
41f495ec29SRui Paulo #include <sys/rman.h>
42f495ec29SRui Paulo
43f495ec29SRui Paulo #include <dev/pci/pcivar.h>
44f495ec29SRui Paulo #include <dev/pci/pcireg.h>
45f495ec29SRui Paulo
46f495ec29SRui Paulo #include <dev/smbus/smbconf.h>
47f495ec29SRui Paulo #include "smbus_if.h"
48f495ec29SRui Paulo
49f495ec29SRui Paulo #define ALPM_DEBUG(x) if (alpm_debug) (x)
50f495ec29SRui Paulo
51f495ec29SRui Paulo #ifdef DEBUG
52f495ec29SRui Paulo static int alpm_debug = 1;
53f495ec29SRui Paulo #else
54f495ec29SRui Paulo static int alpm_debug = 0;
55f495ec29SRui Paulo #endif
56f495ec29SRui Paulo
57f495ec29SRui Paulo #define ACER_M1543_PMU_ID 0x710110b9
58f495ec29SRui Paulo
59f495ec29SRui Paulo /*
60f495ec29SRui Paulo * I/O registers offsets - the base address is programmed via the
61f495ec29SRui Paulo * SMBBA PCI configuration register
62f495ec29SRui Paulo */
63f495ec29SRui Paulo #define SMBSTS 0x0 /* SMBus host/slave status register */
64f495ec29SRui Paulo #define SMBCMD 0x1 /* SMBus host/slave command register */
65f495ec29SRui Paulo #define SMBSTART 0x2 /* start to generate programmed cycle */
66f495ec29SRui Paulo #define SMBHADDR 0x3 /* host address register */
67f495ec29SRui Paulo #define SMBHDATA 0x4 /* data A register for host controller */
68f495ec29SRui Paulo #define SMBHDATB 0x5 /* data B register for host controller */
69f495ec29SRui Paulo #define SMBHBLOCK 0x6 /* block register for host controller */
70f495ec29SRui Paulo #define SMBHCMD 0x7 /* command register for host controller */
71f495ec29SRui Paulo
72f495ec29SRui Paulo /* SMBHADDR mask. */
73f495ec29SRui Paulo #define LSB 0x1 /* XXX: Better name: Read/Write? */
74f495ec29SRui Paulo
75f495ec29SRui Paulo /* SMBSTS masks */
76f495ec29SRui Paulo #define TERMINATE 0x80
77f495ec29SRui Paulo #define BUS_COLLI 0x40
78f495ec29SRui Paulo #define DEVICE_ERR 0x20
79f495ec29SRui Paulo #define SMI_I_STS 0x10
80f495ec29SRui Paulo #define HST_BSY 0x08
81f495ec29SRui Paulo #define IDL_STS 0x04
82f495ec29SRui Paulo #define HSTSLV_STS 0x02
83f495ec29SRui Paulo #define HSTSLV_BSY 0x01
84f495ec29SRui Paulo
85f495ec29SRui Paulo /* SMBCMD masks */
86f495ec29SRui Paulo #define SMB_BLK_CLR 0x80
87f495ec29SRui Paulo #define T_OUT_CMD 0x08
88f495ec29SRui Paulo #define ABORT_HOST 0x04
89f495ec29SRui Paulo
90f495ec29SRui Paulo /* SMBus commands */
91f495ec29SRui Paulo #define SMBQUICK 0x00
92f495ec29SRui Paulo #define SMBSRBYTE 0x10 /* send/receive byte */
93f495ec29SRui Paulo #define SMBWRBYTE 0x20 /* write/read byte */
94f495ec29SRui Paulo #define SMBWRWORD 0x30 /* write/read word */
95f495ec29SRui Paulo #define SMBWRBLOCK 0x40 /* write/read block */
96f495ec29SRui Paulo
97f495ec29SRui Paulo /* PCI configuration registers and masks
98f495ec29SRui Paulo */
99f495ec29SRui Paulo #define COM 0x4
100f495ec29SRui Paulo #define COM_ENABLE_IO 0x1
101f495ec29SRui Paulo
102f495ec29SRui Paulo #define SMBBA PCIR_BAR(1)
103f495ec29SRui Paulo
104f495ec29SRui Paulo #define ATPC 0x5b
105f495ec29SRui Paulo #define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */
106f495ec29SRui Paulo
107f495ec29SRui Paulo #define SMBHSI 0xe0
108f495ec29SRui Paulo #define SMBHSI_SLAVE 0x2
109f495ec29SRui Paulo #define SMBHSI_HOST 0x1
110f495ec29SRui Paulo
111f495ec29SRui Paulo #define SMBHCBC 0xe2
112f495ec29SRui Paulo #define SMBHCBC_CLOCK 0x70
113f495ec29SRui Paulo
114f495ec29SRui Paulo #define SMBCLOCK_149K 0x0
115f495ec29SRui Paulo #define SMBCLOCK_74K 0x20
116f495ec29SRui Paulo #define SMBCLOCK_37K 0x40
117f495ec29SRui Paulo #define SMBCLOCK_223K 0x80
118f495ec29SRui Paulo #define SMBCLOCK_111K 0xa0
119f495ec29SRui Paulo #define SMBCLOCK_55K 0xc0
120f495ec29SRui Paulo
121f495ec29SRui Paulo struct alpm_softc {
122f495ec29SRui Paulo int base;
123f495ec29SRui Paulo struct resource *res;
124f495ec29SRui Paulo bus_space_tag_t smbst;
125f495ec29SRui Paulo bus_space_handle_t smbsh;
126f495ec29SRui Paulo device_t smbus;
127f495ec29SRui Paulo struct mtx lock;
128f495ec29SRui Paulo };
129f495ec29SRui Paulo
130f495ec29SRui Paulo #define ALPM_LOCK(alpm) mtx_lock(&(alpm)->lock)
131f495ec29SRui Paulo #define ALPM_UNLOCK(alpm) mtx_unlock(&(alpm)->lock)
132f495ec29SRui Paulo #define ALPM_LOCK_ASSERT(alpm) mtx_assert(&(alpm)->lock, MA_OWNED)
133f495ec29SRui Paulo
134f495ec29SRui Paulo #define ALPM_SMBINB(alpm,register) \
135f495ec29SRui Paulo (bus_space_read_1(alpm->smbst, alpm->smbsh, register))
136f495ec29SRui Paulo #define ALPM_SMBOUTB(alpm,register,value) \
137f495ec29SRui Paulo (bus_space_write_1(alpm->smbst, alpm->smbsh, register, value))
138f495ec29SRui Paulo
139f495ec29SRui Paulo static int alpm_detach(device_t dev);
140f495ec29SRui Paulo
141f495ec29SRui Paulo static int
alpm_probe(device_t dev)142f495ec29SRui Paulo alpm_probe(device_t dev)
143f495ec29SRui Paulo {
144f495ec29SRui Paulo
145f495ec29SRui Paulo if (pci_get_devid(dev) == ACER_M1543_PMU_ID) {
146f495ec29SRui Paulo device_set_desc(dev, "AcerLabs M15x3 Power Management Unit");
147f495ec29SRui Paulo
148f495ec29SRui Paulo return (BUS_PROBE_DEFAULT);
149f495ec29SRui Paulo }
150f495ec29SRui Paulo
151f495ec29SRui Paulo return (ENXIO);
152f495ec29SRui Paulo }
153f495ec29SRui Paulo
154f495ec29SRui Paulo static int
alpm_attach(device_t dev)155f495ec29SRui Paulo alpm_attach(device_t dev)
156f495ec29SRui Paulo {
157f495ec29SRui Paulo int rid;
158f495ec29SRui Paulo u_int32_t l;
159f495ec29SRui Paulo struct alpm_softc *alpm;
160f495ec29SRui Paulo
161f495ec29SRui Paulo alpm = device_get_softc(dev);
162f495ec29SRui Paulo
163f495ec29SRui Paulo /* Unlock SMBIO base register access */
164f495ec29SRui Paulo l = pci_read_config(dev, ATPC, 1);
165f495ec29SRui Paulo pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1);
166f495ec29SRui Paulo
167f495ec29SRui Paulo /*
168f495ec29SRui Paulo * XX linux sets clock to 74k, should we?
169f495ec29SRui Paulo l = pci_read_config(dev, SMBHCBC, 1);
170f495ec29SRui Paulo l &= 0x1f;
171f495ec29SRui Paulo l |= SMBCLOCK_74K;
172f495ec29SRui Paulo pci_write_config(dev, SMBHCBC, l, 1);
173f495ec29SRui Paulo */
174f495ec29SRui Paulo
175f495ec29SRui Paulo if (bootverbose || alpm_debug) {
176f495ec29SRui Paulo l = pci_read_config(dev, SMBHSI, 1);
177f495ec29SRui Paulo device_printf(dev, "%s/%s",
178f495ec29SRui Paulo (l & SMBHSI_HOST) ? "host":"nohost",
179f495ec29SRui Paulo (l & SMBHSI_SLAVE) ? "slave":"noslave");
180f495ec29SRui Paulo
181f495ec29SRui Paulo l = pci_read_config(dev, SMBHCBC, 1);
182f495ec29SRui Paulo switch (l & SMBHCBC_CLOCK) {
183f495ec29SRui Paulo case SMBCLOCK_149K:
184f495ec29SRui Paulo printf(" 149K");
185f495ec29SRui Paulo break;
186f495ec29SRui Paulo case SMBCLOCK_74K:
187f495ec29SRui Paulo printf(" 74K");
188f495ec29SRui Paulo break;
189f495ec29SRui Paulo case SMBCLOCK_37K:
190f495ec29SRui Paulo printf(" 37K");
191f495ec29SRui Paulo break;
192f495ec29SRui Paulo case SMBCLOCK_223K:
193f495ec29SRui Paulo printf(" 223K");
194f495ec29SRui Paulo break;
195f495ec29SRui Paulo case SMBCLOCK_111K:
196f495ec29SRui Paulo printf(" 111K");
197f495ec29SRui Paulo break;
198f495ec29SRui Paulo case SMBCLOCK_55K:
199f495ec29SRui Paulo printf(" 55K");
200f495ec29SRui Paulo break;
201f495ec29SRui Paulo default:
202453130d9SPedro F. Giffuni printf("unknown");
203f495ec29SRui Paulo break;
204f495ec29SRui Paulo }
205f495ec29SRui Paulo printf("\n");
206f495ec29SRui Paulo }
207f495ec29SRui Paulo
208f495ec29SRui Paulo rid = SMBBA;
209f495ec29SRui Paulo alpm->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
210f495ec29SRui Paulo RF_ACTIVE);
211f495ec29SRui Paulo
212f495ec29SRui Paulo if (alpm->res == NULL) {
213f495ec29SRui Paulo device_printf(dev,"Could not allocate Bus space\n");
214f495ec29SRui Paulo return (ENXIO);
215f495ec29SRui Paulo }
216f495ec29SRui Paulo alpm->smbst = rman_get_bustag(alpm->res);
217f495ec29SRui Paulo alpm->smbsh = rman_get_bushandle(alpm->res);
218f495ec29SRui Paulo mtx_init(&alpm->lock, device_get_nameunit(dev), "alpm", MTX_DEF);
219f495ec29SRui Paulo
220f495ec29SRui Paulo /* attach the smbus */
2215b56413dSWarner Losh alpm->smbus = device_add_child(dev, "smbus", DEVICE_UNIT_ANY);
222f495ec29SRui Paulo if (alpm->smbus == NULL) {
223f495ec29SRui Paulo alpm_detach(dev);
224f495ec29SRui Paulo return (EINVAL);
225f495ec29SRui Paulo }
22618250ec6SJohn Baldwin bus_attach_children(dev);
227f495ec29SRui Paulo
228f495ec29SRui Paulo return (0);
229f495ec29SRui Paulo }
230f495ec29SRui Paulo
231f495ec29SRui Paulo static int
alpm_detach(device_t dev)232f495ec29SRui Paulo alpm_detach(device_t dev)
233f495ec29SRui Paulo {
234f495ec29SRui Paulo struct alpm_softc *alpm = device_get_softc(dev);
235*11a91178SJohn Baldwin int error;
236f495ec29SRui Paulo
237*11a91178SJohn Baldwin error = bus_generic_detach(dev);
238*11a91178SJohn Baldwin if (error != 0)
239*11a91178SJohn Baldwin return (error);
240*11a91178SJohn Baldwin
241f495ec29SRui Paulo mtx_destroy(&alpm->lock);
242f495ec29SRui Paulo
243f495ec29SRui Paulo if (alpm->res)
244f495ec29SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res);
245f495ec29SRui Paulo
246f495ec29SRui Paulo return (0);
247f495ec29SRui Paulo }
248f495ec29SRui Paulo
249f495ec29SRui Paulo static int
alpm_callback(device_t dev,int index,void * data)250f495ec29SRui Paulo alpm_callback(device_t dev, int index, void *data)
251f495ec29SRui Paulo {
252f495ec29SRui Paulo int error = 0;
253f495ec29SRui Paulo
254f495ec29SRui Paulo switch (index) {
255f495ec29SRui Paulo case SMB_REQUEST_BUS:
256f495ec29SRui Paulo case SMB_RELEASE_BUS:
257f495ec29SRui Paulo /* ok, bus allocation accepted */
258f495ec29SRui Paulo break;
259f495ec29SRui Paulo default:
260f495ec29SRui Paulo error = EINVAL;
261f495ec29SRui Paulo }
262f495ec29SRui Paulo
263f495ec29SRui Paulo return (error);
264f495ec29SRui Paulo }
265f495ec29SRui Paulo
266f495ec29SRui Paulo static int
alpm_clear(struct alpm_softc * sc)267f495ec29SRui Paulo alpm_clear(struct alpm_softc *sc)
268f495ec29SRui Paulo {
269f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTS, 0xff);
270f495ec29SRui Paulo DELAY(10);
271f495ec29SRui Paulo
272f495ec29SRui Paulo return (0);
273f495ec29SRui Paulo }
274f495ec29SRui Paulo
275f495ec29SRui Paulo #if 0
276f495ec29SRui Paulo static int
277f495ec29SRui Paulo alpm_abort(struct alpm_softc *sc)
278f495ec29SRui Paulo {
279f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST);
280f495ec29SRui Paulo
281f495ec29SRui Paulo return (0);
282f495ec29SRui Paulo }
283f495ec29SRui Paulo #endif
284f495ec29SRui Paulo
285f495ec29SRui Paulo static int
alpm_idle(struct alpm_softc * sc)286f495ec29SRui Paulo alpm_idle(struct alpm_softc *sc)
287f495ec29SRui Paulo {
288f495ec29SRui Paulo u_char sts;
289f495ec29SRui Paulo
290f495ec29SRui Paulo sts = ALPM_SMBINB(sc, SMBSTS);
291f495ec29SRui Paulo
292f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts));
293f495ec29SRui Paulo
294f495ec29SRui Paulo return (sts & IDL_STS);
295f495ec29SRui Paulo }
296f495ec29SRui Paulo
297f495ec29SRui Paulo /*
298f495ec29SRui Paulo * Poll the SMBus controller
299f495ec29SRui Paulo */
300f495ec29SRui Paulo static int
alpm_wait(struct alpm_softc * sc)301f495ec29SRui Paulo alpm_wait(struct alpm_softc *sc)
302f495ec29SRui Paulo {
303f495ec29SRui Paulo int count = 10000;
304f495ec29SRui Paulo u_char sts = 0;
305f495ec29SRui Paulo int error;
306f495ec29SRui Paulo
307f495ec29SRui Paulo /* wait for command to complete and SMBus controller is idle */
308f495ec29SRui Paulo while (count--) {
309f495ec29SRui Paulo DELAY(10);
310f495ec29SRui Paulo sts = ALPM_SMBINB(sc, SMBSTS);
311f495ec29SRui Paulo if (sts & SMI_I_STS)
312f495ec29SRui Paulo break;
313f495ec29SRui Paulo }
314f495ec29SRui Paulo
315f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts));
316f495ec29SRui Paulo
317f495ec29SRui Paulo error = SMB_ENOERR;
318f495ec29SRui Paulo
319f495ec29SRui Paulo if (!count)
320f495ec29SRui Paulo error |= SMB_ETIMEOUT;
321f495ec29SRui Paulo
322f495ec29SRui Paulo if (sts & TERMINATE)
323f495ec29SRui Paulo error |= SMB_EABORT;
324f495ec29SRui Paulo
325f495ec29SRui Paulo if (sts & BUS_COLLI)
326f495ec29SRui Paulo error |= SMB_ENOACK;
327f495ec29SRui Paulo
328f495ec29SRui Paulo if (sts & DEVICE_ERR)
329f495ec29SRui Paulo error |= SMB_EBUSERR;
330f495ec29SRui Paulo
331f495ec29SRui Paulo if (error != SMB_ENOERR)
332f495ec29SRui Paulo alpm_clear(sc);
333f495ec29SRui Paulo
334f495ec29SRui Paulo return (error);
335f495ec29SRui Paulo }
336f495ec29SRui Paulo
337f495ec29SRui Paulo static int
alpm_quick(device_t dev,u_char slave,int how)338f495ec29SRui Paulo alpm_quick(device_t dev, u_char slave, int how)
339f495ec29SRui Paulo {
340f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
341f495ec29SRui Paulo int error;
342f495ec29SRui Paulo
343f495ec29SRui Paulo ALPM_LOCK(sc);
344f495ec29SRui Paulo alpm_clear(sc);
345f495ec29SRui Paulo if (!alpm_idle(sc)) {
346f495ec29SRui Paulo ALPM_UNLOCK(sc);
347f495ec29SRui Paulo return (EBUSY);
348f495ec29SRui Paulo }
349f495ec29SRui Paulo
350f495ec29SRui Paulo switch (how) {
351f495ec29SRui Paulo case SMB_QWRITE:
352f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave));
353f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
354f495ec29SRui Paulo break;
355f495ec29SRui Paulo case SMB_QREAD:
356f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave));
357f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
358f495ec29SRui Paulo break;
359f495ec29SRui Paulo default:
360f495ec29SRui Paulo panic("%s: unknown QUICK command (%x)!", __func__,
361f495ec29SRui Paulo how);
362f495ec29SRui Paulo }
363f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK);
364f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
365f495ec29SRui Paulo
366f495ec29SRui Paulo error = alpm_wait(sc);
367f495ec29SRui Paulo
368f495ec29SRui Paulo ALPM_DEBUG(printf(", error=0x%x\n", error));
369f495ec29SRui Paulo ALPM_UNLOCK(sc);
370f495ec29SRui Paulo
371f495ec29SRui Paulo return (error);
372f495ec29SRui Paulo }
373f495ec29SRui Paulo
374f495ec29SRui Paulo static int
alpm_sendb(device_t dev,u_char slave,char byte)375f495ec29SRui Paulo alpm_sendb(device_t dev, u_char slave, char byte)
376f495ec29SRui Paulo {
377f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
378f495ec29SRui Paulo int error;
379f495ec29SRui Paulo
380f495ec29SRui Paulo ALPM_LOCK(sc);
381f495ec29SRui Paulo alpm_clear(sc);
382f495ec29SRui Paulo if (!alpm_idle(sc)) {
383f495ec29SRui Paulo ALPM_UNLOCK(sc);
384f495ec29SRui Paulo return (SMB_EBUSY);
385f495ec29SRui Paulo }
386f495ec29SRui Paulo
387f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
388f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
389f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHDATA, byte);
390f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
391f495ec29SRui Paulo
392f495ec29SRui Paulo error = alpm_wait(sc);
393f495ec29SRui Paulo
394f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
395f495ec29SRui Paulo ALPM_UNLOCK(sc);
396f495ec29SRui Paulo
397f495ec29SRui Paulo return (error);
398f495ec29SRui Paulo }
399f495ec29SRui Paulo
400f495ec29SRui Paulo static int
alpm_recvb(device_t dev,u_char slave,char * byte)401f495ec29SRui Paulo alpm_recvb(device_t dev, u_char slave, char *byte)
402f495ec29SRui Paulo {
403f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
404f495ec29SRui Paulo int error;
405f495ec29SRui Paulo
406f495ec29SRui Paulo ALPM_LOCK(sc);
407f495ec29SRui Paulo alpm_clear(sc);
408f495ec29SRui Paulo if (!alpm_idle(sc)) {
409f495ec29SRui Paulo ALPM_UNLOCK(sc);
410f495ec29SRui Paulo return (SMB_EBUSY);
411f495ec29SRui Paulo }
412f495ec29SRui Paulo
413f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
414f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
415f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
416f495ec29SRui Paulo
417f495ec29SRui Paulo if ((error = alpm_wait(sc)) == SMB_ENOERR)
418f495ec29SRui Paulo *byte = ALPM_SMBINB(sc, SMBHDATA);
419f495ec29SRui Paulo
420f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
421f495ec29SRui Paulo ALPM_UNLOCK(sc);
422f495ec29SRui Paulo
423f495ec29SRui Paulo return (error);
424f495ec29SRui Paulo }
425f495ec29SRui Paulo
426f495ec29SRui Paulo static int
alpm_writeb(device_t dev,u_char slave,char cmd,char byte)427f495ec29SRui Paulo alpm_writeb(device_t dev, u_char slave, char cmd, char byte)
428f495ec29SRui Paulo {
429f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
430f495ec29SRui Paulo int error;
431f495ec29SRui Paulo
432f495ec29SRui Paulo ALPM_LOCK(sc);
433f495ec29SRui Paulo alpm_clear(sc);
434f495ec29SRui Paulo if (!alpm_idle(sc)) {
435f495ec29SRui Paulo ALPM_UNLOCK(sc);
436f495ec29SRui Paulo return (SMB_EBUSY);
437f495ec29SRui Paulo }
438f495ec29SRui Paulo
439f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
440f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
441f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHDATA, byte);
442f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
443f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
444f495ec29SRui Paulo
445f495ec29SRui Paulo error = alpm_wait(sc);
446f495ec29SRui Paulo
447f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
448f495ec29SRui Paulo ALPM_UNLOCK(sc);
449f495ec29SRui Paulo
450f495ec29SRui Paulo return (error);
451f495ec29SRui Paulo }
452f495ec29SRui Paulo
453f495ec29SRui Paulo static int
alpm_readb(device_t dev,u_char slave,char cmd,char * byte)454f495ec29SRui Paulo alpm_readb(device_t dev, u_char slave, char cmd, char *byte)
455f495ec29SRui Paulo {
456f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
457f495ec29SRui Paulo int error;
458f495ec29SRui Paulo
459f495ec29SRui Paulo ALPM_LOCK(sc);
460f495ec29SRui Paulo alpm_clear(sc);
461f495ec29SRui Paulo if (!alpm_idle(sc)) {
462f495ec29SRui Paulo ALPM_UNLOCK(sc);
463f495ec29SRui Paulo return (SMB_EBUSY);
464f495ec29SRui Paulo }
465f495ec29SRui Paulo
466f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
467f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
468f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
469f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
470f495ec29SRui Paulo
471f495ec29SRui Paulo if ((error = alpm_wait(sc)) == SMB_ENOERR)
472f495ec29SRui Paulo *byte = ALPM_SMBINB(sc, SMBHDATA);
473f495ec29SRui Paulo
474f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
475f495ec29SRui Paulo ALPM_UNLOCK(sc);
476f495ec29SRui Paulo
477f495ec29SRui Paulo return (error);
478f495ec29SRui Paulo }
479f495ec29SRui Paulo
480f495ec29SRui Paulo static int
alpm_writew(device_t dev,u_char slave,char cmd,short word)481f495ec29SRui Paulo alpm_writew(device_t dev, u_char slave, char cmd, short word)
482f495ec29SRui Paulo {
483f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
484f495ec29SRui Paulo int error;
485f495ec29SRui Paulo
486f495ec29SRui Paulo ALPM_LOCK(sc);
487f495ec29SRui Paulo alpm_clear(sc);
488f495ec29SRui Paulo if (!alpm_idle(sc)) {
489f495ec29SRui Paulo ALPM_UNLOCK(sc);
490f495ec29SRui Paulo return (SMB_EBUSY);
491f495ec29SRui Paulo }
492f495ec29SRui Paulo
493f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
494f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
495f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff);
496f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8);
497f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
498f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
499f495ec29SRui Paulo
500f495ec29SRui Paulo error = alpm_wait(sc);
501f495ec29SRui Paulo
502f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
503f495ec29SRui Paulo ALPM_UNLOCK(sc);
504f495ec29SRui Paulo
505f495ec29SRui Paulo return (error);
506f495ec29SRui Paulo }
507f495ec29SRui Paulo
508f495ec29SRui Paulo static int
alpm_readw(device_t dev,u_char slave,char cmd,short * word)509f495ec29SRui Paulo alpm_readw(device_t dev, u_char slave, char cmd, short *word)
510f495ec29SRui Paulo {
511f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
512f495ec29SRui Paulo int error;
513f495ec29SRui Paulo u_char high, low;
514f495ec29SRui Paulo
515f495ec29SRui Paulo ALPM_LOCK(sc);
516f495ec29SRui Paulo alpm_clear(sc);
517f495ec29SRui Paulo if (!alpm_idle(sc)) {
518f495ec29SRui Paulo ALPM_UNLOCK(sc);
519f495ec29SRui Paulo return (SMB_EBUSY);
520f495ec29SRui Paulo }
521f495ec29SRui Paulo
522f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
523f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
524f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
525f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
526f495ec29SRui Paulo
527f495ec29SRui Paulo if ((error = alpm_wait(sc)) == SMB_ENOERR) {
528f495ec29SRui Paulo low = ALPM_SMBINB(sc, SMBHDATA);
529f495ec29SRui Paulo high = ALPM_SMBINB(sc, SMBHDATB);
530f495ec29SRui Paulo
531f495ec29SRui Paulo *word = ((high & 0xff) << 8) | (low & 0xff);
532f495ec29SRui Paulo }
533f495ec29SRui Paulo
534f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
535f495ec29SRui Paulo ALPM_UNLOCK(sc);
536f495ec29SRui Paulo
537f495ec29SRui Paulo return (error);
538f495ec29SRui Paulo }
539f495ec29SRui Paulo
540f495ec29SRui Paulo static int
alpm_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)541f495ec29SRui Paulo alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
542f495ec29SRui Paulo {
543f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
544f495ec29SRui Paulo u_char i;
545f495ec29SRui Paulo int error;
546f495ec29SRui Paulo
547f495ec29SRui Paulo if (count < 1 || count > 32)
548f495ec29SRui Paulo return (SMB_EINVAL);
549f495ec29SRui Paulo
550f495ec29SRui Paulo ALPM_LOCK(sc);
551f495ec29SRui Paulo alpm_clear(sc);
552f495ec29SRui Paulo if(!alpm_idle(sc)) {
553f495ec29SRui Paulo ALPM_UNLOCK(sc);
554f495ec29SRui Paulo return (SMB_EBUSY);
555f495ec29SRui Paulo }
556f495ec29SRui Paulo
557f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
558f495ec29SRui Paulo
559f495ec29SRui Paulo /* set the cmd and reset the
560f495ec29SRui Paulo * 32-byte long internal buffer */
561f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
562f495ec29SRui Paulo
563f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHDATA, count);
564f495ec29SRui Paulo
565f495ec29SRui Paulo /* fill the 32-byte internal buffer */
566f495ec29SRui Paulo for (i = 0; i < count; i++) {
567f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHBLOCK, buf[i]);
568f495ec29SRui Paulo DELAY(2);
569f495ec29SRui Paulo }
570f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
571f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
572f495ec29SRui Paulo
573f495ec29SRui Paulo error = alpm_wait(sc);
574f495ec29SRui Paulo
575f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
576f495ec29SRui Paulo ALPM_UNLOCK(sc);
577f495ec29SRui Paulo
578f495ec29SRui Paulo return (error);
579f495ec29SRui Paulo }
580f495ec29SRui Paulo
581f495ec29SRui Paulo static int
alpm_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)582f495ec29SRui Paulo alpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
583f495ec29SRui Paulo {
584f495ec29SRui Paulo struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
585f495ec29SRui Paulo u_char data, len, i;
586f495ec29SRui Paulo int error;
587f495ec29SRui Paulo
588f495ec29SRui Paulo if (*count < 1 || *count > 32)
589f495ec29SRui Paulo return (SMB_EINVAL);
590f495ec29SRui Paulo
591f495ec29SRui Paulo ALPM_LOCK(sc);
592f495ec29SRui Paulo alpm_clear(sc);
593f495ec29SRui Paulo if (!alpm_idle(sc)) {
594f495ec29SRui Paulo ALPM_UNLOCK(sc);
595f495ec29SRui Paulo return (SMB_EBUSY);
596f495ec29SRui Paulo }
597f495ec29SRui Paulo
598f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
599f495ec29SRui Paulo
600f495ec29SRui Paulo /* set the cmd and reset the
601f495ec29SRui Paulo * 32-byte long internal buffer */
602f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
603f495ec29SRui Paulo
604f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBHCMD, cmd);
605f495ec29SRui Paulo ALPM_SMBOUTB(sc, SMBSTART, 0xff);
606f495ec29SRui Paulo
607f495ec29SRui Paulo if ((error = alpm_wait(sc)) != SMB_ENOERR)
608f495ec29SRui Paulo goto error;
609f495ec29SRui Paulo
610f495ec29SRui Paulo len = ALPM_SMBINB(sc, SMBHDATA);
611f495ec29SRui Paulo
612f495ec29SRui Paulo /* read the 32-byte internal buffer */
613f495ec29SRui Paulo for (i = 0; i < len; i++) {
614f495ec29SRui Paulo data = ALPM_SMBINB(sc, SMBHBLOCK);
615f495ec29SRui Paulo if (i < *count)
616f495ec29SRui Paulo buf[i] = data;
617f495ec29SRui Paulo DELAY(2);
618f495ec29SRui Paulo }
619f495ec29SRui Paulo *count = len;
620f495ec29SRui Paulo
621f495ec29SRui Paulo error:
622f495ec29SRui Paulo ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
623f495ec29SRui Paulo ALPM_UNLOCK(sc);
624f495ec29SRui Paulo
625f495ec29SRui Paulo return (error);
626f495ec29SRui Paulo }
627f495ec29SRui Paulo
628f495ec29SRui Paulo static device_method_t alpm_methods[] = {
629f495ec29SRui Paulo /* device interface */
630f495ec29SRui Paulo DEVMETHOD(device_probe, alpm_probe),
631f495ec29SRui Paulo DEVMETHOD(device_attach, alpm_attach),
632f495ec29SRui Paulo DEVMETHOD(device_detach, alpm_detach),
633f495ec29SRui Paulo
634f495ec29SRui Paulo /* smbus interface */
635f495ec29SRui Paulo DEVMETHOD(smbus_callback, alpm_callback),
636f495ec29SRui Paulo DEVMETHOD(smbus_quick, alpm_quick),
637f495ec29SRui Paulo DEVMETHOD(smbus_sendb, alpm_sendb),
638f495ec29SRui Paulo DEVMETHOD(smbus_recvb, alpm_recvb),
639f495ec29SRui Paulo DEVMETHOD(smbus_writeb, alpm_writeb),
640f495ec29SRui Paulo DEVMETHOD(smbus_readb, alpm_readb),
641f495ec29SRui Paulo DEVMETHOD(smbus_writew, alpm_writew),
642f495ec29SRui Paulo DEVMETHOD(smbus_readw, alpm_readw),
643f495ec29SRui Paulo DEVMETHOD(smbus_bwrite, alpm_bwrite),
644f495ec29SRui Paulo DEVMETHOD(smbus_bread, alpm_bread),
645f495ec29SRui Paulo { 0, 0 }
646f495ec29SRui Paulo };
647f495ec29SRui Paulo
648f495ec29SRui Paulo static driver_t alpm_driver = {
649f495ec29SRui Paulo "alpm",
650f495ec29SRui Paulo alpm_methods,
651f495ec29SRui Paulo sizeof(struct alpm_softc)
652f495ec29SRui Paulo };
653f495ec29SRui Paulo
654f3498d7bSJohn Baldwin DRIVER_MODULE(alpm, pci, alpm_driver, 0, 0);
655c6d39765SJohn Baldwin DRIVER_MODULE(smbus, alpm, smbus_driver, 0, 0);
656f495ec29SRui Paulo MODULE_DEPEND(alpm, pci, 1, 1, 1);
657f495ec29SRui Paulo MODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
658f495ec29SRui Paulo MODULE_VERSION(alpm, 1);
659