alpm.c revision 113506
143973Snsouch/*- 270606Snsouch * Copyright (c) 1998, 1999, 2001 Nicolas Souchu 343973Snsouch * All rights reserved. 443973Snsouch * 543973Snsouch * Redistribution and use in source and binary forms, with or without 643973Snsouch * modification, are permitted provided that the following conditions 743973Snsouch * are met: 843973Snsouch * 1. Redistributions of source code must retain the above copyright 943973Snsouch * notice, this list of conditions and the following disclaimer. 1043973Snsouch * 2. Redistributions in binary form must reproduce the above copyright 1143973Snsouch * notice, this list of conditions and the following disclaimer in the 1243973Snsouch * documentation and/or other materials provided with the distribution. 1343973Snsouch * 1443973Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1543973Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1643973Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1743973Snsouch * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1843973Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1943973Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2043973Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2143973Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2243973Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2343973Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2443973Snsouch * SUCH DAMAGE. 2543973Snsouch * 2650477Speter * $FreeBSD: head/sys/pci/alpm.c 113506 2003-04-15 06:37:30Z mdodd $ 2743973Snsouch * 2843973Snsouch */ 2943973Snsouch 3043973Snsouch/* 3143973Snsouch * Power Management support for the Acer M15x3 chipsets 3243973Snsouch */ 3343973Snsouch#include <sys/param.h> 3443973Snsouch#include <sys/kernel.h> 3543973Snsouch#include <sys/systm.h> 3643973Snsouch#include <sys/module.h> 3743973Snsouch#include <sys/bus.h> 3843973Snsouch#include <sys/uio.h> 3943973Snsouch 4043973Snsouch#include <machine/bus_pio.h> 4143973Snsouch#include <machine/bus_memio.h> 4243973Snsouch#include <machine/bus.h> 4370606Snsouch#include <machine/resource.h> 4470606Snsouch#include <sys/rman.h> 4543973Snsouch 4643973Snsouch#include <pci/pcivar.h> 4743973Snsouch#include <pci/pcireg.h> 4843973Snsouch 4943973Snsouch#include <dev/iicbus/iiconf.h> 5043973Snsouch#include <dev/smbus/smbconf.h> 5143973Snsouch#include "smbus_if.h" 5243973Snsouch 5343973Snsouch#define ALPM_DEBUG(x) if (alpm_debug) (x) 5443973Snsouch 5543973Snsouch#ifdef DEBUG 5643973Snsouchstatic int alpm_debug = 1; 5743973Snsouch#else 5843973Snsouchstatic int alpm_debug = 0; 5943973Snsouch#endif 6043973Snsouch 6143973Snsouch#define ACER_M1543_PMU_ID 0x710110b9 6243973Snsouch 6343973Snsouch/* Uncomment this line to force another I/O base address for SMB */ 6443973Snsouch/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */ 6543973Snsouch 6643973Snsouch/* I/O registers offsets - the base address is programmed via the 6743973Snsouch * SMBBA PCI configuration register 6843973Snsouch */ 6943973Snsouch#define SMBSTS 0x0 /* SMBus host/slave status register */ 7043973Snsouch#define SMBCMD 0x1 /* SMBus host/slave command register */ 7143973Snsouch#define SMBSTART 0x2 /* start to generate programmed cycle */ 7243973Snsouch#define SMBHADDR 0x3 /* host address register */ 7343973Snsouch#define SMBHDATA 0x4 /* data A register for host controller */ 7443973Snsouch#define SMBHDATB 0x5 /* data B register for host controller */ 7543973Snsouch#define SMBHBLOCK 0x6 /* block register for host controller */ 7643973Snsouch#define SMBHCMD 0x7 /* command register for host controller */ 7743973Snsouch 7843973Snsouch/* SMBSTS masks */ 7943973Snsouch#define TERMINATE 0x80 8043973Snsouch#define BUS_COLLI 0x40 8143973Snsouch#define DEVICE_ERR 0x20 8243973Snsouch#define SMI_I_STS 0x10 8343973Snsouch#define HST_BSY 0x08 8443973Snsouch#define IDL_STS 0x04 8543973Snsouch#define HSTSLV_STS 0x02 8643973Snsouch#define HSTSLV_BSY 0x01 8743973Snsouch 8843973Snsouch/* SMBCMD masks */ 8943973Snsouch#define SMB_BLK_CLR 0x80 9043973Snsouch#define T_OUT_CMD 0x08 9143973Snsouch#define ABORT_HOST 0x04 9243973Snsouch 9343973Snsouch/* SMBus commands */ 9443973Snsouch#define SMBQUICK 0x00 9543973Snsouch#define SMBSRBYTE 0x10 /* send/receive byte */ 9643973Snsouch#define SMBWRBYTE 0x20 /* write/read byte */ 9743973Snsouch#define SMBWRWORD 0x30 /* write/read word */ 9843973Snsouch#define SMBWRBLOCK 0x40 /* write/read block */ 9943973Snsouch 10043973Snsouch/* PCI configuration registers and masks 10143973Snsouch */ 10243973Snsouch#define COM 0x4 10343973Snsouch#define COM_ENABLE_IO 0x1 10443973Snsouch 10543973Snsouch#define SMBBA 0x14 10643973Snsouch 10743973Snsouch#define ATPC 0x5b 10870606Snsouch#define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */ 10943973Snsouch 11043973Snsouch#define SMBHSI 0xe0 11143973Snsouch#define SMBHSI_SLAVE 0x2 11243973Snsouch#define SMBHSI_HOST 0x1 11343973Snsouch 11443973Snsouch#define SMBHCBC 0xe2 11543973Snsouch#define SMBHCBC_CLOCK 0x70 11643973Snsouch 11743973Snsouch#define SMBCLOCK_149K 0x0 11843973Snsouch#define SMBCLOCK_74K 0x20 11943973Snsouch#define SMBCLOCK_37K 0x40 12043973Snsouch#define SMBCLOCK_223K 0x80 12143973Snsouch#define SMBCLOCK_111K 0xa0 12243973Snsouch#define SMBCLOCK_55K 0xc0 12343973Snsouch 12493023Snsouchstruct alpm_softc { 12543973Snsouch int base; 12693023Snsouch struct resource *res; 12743973Snsouch bus_space_tag_t smbst; 12843973Snsouch bus_space_handle_t smbsh; 12943973Snsouch device_t smbus; 13043973Snsouch}; 13143973Snsouch 13293023Snsouch#define ALPM_SMBINB(alpm,register) \ 13393023Snsouch (bus_space_read_1(alpm->smbst, alpm->smbsh, register)) 13493023Snsouch#define ALPM_SMBOUTB(alpm,register,value) \ 13593023Snsouch (bus_space_write_1(alpm->smbst, alpm->smbsh, register, value)) 13643973Snsouch 13793023Snsouchstatic int 13893023Snsouchalpm_probe(device_t dev) 13993023Snsouch{ 14093023Snsouch#ifdef ALPM_SMBIO_BASE_ADDR 14193023Snsouch u_int32_t l; 14293023Snsouch#endif 14343973Snsouch 14493023Snsouch if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { 14593023Snsouch device_set_desc(dev, "AcerLabs M15x3 Power Management Unit"); 14643973Snsouch 14793023Snsouch#ifdef ALPM_SMBIO_BASE_ADDR 14893023Snsouch if (bootverbose || alpm_debug) 14993023Snsouch device_printf(dev, "forcing base I/O at 0x%x\n", 15093023Snsouch ALPM_SMBIO_BASE_ADDR); 15143973Snsouch 15293023Snsouch /* disable I/O */ 15393023Snsouch l = pci_read_config(dev, COM, 2); 15493023Snsouch pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2); 15543973Snsouch 15693023Snsouch /* set the I/O base address */ 15793023Snsouch pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); 15843973Snsouch 15993023Snsouch /* enable I/O */ 16093023Snsouch pci_write_config(dev, COM, l | COM_ENABLE_IO, 2); 16143973Snsouch 16293023Snsouch if (bus_set_resource(dev, SYS_RES_IOPORT, SMBBA, 16393023Snsouch ALPM_SMBIO_BASE_ADDR, 256)) { 16493023Snsouch device_printf(dev, "could not set bus resource\n"); 16593023Snsouch return (ENXIO); 16693023Snsouch } 16793023Snsouch#endif 16893023Snsouch return (0); 16993023Snsouch } 17043973Snsouch 17193023Snsouch return (ENXIO); 17243973Snsouch} 17343973Snsouch 17470606Snsouchstatic int 17593023Snsouchalpm_attach(device_t dev) 17643973Snsouch{ 17770606Snsouch int rid, unit; 17870606Snsouch u_int32_t l; 17993023Snsouch struct alpm_softc *alpm; 18043973Snsouch 18170606Snsouch alpm = device_get_softc(dev); 18270606Snsouch unit = device_get_unit(dev); 18343973Snsouch 18443973Snsouch /* Unlock SMBIO base register access */ 18570606Snsouch l = pci_read_config(dev, ATPC, 1); 18670606Snsouch pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1); 18743973Snsouch 18870606Snsouch /* 18970606Snsouch * XX linux sets clock to 74k, should we? 19070606Snsouch l = pci_read_config(dev, SMBHCBC, 1); 19170606Snsouch l &= 0x1f; 19270606Snsouch l |= SMBCLOCK_74K; 19370606Snsouch pci_write_config(dev, SMBHCBC, l, 1); 19470606Snsouch */ 19570606Snsouch 19693023Snsouch if (bootverbose || alpm_debug) { 19770606Snsouch l = pci_read_config(dev, SMBHSI, 1); 19893023Snsouch device_printf(dev, "%s/%s", 19943973Snsouch (l & SMBHSI_HOST) ? "host":"nohost", 20043973Snsouch (l & SMBHSI_SLAVE) ? "slave":"noslave"); 20143973Snsouch 20270606Snsouch l = pci_read_config(dev, SMBHCBC, 1); 20343973Snsouch switch (l & SMBHCBC_CLOCK) { 20443973Snsouch case SMBCLOCK_149K: 20543973Snsouch printf(" 149K"); 20643973Snsouch break; 20743973Snsouch case SMBCLOCK_74K: 20843973Snsouch printf(" 74K"); 20943973Snsouch break; 21043973Snsouch case SMBCLOCK_37K: 21143973Snsouch printf(" 37K"); 21243973Snsouch break; 21343973Snsouch case SMBCLOCK_223K: 21443973Snsouch printf(" 223K"); 21543973Snsouch break; 21643973Snsouch case SMBCLOCK_111K: 21743973Snsouch printf(" 111K"); 21843973Snsouch break; 21943973Snsouch case SMBCLOCK_55K: 22043973Snsouch printf(" 55K"); 22143973Snsouch break; 22293023Snsouch default: 22393023Snsouch printf("unkown"); 22493023Snsouch break; 22543973Snsouch } 22693023Snsouch printf("\n"); 22743973Snsouch } 22843973Snsouch 22993023Snsouch rid = SMBBA; 23093023Snsouch alpm->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 23193023Snsouch 0, ~0, 1, RF_ACTIVE); 23243973Snsouch 23393023Snsouch if (alpm->res == NULL) { 23470606Snsouch device_printf(dev,"Could not allocate Bus space\n"); 23593023Snsouch return (ENXIO); 23670606Snsouch } 23793023Snsouch alpm->smbst = rman_get_bustag(alpm->res); 23893023Snsouch alpm->smbsh = rman_get_bushandle(alpm->res); 23970606Snsouch 24093023Snsouch /* attach the smbus */ 24193023Snsouch alpm->smbus = device_add_child(dev, "smbus", -1); 24293023Snsouch bus_generic_attach(dev); 24343973Snsouch 24443973Snsouch return (0); 24543973Snsouch} 24643973Snsouch 24743973Snsouchstatic int 24893023Snsouchalpm_detach(device_t dev) 24943973Snsouch{ 25093023Snsouch struct alpm_softc *alpm = device_get_softc(dev); 25143973Snsouch 25293023Snsouch if (alpm->smbus) { 25393023Snsouch device_delete_child(dev, alpm->smbus); 25493023Snsouch alpm->smbus = NULL; 25593023Snsouch } 25643973Snsouch 25793023Snsouch if (alpm->res) 25893023Snsouch bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res); 25943973Snsouch 26043973Snsouch return (0); 26143973Snsouch} 26243973Snsouch 26343973Snsouchstatic int 26493023Snsouchalpm_callback(device_t dev, int index, caddr_t *data) 26543973Snsouch{ 26643973Snsouch int error = 0; 26743973Snsouch 26843973Snsouch switch (index) { 26943973Snsouch case SMB_REQUEST_BUS: 27043973Snsouch case SMB_RELEASE_BUS: 27143973Snsouch /* ok, bus allocation accepted */ 27243973Snsouch break; 27343973Snsouch default: 27443973Snsouch error = EINVAL; 27543973Snsouch } 27643973Snsouch 27743973Snsouch return (error); 27843973Snsouch} 27943973Snsouch 28043973Snsouchstatic int 28193023Snsouchalpm_clear(struct alpm_softc *sc) 28243973Snsouch{ 28343973Snsouch ALPM_SMBOUTB(sc, SMBSTS, 0xff); 28443973Snsouch DELAY(10); 28543973Snsouch 28643973Snsouch return (0); 28743973Snsouch} 28843973Snsouch 28943973Snsouch#if 0 29043973Snsouchstatic int 29193023Snsouchalpm_abort(struct alpm_softc *sc) 29243973Snsouch{ 29343973Snsouch ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); 29443973Snsouch 29543973Snsouch return (0); 29643973Snsouch} 29743973Snsouch#endif 29843973Snsouch 29943973Snsouchstatic int 30093023Snsouchalpm_idle(struct alpm_softc *sc) 30143973Snsouch{ 30243973Snsouch u_char sts; 30343973Snsouch 30443973Snsouch sts = ALPM_SMBINB(sc, SMBSTS); 30543973Snsouch 30643973Snsouch ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); 30743973Snsouch 30843973Snsouch return (sts & IDL_STS); 30943973Snsouch} 31043973Snsouch 31143973Snsouch/* 31243973Snsouch * Poll the SMBus controller 31343973Snsouch */ 31443973Snsouchstatic int 31593023Snsouchalpm_wait(struct alpm_softc *sc) 31643973Snsouch{ 31743973Snsouch int count = 10000; 31870606Snsouch u_char sts = 0; 31943973Snsouch int error; 32043973Snsouch 32143973Snsouch /* wait for command to complete and SMBus controller is idle */ 32243973Snsouch while(count--) { 32343973Snsouch DELAY(10); 32443973Snsouch sts = ALPM_SMBINB(sc, SMBSTS); 32543973Snsouch if (sts & SMI_I_STS) 32643973Snsouch break; 32743973Snsouch } 32843973Snsouch 32943973Snsouch ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); 33043973Snsouch 33143973Snsouch error = SMB_ENOERR; 33243973Snsouch 33343973Snsouch if (!count) 33443973Snsouch error |= SMB_ETIMEOUT; 33543973Snsouch 33643973Snsouch if (sts & TERMINATE) 33743973Snsouch error |= SMB_EABORT; 33843973Snsouch 33943973Snsouch if (sts & BUS_COLLI) 34043973Snsouch error |= SMB_ENOACK; 34143973Snsouch 34243973Snsouch if (sts & DEVICE_ERR) 34343973Snsouch error |= SMB_EBUSERR; 34443973Snsouch 34543973Snsouch if (error != SMB_ENOERR) 34693023Snsouch alpm_clear(sc); 34743973Snsouch 34843973Snsouch return (error); 34943973Snsouch} 35043973Snsouch 35143973Snsouchstatic int 35293023Snsouchalpm_quick(device_t dev, u_char slave, int how) 35343973Snsouch{ 35493023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 35543973Snsouch int error; 35643973Snsouch 35793023Snsouch alpm_clear(sc); 35893023Snsouch if (!alpm_idle(sc)) 35943973Snsouch return (EBUSY); 36043973Snsouch 36143973Snsouch switch (how) { 36243973Snsouch case SMB_QWRITE: 36343973Snsouch ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); 36443973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 36543973Snsouch break; 36643973Snsouch case SMB_QREAD: 36743973Snsouch ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); 36843973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 36943973Snsouch break; 37043973Snsouch default: 37187599Sobrien panic("%s: unknown QUICK command (%x)!", __func__, 37243973Snsouch how); 37343973Snsouch } 37443973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); 37543973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 37643973Snsouch 37793023Snsouch error = alpm_wait(sc); 37843973Snsouch 37943973Snsouch ALPM_DEBUG(printf(", error=0x%x\n", error)); 38043973Snsouch 38143973Snsouch return (error); 38243973Snsouch} 38343973Snsouch 38443973Snsouchstatic int 38593023Snsouchalpm_sendb(device_t dev, u_char slave, char byte) 38643973Snsouch{ 38793023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 38843973Snsouch int error; 38943973Snsouch 39093023Snsouch alpm_clear(sc); 39193023Snsouch if (!alpm_idle(sc)) 39243973Snsouch return (SMB_EBUSY); 39343973Snsouch 39443973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 39543973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 39643973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, byte); 39743973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 39843973Snsouch 39993023Snsouch error = alpm_wait(sc); 40043973Snsouch 40143973Snsouch ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 40243973Snsouch 40343973Snsouch return (error); 40443973Snsouch} 40543973Snsouch 40643973Snsouchstatic int 40793023Snsouchalpm_recvb(device_t dev, u_char slave, char *byte) 40843973Snsouch{ 40993023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 41043973Snsouch int error; 41143973Snsouch 41293023Snsouch alpm_clear(sc); 41393023Snsouch if (!alpm_idle(sc)) 41443973Snsouch return (SMB_EBUSY); 41543973Snsouch 41643973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 41743973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 41843973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 41943973Snsouch 42093023Snsouch if ((error = alpm_wait(sc)) == SMB_ENOERR) 42143973Snsouch *byte = ALPM_SMBINB(sc, SMBHDATA); 42243973Snsouch 42343973Snsouch ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 42443973Snsouch 42543973Snsouch return (error); 42643973Snsouch} 42743973Snsouch 42843973Snsouchstatic int 42993023Snsouchalpm_writeb(device_t dev, u_char slave, char cmd, char byte) 43043973Snsouch{ 43193023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 43243973Snsouch int error; 43343973Snsouch 43493023Snsouch alpm_clear(sc); 43593023Snsouch if (!alpm_idle(sc)) 43643973Snsouch return (SMB_EBUSY); 43743973Snsouch 43843973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 43943973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 44043973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, byte); 44143973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 44243973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 44343973Snsouch 44493023Snsouch error = alpm_wait(sc); 44543973Snsouch 44643973Snsouch ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 44743973Snsouch 44843973Snsouch return (error); 44943973Snsouch} 45043973Snsouch 45143973Snsouchstatic int 45293023Snsouchalpm_readb(device_t dev, u_char slave, char cmd, char *byte) 45343973Snsouch{ 45493023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 45543973Snsouch int error; 45643973Snsouch 45793023Snsouch alpm_clear(sc); 45893023Snsouch if (!alpm_idle(sc)) 45943973Snsouch return (SMB_EBUSY); 46043973Snsouch 46143973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 46243973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 46343973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 46443973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 46543973Snsouch 46693023Snsouch if ((error = alpm_wait(sc)) == SMB_ENOERR) 46743973Snsouch *byte = ALPM_SMBINB(sc, SMBHDATA); 46843973Snsouch 46943973Snsouch ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 47043973Snsouch 47143973Snsouch return (error); 47243973Snsouch} 47343973Snsouch 47443973Snsouchstatic int 47593023Snsouchalpm_writew(device_t dev, u_char slave, char cmd, short word) 47643973Snsouch{ 47793023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 47843973Snsouch int error; 47943973Snsouch 48093023Snsouch alpm_clear(sc); 48193023Snsouch if (!alpm_idle(sc)) 48243973Snsouch return (SMB_EBUSY); 48343973Snsouch 48443973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 48543973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 48643973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); 48743973Snsouch ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); 48843973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 48943973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 49043973Snsouch 49193023Snsouch error = alpm_wait(sc); 49243973Snsouch 49343973Snsouch ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 49443973Snsouch 49543973Snsouch return (error); 49643973Snsouch} 49743973Snsouch 49843973Snsouchstatic int 49993023Snsouchalpm_readw(device_t dev, u_char slave, char cmd, short *word) 50043973Snsouch{ 50193023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 50243973Snsouch int error; 50343973Snsouch u_char high, low; 50443973Snsouch 50593023Snsouch alpm_clear(sc); 50693023Snsouch if (!alpm_idle(sc)) 50743973Snsouch return (SMB_EBUSY); 50843973Snsouch 50943973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 51043973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 51143973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 51243973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 51343973Snsouch 51493023Snsouch if ((error = alpm_wait(sc)) == SMB_ENOERR) { 51543973Snsouch low = ALPM_SMBINB(sc, SMBHDATA); 51643973Snsouch high = ALPM_SMBINB(sc, SMBHDATB); 51743973Snsouch 51843973Snsouch *word = ((high & 0xff) << 8) | (low & 0xff); 51943973Snsouch } 52043973Snsouch 52143973Snsouch ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 52243973Snsouch 52343973Snsouch return (error); 52443973Snsouch} 52543973Snsouch 52643973Snsouchstatic int 52793023Snsouchalpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 52843973Snsouch{ 52993023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 53043973Snsouch u_char remain, len, i; 53143973Snsouch int error = SMB_ENOERR; 53243973Snsouch 53393023Snsouch alpm_clear(sc); 53493023Snsouch if(!alpm_idle(sc)) 53543973Snsouch return (SMB_EBUSY); 53643973Snsouch 53743973Snsouch remain = count; 53843973Snsouch while (remain) { 53943973Snsouch len = min(remain, 32); 54043973Snsouch 54143973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 54243973Snsouch 54343973Snsouch /* set the cmd and reset the 54443973Snsouch * 32-byte long internal buffer */ 54543973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 54643973Snsouch 54743973Snsouch ALPM_SMBOUTB(sc, SMBHDATA, len); 54843973Snsouch 54943973Snsouch /* fill the 32-byte internal buffer */ 55043973Snsouch for (i=0; i<len; i++) { 55143973Snsouch ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]); 55243973Snsouch DELAY(2); 55343973Snsouch } 55443973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 55543973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 55643973Snsouch 55793023Snsouch if ((error = alpm_wait(sc)) != SMB_ENOERR) 55843973Snsouch goto error; 55943973Snsouch 56043973Snsouch remain -= len; 56143973Snsouch } 56243973Snsouch 56343973Snsoucherror: 56443973Snsouch ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 56543973Snsouch 56643973Snsouch return (error); 56743973Snsouch} 56843973Snsouch 56943973Snsouchstatic int 57093023Snsouchalpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 57143973Snsouch{ 57293023Snsouch struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); 57343973Snsouch u_char remain, len, i; 57443973Snsouch int error = SMB_ENOERR; 57543973Snsouch 57693023Snsouch alpm_clear(sc); 57793023Snsouch if (!alpm_idle(sc)) 57843973Snsouch return (SMB_EBUSY); 57943973Snsouch 58043973Snsouch remain = count; 58143973Snsouch while (remain) { 58243973Snsouch ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 58343973Snsouch 58443973Snsouch /* set the cmd and reset the 58543973Snsouch * 32-byte long internal buffer */ 58643973Snsouch ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 58743973Snsouch 58843973Snsouch ALPM_SMBOUTB(sc, SMBHCMD, cmd); 58943973Snsouch ALPM_SMBOUTB(sc, SMBSTART, 0xff); 59043973Snsouch 59193023Snsouch if ((error = alpm_wait(sc)) != SMB_ENOERR) 59243973Snsouch goto error; 59343973Snsouch 59443973Snsouch len = ALPM_SMBINB(sc, SMBHDATA); 59543973Snsouch 59643973Snsouch /* read the 32-byte internal buffer */ 59743973Snsouch for (i=0; i<len; i++) { 59843973Snsouch buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK); 59943973Snsouch DELAY(2); 60043973Snsouch } 60143973Snsouch 60243973Snsouch remain -= len; 60343973Snsouch } 60443973Snsoucherror: 60543973Snsouch ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 60643973Snsouch 60743973Snsouch return (error); 60843973Snsouch} 60943973Snsouch 61093023Snsouchstatic devclass_t alpm_devclass; 61193023Snsouch 61293023Snsouchstatic device_method_t alpm_methods[] = { 61393023Snsouch /* device interface */ 61493023Snsouch DEVMETHOD(device_probe, alpm_probe), 61593023Snsouch DEVMETHOD(device_attach, alpm_attach), 61693023Snsouch DEVMETHOD(device_detach, alpm_detach), 61793023Snsouch 61893023Snsouch /* smbus interface */ 61993023Snsouch DEVMETHOD(smbus_callback, alpm_callback), 62093023Snsouch DEVMETHOD(smbus_quick, alpm_quick), 62193023Snsouch DEVMETHOD(smbus_sendb, alpm_sendb), 62293023Snsouch DEVMETHOD(smbus_recvb, alpm_recvb), 62393023Snsouch DEVMETHOD(smbus_writeb, alpm_writeb), 62493023Snsouch DEVMETHOD(smbus_readb, alpm_readb), 62593023Snsouch DEVMETHOD(smbus_writew, alpm_writew), 62693023Snsouch DEVMETHOD(smbus_readw, alpm_readw), 62793023Snsouch DEVMETHOD(smbus_bwrite, alpm_bwrite), 62893023Snsouch DEVMETHOD(smbus_bread, alpm_bread), 62993023Snsouch 63093023Snsouch { 0, 0 } 63193023Snsouch}; 63293023Snsouch 63393023Snsouchstatic driver_t alpm_driver = { 63493023Snsouch "alpm", 63593023Snsouch alpm_methods, 63693023Snsouch sizeof(struct alpm_softc) 63793023Snsouch}; 63893023Snsouch 63993023SnsouchDRIVER_MODULE(alpm, pci, alpm_driver, alpm_devclass, 0, 0); 640113506SmdoddMODULE_DEPEND(alpm, pci, 1, 1, 1); 64193023SnsouchMODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 64293023SnsouchMODULE_VERSION(alpm, 1); 643