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