i2c-ali15x3.c revision 8f9082c5ce0e2c2f7ad0211b0c089f680d2efc11
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds monitoring 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Philip Edelbrock <phil@netroedge.com> and 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Mark D. Studebaker <mdsxyz123@yahoo.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is free software; you can redistribute it and/or modify 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it under the terms of the GNU General Public License as published by 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the Free Software Foundation; either version 2 of the License, or 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (at your option) any later version. 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is distributed in the hope that it will be useful, 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GNU General Public License for more details. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You should have received a copy of the GNU General Public License 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds along with this program; if not, write to the Free Software 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This is the driver for the SMB Host controller on 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Acer Labs Inc. (ALI) M1541 and M1543C South Bridges. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The M1543C is a South bridge for desktop systems. 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The M1533 is a South bridge for portable systems. 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds They are part of the following ALI chipsets: 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with AGP and 100MHz CPU Front Side bus 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Aladdin V": Includes the M1541 Socket 7 North bridge 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with AGP and 100MHz CPU Front Side bus 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Aladdin IV": Includes the M1541 Socket 7 North bridge 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds with host bus up to 83.3 MHz. 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For an overview of these chips see http://www.acerlabs.com 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The M1533/M1543C devices appear as FOUR separate devices 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds on the PCI bus. An output of lspci will show something similar 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to the following: 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 00:02.0 USB Controller: Acer Laboratories Inc. M5237 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 00:03.0 Bridge: Acer Laboratories Inc. M7101 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 00:07.0 ISA bridge: Acer Laboratories Inc. M1533 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 00:0f.0 IDE interface: Acer Laboratories Inc. M5229 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The SMB controller is part of the 7101 device, which is an 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ACPI-compliant Power Management Unit (PMU). 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The whole 7101 device has to be enabled for the SMB to work. 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You can't just enable the SMB alone. 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The SMB and the ACPI have separate I/O spaces. 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds We make sure that the SMB is enabled. We leave the ACPI alone. 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver controls the SMB Host only. 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The SMB Slave controller on the M15X3 is not enabled. 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver does not use interrupts. 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we assume there can only be one ALI15X3, with one SMBus interface */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 SMBus address offsets */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTSTS (0 + ali15x3_smba) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCNT (1 + ali15x3_smba) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTSTART (2 + ali15x3_smba) 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCMD (7 + ali15x3_smba) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTADD (3 + ali15x3_smba) 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT0 (4 + ali15x3_smba) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT1 (5 + ali15x3_smba) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBBLKDAT (6 + ali15x3_smba) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI Address Constants */ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBCOM 0x004 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBBA 0x014 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBATPC 0x05B /* used to unlock xxxBA registers */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCFG 0x0E0 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBSLVC 0x0E1 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBCLK 0x0E2 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBREV 0x008 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Other settings */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_TIMEOUT 200 /* times 1/100 sec */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_SMB_IOSIZE 32 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB. 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds We don't use these here. If the bases aren't set to some value we 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tell user to upgrade BIOS and we fail. 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_SMB_DEFAULTBASE 0xE800 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 address lock bits */ 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_LOCK 0x06 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 command constants */ 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_ABORT 0x02 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_T_OUT 0x04 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_QUICK 0x00 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BYTE 0x10 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BYTE_DATA 0x20 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_WORD_DATA 0x30 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BLOCK_DATA 0x40 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BLOCK_CLR 0x80 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 status register bits */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_IDLE 0x04 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_BUSY 0x08 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_DONE 0x10 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_DEV 0x20 /* device error */ 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_COLL 0x40 /* collision or no response */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_TERM 0x80 /* terminated by abort */ 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If force_addr is set to anything different from 0, we forcibly enable 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the device at the given address. */ 128605070952f0b41caaa211c47b02eeac703529008Jean Delvarestatic u16 force_addr; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr, 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initialize the base address of the i2c controller"); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 133d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvarestatic struct pci_driver ali15x3_driver; 134605070952f0b41caaa211c47b02eeac703529008Jean Delvarestatic unsigned short ali15x3_smba; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ali15x3_setup(struct pci_dev *ALI15X3_dev) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 a; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char temp; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the following things: 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - SMB I/O address is initialized 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - Device is enabled 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds - We can use the addresses 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unlock the register. 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The data sheet says that the address registers are read-only 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if the lock bits are 1, but in fact the address registers 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds are zero unless you clear the lock bits. 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp); 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_LOCK) { 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp &= ~ALI15X3_LOCK; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(ALI15X3_dev, SMBATPC, temp); 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine the address of the SMBus area */ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba); 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1)); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ali15x3_smba == 0 && force_addr == 0) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized " 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "- upgrade BIOS or use force_addr=0xaddr\n"); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(force_addr) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 170d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvare if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE, 171d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvare ali15x3_driver.name)) { 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&ALI15X3_dev->dev, 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ALI15X3_smb region 0x%x already in use!\n", 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_smba); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(force_addr) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n", 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_smba); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBBA, 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_smba)) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev, 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBBA, &a)) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure it works */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&ALI15X3_dev->dev, 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "force address failed - not supported?\n"); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto error; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check if whole device is enabled */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp & 1) == 0) { 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n"); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Is SMB Host controller enabled? */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp & 1) == 0) { 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n"); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set SMB clock to 74KHz as recommended in data sheet */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The interrupt routing for SMB is set up in register 0x77 in the 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1533 ISA Bridge device, NOT in the 7101 device. 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Don't bother with finding the 1533 device and reading the register. 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((....... & 0x0F) == 1) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n"); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(ALI15X3_dev, SMBREV, &temp); 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror: 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Another internally used function */ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ali15x3_transaction(struct i2c_adapter *adap) 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int temp; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result = 0; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout = 0; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, " 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* get status */ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = inb_p(SMBHSTSTS); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure the SMBus host is ready to start transmitting */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check the busy bit first */ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_STS_BUSY) { 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If the host controller is still busy, it may have timed out in the 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds previous transaction, resulting in a "SMBus Timeout" Dev. 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I've tried the following to reset a stuck busy bit. 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1. Reset the controller with an ABORT command. 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (this doesn't seem to clear the controller if an external 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device is hung) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2. Reset the controller and the other SMBus devices with a 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds T_OUT command. (this clears the host busy bit if an 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds external device is hung, but it comes back upon a new access 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds to a device) 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3. Disable and reenable the controller in SMBHSTCFG 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Worst case, nothing seems to work except power reset. 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Abort - reset the host controller */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Try resetting entire SMB bus, including other devices - 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This may not work either - it clears the BUSY bit but 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds then the BUSY bit may come back on when you try and use the chip again. 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds If that's the case you are stuck. 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&adap->dev, "Resetting entire SMB Bus to " 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "clear busy condition (%02x)\n", temp); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(ALI15X3_T_OUT, SMBHSTCNT); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = inb_p(SMBHSTSTS); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* now check the error bits and the busy bit */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* do a clear-on-write */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0xFF, SMBHSTSTS); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) & 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) { 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* this is probably going to be correctable only by a power reset 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds as one of the bits now appears to be stuck */ 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* This may be a bus or device with electrical problems. */ 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - " 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "controller or device on bus is probably hung\n", 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp); 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* check and clear done bit */ 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_STS_DONE) { 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(temp, SMBHSTSTS); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* start the transaction by writing anything to the start register */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0xFF, SMBHSTSTART); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We will always wait for a fraction of a second! */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout = 0; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(1); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = inb_p(SMBHSTSTS); 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE))) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (timeout++ < MAX_TIMEOUT)); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If the SMBus is still busy, we give up */ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout >= MAX_TIMEOUT) { 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -1; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&adap->dev, "SMBus Timeout!\n"); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_STS_TERM) { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -1; 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&adap->dev, "Error: Failed bus transaction\n"); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Unfortunately the ALI SMB controller maps "no response" and "bus 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds collision" into a single bit. No reponse is the usual case so don't 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do a printk. 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This means that bus collisions go unreported. 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_STS_COLL) { 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -1; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&adap->dev, 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Error: no response or bus collision ADD=%02x\n", 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb_p(SMBHSTADD)); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* haven't ever seen this */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (temp & ALI15X3_STS_DEV) { 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = -1; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&adap->dev, "Error: device error\n"); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, " 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS), 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD), 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1)); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return result; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Return -1 on error. */ 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic s32 ali15x3_access(struct i2c_adapter * adap, u16 addr, 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned short flags, char read_write, u8 command, 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int size, union i2c_smbus_data * data) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, len; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int temp; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int timeout; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clear all the bits (clear-on-write) */ 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0xFF, SMBHSTSTS); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* make sure SMBus is idle */ 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = inb_p(SMBHSTSTS); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (timeout = 0; 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds timeout++) { 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msleep(1); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds temp = inb_p(SMBHSTSTS); 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (timeout >= MAX_TIMEOUT) { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (size) { 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_PROC_CALL: 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n"); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_QUICK: 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBHSTADD); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ALI15X3_QUICK; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_BYTE: 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBHSTADD); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(command, SMBHSTCMD); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ALI15X3_BYTE; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_BYTE_DATA: 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBHSTADD); 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(command, SMBHSTCMD); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_write == I2C_SMBUS_WRITE) 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(data->byte, SMBHSTDAT0); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ALI15X3_BYTE_DATA; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_WORD_DATA: 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBHSTADD); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(command, SMBHSTCMD); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_write == I2C_SMBUS_WRITE) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(data->word & 0xff, SMBHSTDAT0); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ALI15X3_WORD_DATA; 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case I2C_SMBUS_BLOCK_DATA: 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SMBHSTADD); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(command, SMBHSTCMD); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (read_write == I2C_SMBUS_WRITE) { 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = data->block[0]; 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len < 0) { 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 0; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->block[0] = len; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > 32) { 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 32; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->block[0] = len; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(len, SMBHSTDAT0); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset SMBBLKDAT */ 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= len; i++) 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(data->block[i], SMBBLKDAT); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = ALI15X3_BLOCK_DATA; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(size, SMBHSTCNT); /* output command */ 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ali15x3_transaction(adap)) /* Error in transaction */ 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK)) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (size) { 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ALI15X3_BYTE: /* Result put in SMBHSTDAT0 */ 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->byte = inb_p(SMBHSTDAT0); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ALI15X3_BYTE_DATA: 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->byte = inb_p(SMBHSTDAT0); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ALI15X3_WORD_DATA: 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case ALI15X3_BLOCK_DATA: 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = inb_p(SMBHSTDAT0); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > 32) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 32; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->block[0] = len; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset SMBBLKDAT */ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= data->block[0]; i++) { 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->block[i] = inb_p(SMBBLKDAT); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n", 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len, i, data->block[i]); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 ali15x3_func(struct i2c_adapter *adapter) 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds I2C_FUNC_SMBUS_BLOCK_DATA; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4668f9082c5ce0e2c2f7ad0211b0c089f680d2efc11Jean Delvarestatic const struct i2c_algorithm smbus_algorithm = { 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .smbus_xfer = ali15x3_access, 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .functionality = ali15x3_func, 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_adapter ali15x3_adapter = { 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .class = I2C_CLASS_HWMON, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .algo = &smbus_algorithm, 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id ali15x3_ids[] = { 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, } 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (pci, ali15x3_ids); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ali15x3_setup(dev)) { 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&dev->dev, 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ALI15X3 not detected, module not inserted.\n"); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set up the driverfs linkage to our parent device */ 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ali15x3_adapter.dev.parent = &dev->dev; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "SMBus ALI15X3 adapter at %04x", ali15x3_smba); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i2c_add_adapter(&ali15x3_adapter); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit ali15x3_remove(struct pci_dev *dev) 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_del_adapter(&ali15x3_adapter); 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver ali15x3_driver = { 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "ali15x3_smbus", 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = ali15x3_ids, 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = ali15x3_probe, 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = __devexit_p(ali15x3_remove), 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2c_ali15x3_init(void) 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pci_register_driver(&ali15x3_driver); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2c_ali15x3_exit(void) 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unregister_driver(&ali15x3_driver); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, " 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Philip Edelbrock <phil@netroedge.com>, " 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "and Mark D. Studebaker <mdsxyz123@yahoo.com>"); 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ALI15X3 SMBus driver"); 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2c_ali15x3_init); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2c_ali15x3_exit); 531