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