1/*
2 * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
3 *
4 * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 */
16
17/*
18 * We select the channels by sending commands to the Philips
19 * PCA9556 chip at I2C address 0x18. The main adapter is used for
20 * the non-multiplexed part of the bus, and 4 virtual adapters
21 * are defined for the multiplexed addresses: 0x50-0x53 (memory
22 * module EEPROM) located on channels 1-4, and 0x4c (LM63)
23 * located on multiplexed channels 0 and 5-7. We define one
24 * virtual adapter per CPU, which corresponds to two multiplexed
25 * channels:
26 *   CPU0: virtual adapter 1, channels 1 and 0
27 *   CPU1: virtual adapter 2, channels 2 and 5
28 *   CPU2: virtual adapter 3, channels 3 and 6
29 *   CPU3: virtual adapter 4, channels 4 and 7
30 */
31
32#include <linux/module.h>
33#include <linux/kernel.h>
34#include <linux/slab.h>
35#include <linux/init.h>
36#include <linux/i2c.h>
37#include <linux/mutex.h>
38
39extern struct i2c_adapter amd756_smbus;
40
41static struct i2c_adapter *s4882_adapter;
42static struct i2c_algorithm *s4882_algo;
43
44/* Wrapper access functions for multiplexed SMBus */
45static DEFINE_MUTEX(amd756_lock);
46
47static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
48			       unsigned short flags, char read_write,
49			       u8 command, int size,
50			       union i2c_smbus_data * data)
51{
52	int error;
53
54	/* We exclude the multiplexed addresses */
55	if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
56	 || addr == 0x18)
57		return -ENXIO;
58
59	mutex_lock(&amd756_lock);
60
61	error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
62					      command, size, data);
63
64	mutex_unlock(&amd756_lock);
65
66	return error;
67}
68
69/* We remember the last used channels combination so as to only switch
70   channels when it is really needed. This greatly reduces the SMBus
71   overhead, but also assumes that nobody will be writing to the PCA9556
72   in our back. */
73static u8 last_channels;
74
75static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
76					unsigned short flags, char read_write,
77					u8 command, int size,
78					union i2c_smbus_data * data,
79					u8 channels)
80{
81	int error;
82
83	/* We exclude the non-multiplexed addresses */
84	if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
85		return -ENXIO;
86
87	mutex_lock(&amd756_lock);
88
89	if (last_channels != channels) {
90		union i2c_smbus_data mplxdata;
91		mplxdata.byte = channels;
92
93		error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
94						      I2C_SMBUS_WRITE, 0x01,
95						      I2C_SMBUS_BYTE_DATA,
96						      &mplxdata);
97		if (error)
98			goto UNLOCK;
99		last_channels = channels;
100	}
101	error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
102					      command, size, data);
103
104UNLOCK:
105	mutex_unlock(&amd756_lock);
106	return error;
107}
108
109static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
110			       unsigned short flags, char read_write,
111			       u8 command, int size,
112			       union i2c_smbus_data * data)
113{
114	/* CPU0: channels 1 and 0 enabled */
115	return amd756_access_channel(adap, addr, flags, read_write, command,
116				     size, data, 0x03);
117}
118
119static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
120			       unsigned short flags, char read_write,
121			       u8 command, int size,
122			       union i2c_smbus_data * data)
123{
124	/* CPU1: channels 2 and 5 enabled */
125	return amd756_access_channel(adap, addr, flags, read_write, command,
126				     size, data, 0x24);
127}
128
129static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
130			       unsigned short flags, char read_write,
131			       u8 command, int size,
132			       union i2c_smbus_data * data)
133{
134	/* CPU2: channels 3 and 6 enabled */
135	return amd756_access_channel(adap, addr, flags, read_write, command,
136				     size, data, 0x48);
137}
138
139static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
140			       unsigned short flags, char read_write,
141			       u8 command, int size,
142			       union i2c_smbus_data * data)
143{
144	/* CPU3: channels 4 and 7 enabled */
145	return amd756_access_channel(adap, addr, flags, read_write, command,
146				     size, data, 0x90);
147}
148
149static int __init amd756_s4882_init(void)
150{
151	int i, error;
152	union i2c_smbus_data ioconfig;
153
154	if (!amd756_smbus.dev.parent)
155		return -ENODEV;
156
157	/* Configure the PCA9556 multiplexer */
158	ioconfig.byte = 0x00; /* All I/O to output mode */
159	error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
160			       I2C_SMBUS_BYTE_DATA, &ioconfig);
161	if (error) {
162		dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
163		error = -EIO;
164		goto ERROR0;
165	}
166
167	/* Unregister physical bus */
168	i2c_del_adapter(&amd756_smbus);
169
170	printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
171	/* Define the 5 virtual adapters and algorithms structures */
172	if (!(s4882_adapter = kzalloc(5 * sizeof(struct i2c_adapter),
173				      GFP_KERNEL))) {
174		error = -ENOMEM;
175		goto ERROR1;
176	}
177	if (!(s4882_algo = kzalloc(5 * sizeof(struct i2c_algorithm),
178				   GFP_KERNEL))) {
179		error = -ENOMEM;
180		goto ERROR2;
181	}
182
183	/* Fill in the new structures */
184	s4882_algo[0] = *(amd756_smbus.algo);
185	s4882_algo[0].smbus_xfer = amd756_access_virt0;
186	s4882_adapter[0] = amd756_smbus;
187	s4882_adapter[0].algo = s4882_algo;
188	s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
189	for (i = 1; i < 5; i++) {
190		s4882_algo[i] = *(amd756_smbus.algo);
191		s4882_adapter[i] = amd756_smbus;
192		snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
193			 "SMBus 8111 adapter (CPU%d)", i-1);
194		s4882_adapter[i].algo = s4882_algo+i;
195		s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
196	}
197	s4882_algo[1].smbus_xfer = amd756_access_virt1;
198	s4882_algo[2].smbus_xfer = amd756_access_virt2;
199	s4882_algo[3].smbus_xfer = amd756_access_virt3;
200	s4882_algo[4].smbus_xfer = amd756_access_virt4;
201
202	/* Register virtual adapters */
203	for (i = 0; i < 5; i++) {
204		error = i2c_add_adapter(s4882_adapter+i);
205		if (error) {
206			printk(KERN_ERR "i2c-amd756-s4882: "
207			       "Virtual adapter %d registration "
208			       "failed, module not inserted\n", i);
209			for (i--; i >= 0; i--)
210				i2c_del_adapter(s4882_adapter+i);
211			goto ERROR3;
212		}
213	}
214
215	return 0;
216
217ERROR3:
218	kfree(s4882_algo);
219	s4882_algo = NULL;
220ERROR2:
221	kfree(s4882_adapter);
222	s4882_adapter = NULL;
223ERROR1:
224	/* Restore physical bus */
225	i2c_add_adapter(&amd756_smbus);
226ERROR0:
227	return error;
228}
229
230static void __exit amd756_s4882_exit(void)
231{
232	if (s4882_adapter) {
233		int i;
234
235		for (i = 0; i < 5; i++)
236			i2c_del_adapter(s4882_adapter+i);
237		kfree(s4882_adapter);
238		s4882_adapter = NULL;
239	}
240	kfree(s4882_algo);
241	s4882_algo = NULL;
242
243	/* Restore physical bus */
244	if (i2c_add_adapter(&amd756_smbus))
245		printk(KERN_ERR "i2c-amd756-s4882: "
246		       "Physical bus restoration failed\n");
247}
248
249MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
250MODULE_DESCRIPTION("S4882 SMBus multiplexing");
251MODULE_LICENSE("GPL");
252
253module_init(amd756_s4882_init);
254module_exit(amd756_s4882_exit);
255