1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/slab.h>
37#include <linux/init.h>
38#include <linux/i2c.h>
39#include <linux/mutex.h>
40
41extern struct i2c_adapter *nforce2_smbus;
42
43static struct i2c_adapter *s4985_adapter;
44static struct i2c_algorithm *s4985_algo;
45
46
47static DEFINE_MUTEX(nforce2_lock);
48
49static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
50 unsigned short flags, char read_write,
51 u8 command, int size,
52 union i2c_smbus_data *data)
53{
54 int error;
55
56
57 if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
58 || addr == 0x18)
59 return -ENXIO;
60
61 mutex_lock(&nforce2_lock);
62 error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
63 command, size, data);
64 mutex_unlock(&nforce2_lock);
65
66 return error;
67}
68
69
70
71
72
73static u8 last_channels;
74
75static inline s32 nforce2_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
84 if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
85 return -ENXIO;
86
87 mutex_lock(&nforce2_lock);
88 if (last_channels != channels) {
89 union i2c_smbus_data mplxdata;
90 mplxdata.byte = channels;
91
92 error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
93 I2C_SMBUS_WRITE, 0x01,
94 I2C_SMBUS_BYTE_DATA,
95 &mplxdata);
96 if (error)
97 goto UNLOCK;
98 last_channels = channels;
99 }
100 error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
101 command, size, data);
102
103UNLOCK:
104 mutex_unlock(&nforce2_lock);
105 return error;
106}
107
108static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
109 unsigned short flags, char read_write,
110 u8 command, int size,
111 union i2c_smbus_data *data)
112{
113
114 return nforce2_access_channel(adap, addr, flags, read_write, command,
115 size, data, 0x02);
116}
117
118static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
119 unsigned short flags, char read_write,
120 u8 command, int size,
121 union i2c_smbus_data *data)
122{
123
124 return nforce2_access_channel(adap, addr, flags, read_write, command,
125 size, data, 0x04);
126}
127
128static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
129 unsigned short flags, char read_write,
130 u8 command, int size,
131 union i2c_smbus_data *data)
132{
133
134 return nforce2_access_channel(adap, addr, flags, read_write, command,
135 size, data, 0x08);
136}
137
138static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
139 unsigned short flags, char read_write,
140 u8 command, int size,
141 union i2c_smbus_data *data)
142{
143
144 return nforce2_access_channel(adap, addr, flags, read_write, command,
145 size, data, 0x10);
146}
147
148static int __init nforce2_s4985_init(void)
149{
150 int i, error;
151 union i2c_smbus_data ioconfig;
152
153 if (!nforce2_smbus)
154 return -ENODEV;
155
156
157 ioconfig.byte = 0x00;
158 error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
159 I2C_SMBUS_BYTE_DATA, &ioconfig);
160 if (error) {
161 dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
162 error = -EIO;
163 goto ERROR0;
164 }
165
166
167 error = i2c_del_adapter(nforce2_smbus);
168 if (error) {
169 dev_err(&nforce2_smbus->dev, "Physical bus removal failed\n");
170 goto ERROR0;
171 }
172
173 printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
174
175 s4985_adapter = kzalloc(5 * sizeof(struct i2c_adapter), GFP_KERNEL);
176 if (!s4985_adapter) {
177 error = -ENOMEM;
178 goto ERROR1;
179 }
180 s4985_algo = kzalloc(5 * sizeof(struct i2c_algorithm), GFP_KERNEL);
181 if (!s4985_algo) {
182 error = -ENOMEM;
183 goto ERROR2;
184 }
185
186
187 s4985_algo[0] = *(nforce2_smbus->algo);
188 s4985_algo[0].smbus_xfer = nforce2_access_virt0;
189 s4985_adapter[0] = *nforce2_smbus;
190 s4985_adapter[0].algo = s4985_algo;
191 s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
192 for (i = 1; i < 5; i++) {
193 s4985_algo[i] = *(nforce2_smbus->algo);
194 s4985_adapter[i] = *nforce2_smbus;
195 snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
196 "SMBus nForce2 adapter (CPU%d)", i - 1);
197 s4985_adapter[i].algo = s4985_algo + i;
198 s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
199 }
200 s4985_algo[1].smbus_xfer = nforce2_access_virt1;
201 s4985_algo[2].smbus_xfer = nforce2_access_virt2;
202 s4985_algo[3].smbus_xfer = nforce2_access_virt3;
203 s4985_algo[4].smbus_xfer = nforce2_access_virt4;
204
205
206 for (i = 0; i < 5; i++) {
207 error = i2c_add_adapter(s4985_adapter + i);
208 if (error) {
209 printk(KERN_ERR "i2c-nforce2-s4985: "
210 "Virtual adapter %d registration "
211 "failed, module not inserted\n", i);
212 for (i--; i >= 0; i--)
213 i2c_del_adapter(s4985_adapter + i);
214 goto ERROR3;
215 }
216 }
217
218 return 0;
219
220ERROR3:
221 kfree(s4985_algo);
222 s4985_algo = NULL;
223ERROR2:
224 kfree(s4985_adapter);
225 s4985_adapter = NULL;
226ERROR1:
227
228 i2c_add_adapter(nforce2_smbus);
229ERROR0:
230 return error;
231}
232
233static void __exit nforce2_s4985_exit(void)
234{
235 if (s4985_adapter) {
236 int i;
237
238 for (i = 0; i < 5; i++)
239 i2c_del_adapter(s4985_adapter+i);
240 kfree(s4985_adapter);
241 s4985_adapter = NULL;
242 }
243 kfree(s4985_algo);
244 s4985_algo = NULL;
245
246
247 if (i2c_add_adapter(nforce2_smbus))
248 printk(KERN_ERR "i2c-nforce2-s4985: "
249 "Physical bus restoration failed\n");
250}
251
252MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
253MODULE_DESCRIPTION("S4985 SMBus multiplexing");
254MODULE_LICENSE("GPL");
255
256module_init(nforce2_s4985_init);
257module_exit(nforce2_s4985_exit);
258