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