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