11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2004 Steven J. Hill 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2001,2002,2003 Broadcom Corporation 451c3711704b66986373408cbc0540abea43d2380Jean Delvare * Copyright (C) 1995-2000 Simon G. Vogl 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 2 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the License, or (at your option) any later version. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151c3711704b66986373408cbc0540abea43d2380Jean Delvare#include <linux/kernel.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 2351c3711704b66986373408cbc0540abea43d2380Jean Delvare#include <linux/init.h> 2451c3711704b66986373408cbc0540abea43d2380Jean Delvare#include <linux/i2c.h> 252178218027e4da0608219fae1d02e5c88f4e560dH Hartley Sweeten#include <linux/io.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sibyte/sb1250_regs.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sibyte/sb1250_smbus.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951c3711704b66986373408cbc0540abea43d2380Jean Delvare 3051c3711704b66986373408cbc0540abea43d2380Jean Delvarestruct i2c_algo_sibyte_data { 3151c3711704b66986373408cbc0540abea43d2380Jean Delvare void *data; /* private data */ 3251c3711704b66986373408cbc0540abea43d2380Jean Delvare int bus; /* which bus */ 3351c3711704b66986373408cbc0540abea43d2380Jean Delvare void *reg_base; /* CSR base */ 3451c3711704b66986373408cbc0540abea43d2380Jean Delvare}; 3551c3711704b66986373408cbc0540abea43d2380Jean Delvare 3651c3711704b66986373408cbc0540abea43d2380Jean Delvare/* ----- global defines ----------------------------------------------- */ 3751c3711704b66986373408cbc0540abea43d2380Jean Delvare#define SMB_CSR(a,r) ((long)(a->reg_base + r)) 3851c3711704b66986373408cbc0540abea43d2380Jean Delvare 3951c3711704b66986373408cbc0540abea43d2380Jean Delvare 4051c3711704b66986373408cbc0540abea43d2380Jean Delvarestatic int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr, 4151c3711704b66986373408cbc0540abea43d2380Jean Delvare unsigned short flags, char read_write, 4251c3711704b66986373408cbc0540abea43d2380Jean Delvare u8 command, int size, union i2c_smbus_data * data) 4351c3711704b66986373408cbc0540abea43d2380Jean Delvare{ 4451c3711704b66986373408cbc0540abea43d2380Jean Delvare struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; 4551c3711704b66986373408cbc0540abea43d2380Jean Delvare int data_bytes = 0; 4651c3711704b66986373408cbc0540abea43d2380Jean Delvare int error; 4751c3711704b66986373408cbc0540abea43d2380Jean Delvare 4851c3711704b66986373408cbc0540abea43d2380Jean Delvare while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) 4951c3711704b66986373408cbc0540abea43d2380Jean Delvare ; 5051c3711704b66986373408cbc0540abea43d2380Jean Delvare 5151c3711704b66986373408cbc0540abea43d2380Jean Delvare switch (size) { 5251c3711704b66986373408cbc0540abea43d2380Jean Delvare case I2C_SMBUS_QUICK: 5351c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | 5451c3711704b66986373408cbc0540abea43d2380Jean Delvare (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) | 5551c3711704b66986373408cbc0540abea43d2380Jean Delvare V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START)); 5651c3711704b66986373408cbc0540abea43d2380Jean Delvare break; 5751c3711704b66986373408cbc0540abea43d2380Jean Delvare case I2C_SMBUS_BYTE: 5851c3711704b66986373408cbc0540abea43d2380Jean Delvare if (read_write == I2C_SMBUS_READ) { 5951c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE), 6051c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 6151c3711704b66986373408cbc0540abea43d2380Jean Delvare data_bytes = 1; 6251c3711704b66986373408cbc0540abea43d2380Jean Delvare } else { 6351c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); 6451c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE), 6551c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 6651c3711704b66986373408cbc0540abea43d2380Jean Delvare } 6751c3711704b66986373408cbc0540abea43d2380Jean Delvare break; 6851c3711704b66986373408cbc0540abea43d2380Jean Delvare case I2C_SMBUS_BYTE_DATA: 6951c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); 7051c3711704b66986373408cbc0540abea43d2380Jean Delvare if (read_write == I2C_SMBUS_READ) { 7151c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE), 7251c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 7351c3711704b66986373408cbc0540abea43d2380Jean Delvare data_bytes = 1; 7451c3711704b66986373408cbc0540abea43d2380Jean Delvare } else { 7551c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_LB(data->byte), 7651c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_DATA)); 7751c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), 7851c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 7951c3711704b66986373408cbc0540abea43d2380Jean Delvare } 8051c3711704b66986373408cbc0540abea43d2380Jean Delvare break; 8151c3711704b66986373408cbc0540abea43d2380Jean Delvare case I2C_SMBUS_WORD_DATA: 8251c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD)); 8351c3711704b66986373408cbc0540abea43d2380Jean Delvare if (read_write == I2C_SMBUS_READ) { 8451c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE), 8551c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 8651c3711704b66986373408cbc0540abea43d2380Jean Delvare data_bytes = 2; 8751c3711704b66986373408cbc0540abea43d2380Jean Delvare } else { 8851c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_LB(data->word & 0xff), 8951c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_DATA)); 9051c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(V_SMB_MB(data->word >> 8), 9151c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_DATA)); 9251c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE), 9351c3711704b66986373408cbc0540abea43d2380Jean Delvare SMB_CSR(adap, R_SMB_START)); 9451c3711704b66986373408cbc0540abea43d2380Jean Delvare } 9551c3711704b66986373408cbc0540abea43d2380Jean Delvare break; 9651c3711704b66986373408cbc0540abea43d2380Jean Delvare default: 97102b59c6d6d30fb6560177fd1ae8a34c4c163897Guenter Roeck return -EOPNOTSUPP; 9851c3711704b66986373408cbc0540abea43d2380Jean Delvare } 9951c3711704b66986373408cbc0540abea43d2380Jean Delvare 10051c3711704b66986373408cbc0540abea43d2380Jean Delvare while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY) 10151c3711704b66986373408cbc0540abea43d2380Jean Delvare ; 10251c3711704b66986373408cbc0540abea43d2380Jean Delvare 10351c3711704b66986373408cbc0540abea43d2380Jean Delvare error = csr_in32(SMB_CSR(adap, R_SMB_STATUS)); 10451c3711704b66986373408cbc0540abea43d2380Jean Delvare if (error & M_SMB_ERROR) { 10551c3711704b66986373408cbc0540abea43d2380Jean Delvare /* Clear error bit by writing a 1 */ 10651c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS)); 107102b59c6d6d30fb6560177fd1ae8a34c4c163897Guenter Roeck return (error & M_SMB_ERROR_TYPE) ? -EIO : -ENXIO; 10851c3711704b66986373408cbc0540abea43d2380Jean Delvare } 10951c3711704b66986373408cbc0540abea43d2380Jean Delvare 11051c3711704b66986373408cbc0540abea43d2380Jean Delvare if (data_bytes == 1) 11151c3711704b66986373408cbc0540abea43d2380Jean Delvare data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff; 11251c3711704b66986373408cbc0540abea43d2380Jean Delvare if (data_bytes == 2) 11351c3711704b66986373408cbc0540abea43d2380Jean Delvare data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff; 11451c3711704b66986373408cbc0540abea43d2380Jean Delvare 11551c3711704b66986373408cbc0540abea43d2380Jean Delvare return 0; 11651c3711704b66986373408cbc0540abea43d2380Jean Delvare} 11751c3711704b66986373408cbc0540abea43d2380Jean Delvare 11851c3711704b66986373408cbc0540abea43d2380Jean Delvarestatic u32 bit_func(struct i2c_adapter *adap) 11951c3711704b66986373408cbc0540abea43d2380Jean Delvare{ 12051c3711704b66986373408cbc0540abea43d2380Jean Delvare return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 12151c3711704b66986373408cbc0540abea43d2380Jean Delvare I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA); 12251c3711704b66986373408cbc0540abea43d2380Jean Delvare} 12351c3711704b66986373408cbc0540abea43d2380Jean Delvare 12451c3711704b66986373408cbc0540abea43d2380Jean Delvare 12551c3711704b66986373408cbc0540abea43d2380Jean Delvare/* -----exported algorithm data: ------------------------------------- */ 12651c3711704b66986373408cbc0540abea43d2380Jean Delvare 1278f9082c5ce0e2c2f7ad0211b0c089f680d2efc11Jean Delvarestatic const struct i2c_algorithm i2c_sibyte_algo = { 12851c3711704b66986373408cbc0540abea43d2380Jean Delvare .smbus_xfer = smbus_xfer, 12951c3711704b66986373408cbc0540abea43d2380Jean Delvare .functionality = bit_func, 13051c3711704b66986373408cbc0540abea43d2380Jean Delvare}; 13151c3711704b66986373408cbc0540abea43d2380Jean Delvare 13251c3711704b66986373408cbc0540abea43d2380Jean Delvare/* 13351c3711704b66986373408cbc0540abea43d2380Jean Delvare * registering functions to load algorithms at runtime 13451c3711704b66986373408cbc0540abea43d2380Jean Delvare */ 135b11a9d8392a698f01337232aa8c5d5603519943fMaciej W. Rozyckistatic int __init i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed) 13651c3711704b66986373408cbc0540abea43d2380Jean Delvare{ 13751c3711704b66986373408cbc0540abea43d2380Jean Delvare struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data; 13851c3711704b66986373408cbc0540abea43d2380Jean Delvare 139b3eb5a0bc3c359dbb5ccb0708df18525ab6a1430Maciej W. Rozycki /* Register new adapter to i2c module... */ 14051c3711704b66986373408cbc0540abea43d2380Jean Delvare i2c_adap->algo = &i2c_sibyte_algo; 14151c3711704b66986373408cbc0540abea43d2380Jean Delvare 142b3eb5a0bc3c359dbb5ccb0708df18525ab6a1430Maciej W. Rozycki /* Set the requested frequency. */ 14351c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ)); 14451c3711704b66986373408cbc0540abea43d2380Jean Delvare csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL)); 14551c3711704b66986373408cbc0540abea43d2380Jean Delvare 146392a0408fdc4c9069c32a9a02b0088eae76c4618Maciej W. Rozycki return i2c_add_numbered_adapter(i2c_adap); 14751c3711704b66986373408cbc0540abea43d2380Jean Delvare} 14851c3711704b66986373408cbc0540abea43d2380Jean Delvare 14951c3711704b66986373408cbc0540abea43d2380Jean Delvare 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_algo_sibyte_data sibyte_board_data[2] = { 151a242b44da6feb604c4c659b78f63dedb69b2d4a3Ralf Baechle { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, 152a242b44da6feb604c4c659b78f63dedb69b2d4a3Ralf Baechle { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_adapter sibyte_board_adapter[2] = { 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1583401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .algo = NULL, 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .algo_data = &sibyte_board_data[0], 161392a0408fdc4c9069c32a9a02b0088eae76c4618Maciej W. Rozycki .nr = 0, 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "SiByte SMBus 0", 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1663401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .algo = NULL, 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .algo_data = &sibyte_board_data[1], 169392a0408fdc4c9069c32a9a02b0088eae76c4618Maciej W. Rozycki .nr = 1, 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "SiByte SMBus 1", 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2c_sibyte_init(void) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1765cd6e675f862568ad73c061665ee5080cfd952c5Jean Delvare pr_info("i2c-sibyte: i2c SMBus adapter module for SiByte board\n"); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i2c_sibyte_add_bus(&sibyte_board_adapter[0], K_SMB_FREQ_100KHZ) < 0) 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1795cd6e675f862568ad73c061665ee5080cfd952c5Jean Delvare if (i2c_sibyte_add_bus(&sibyte_board_adapter[1], 1805cd6e675f862568ad73c061665ee5080cfd952c5Jean Delvare K_SMB_FREQ_400KHZ) < 0) { 1815cd6e675f862568ad73c061665ee5080cfd952c5Jean Delvare i2c_del_adapter(&sibyte_board_adapter[0]); 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 1835cd6e675f862568ad73c061665ee5080cfd952c5Jean Delvare } 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2c_sibyte_exit(void) 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 189ae1390d8c3e2142e5cf6d192951d6e2b1fa213c5Yoichi Yuasa i2c_del_adapter(&sibyte_board_adapter[0]); 190ae1390d8c3e2142e5cf6d192951d6e2b1fa213c5Yoichi Yuasa i2c_del_adapter(&sibyte_board_adapter[1]); 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2c_sibyte_init); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2c_sibyte_exit); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 196643bd3fbd9dc73ed3dc1e4f6980e6f15fdbb9bb6Jean DelvareMODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>"); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("SMBus adapter routines for SiByte boards"); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 199