1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2279e9024SJean Delvare /*
3279e9024SJean Delvare  * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
4279e9024SJean Delvare  *
57c81c60fSJean Delvare  * Copyright (C) 2008 Jean Delvare <jdelvare@suse.de>
6279e9024SJean Delvare  */
7279e9024SJean Delvare 
8279e9024SJean Delvare /*
9279e9024SJean Delvare  * We select the channels by sending commands to the Philips
10279e9024SJean Delvare  * PCA9556 chip at I2C address 0x18. The main adapter is used for
11279e9024SJean Delvare  * the non-multiplexed part of the bus, and 4 virtual adapters
12279e9024SJean Delvare  * are defined for the multiplexed addresses: 0x50-0x53 (memory
13279e9024SJean Delvare  * module EEPROM) located on channels 1-4. We define one virtual
14279e9024SJean Delvare  * adapter per CPU, which corresponds to one multiplexed channel:
15279e9024SJean Delvare  *   CPU0: virtual adapter 1, channel 1
16279e9024SJean Delvare  *   CPU1: virtual adapter 2, channel 2
17279e9024SJean Delvare  *   CPU2: virtual adapter 3, channel 3
18279e9024SJean Delvare  *   CPU3: virtual adapter 4, channel 4
19279e9024SJean Delvare  */
20279e9024SJean Delvare 
21279e9024SJean Delvare #include <linux/module.h>
22279e9024SJean Delvare #include <linux/kernel.h>
23279e9024SJean Delvare #include <linux/slab.h>
24279e9024SJean Delvare #include <linux/init.h>
25279e9024SJean Delvare #include <linux/i2c.h>
26279e9024SJean Delvare #include <linux/mutex.h>
27279e9024SJean Delvare 
28279e9024SJean Delvare extern struct i2c_adapter *nforce2_smbus;
29279e9024SJean Delvare 
30279e9024SJean Delvare static struct i2c_adapter *s4985_adapter;
31279e9024SJean Delvare static struct i2c_algorithm *s4985_algo;
32279e9024SJean Delvare 
33279e9024SJean Delvare /* Wrapper access functions for multiplexed SMBus */
34279e9024SJean Delvare static DEFINE_MUTEX(nforce2_lock);
35279e9024SJean Delvare 
nforce2_access_virt0(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)36279e9024SJean Delvare static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr,
37279e9024SJean Delvare 				unsigned short flags, char read_write,
38279e9024SJean Delvare 				u8 command, int size,
39279e9024SJean Delvare 				union i2c_smbus_data *data)
40279e9024SJean Delvare {
41279e9024SJean Delvare 	int error;
42279e9024SJean Delvare 
43279e9024SJean Delvare 	/* We exclude the multiplexed addresses */
44279e9024SJean Delvare 	if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
45279e9024SJean Delvare 	 || addr == 0x18)
46279e9024SJean Delvare 		return -ENXIO;
47279e9024SJean Delvare 
48279e9024SJean Delvare 	mutex_lock(&nforce2_lock);
49279e9024SJean Delvare 	error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
50279e9024SJean Delvare 						command, size, data);
51279e9024SJean Delvare 	mutex_unlock(&nforce2_lock);
52279e9024SJean Delvare 
53279e9024SJean Delvare 	return error;
54279e9024SJean Delvare }
55279e9024SJean Delvare 
56279e9024SJean Delvare /* We remember the last used channels combination so as to only switch
57279e9024SJean Delvare    channels when it is really needed. This greatly reduces the SMBus
58279e9024SJean Delvare    overhead, but also assumes that nobody will be writing to the PCA9556
59279e9024SJean Delvare    in our back. */
60279e9024SJean Delvare static u8 last_channels;
61279e9024SJean Delvare 
nforce2_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)62279e9024SJean Delvare static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr,
63279e9024SJean Delvare 					 unsigned short flags, char read_write,
64279e9024SJean Delvare 					 u8 command, int size,
65279e9024SJean Delvare 					 union i2c_smbus_data *data,
66279e9024SJean Delvare 					 u8 channels)
67279e9024SJean Delvare {
68279e9024SJean Delvare 	int error;
69279e9024SJean Delvare 
70279e9024SJean Delvare 	/* We exclude the non-multiplexed addresses */
71279e9024SJean Delvare 	if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
72279e9024SJean Delvare 		return -ENXIO;
73279e9024SJean Delvare 
74279e9024SJean Delvare 	mutex_lock(&nforce2_lock);
75279e9024SJean Delvare 	if (last_channels != channels) {
76279e9024SJean Delvare 		union i2c_smbus_data mplxdata;
77279e9024SJean Delvare 		mplxdata.byte = channels;
78279e9024SJean Delvare 
79279e9024SJean Delvare 		error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0,
80279e9024SJean Delvare 							I2C_SMBUS_WRITE, 0x01,
81279e9024SJean Delvare 							I2C_SMBUS_BYTE_DATA,
82279e9024SJean Delvare 							&mplxdata);
83279e9024SJean Delvare 		if (error)
84279e9024SJean Delvare 			goto UNLOCK;
85279e9024SJean Delvare 		last_channels = channels;
86279e9024SJean Delvare 	}
87279e9024SJean Delvare 	error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write,
88279e9024SJean Delvare 						command, size, data);
89279e9024SJean Delvare 
90279e9024SJean Delvare UNLOCK:
91279e9024SJean Delvare 	mutex_unlock(&nforce2_lock);
92279e9024SJean Delvare 	return error;
93279e9024SJean Delvare }
94279e9024SJean Delvare 
nforce2_access_virt1(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)95279e9024SJean Delvare static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr,
96279e9024SJean Delvare 				unsigned short flags, char read_write,
97279e9024SJean Delvare 				u8 command, int size,
98279e9024SJean Delvare 				union i2c_smbus_data *data)
99279e9024SJean Delvare {
100279e9024SJean Delvare 	/* CPU0: channel 1 enabled */
101279e9024SJean Delvare 	return nforce2_access_channel(adap, addr, flags, read_write, command,
102279e9024SJean Delvare 				      size, data, 0x02);
103279e9024SJean Delvare }
104279e9024SJean Delvare 
nforce2_access_virt2(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)105279e9024SJean Delvare static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr,
106279e9024SJean Delvare 				unsigned short flags, char read_write,
107279e9024SJean Delvare 				u8 command, int size,
108279e9024SJean Delvare 				union i2c_smbus_data *data)
109279e9024SJean Delvare {
110279e9024SJean Delvare 	/* CPU1: channel 2 enabled */
111279e9024SJean Delvare 	return nforce2_access_channel(adap, addr, flags, read_write, command,
112279e9024SJean Delvare 				      size, data, 0x04);
113279e9024SJean Delvare }
114279e9024SJean Delvare 
nforce2_access_virt3(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)115279e9024SJean Delvare static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr,
116279e9024SJean Delvare 				unsigned short flags, char read_write,
117279e9024SJean Delvare 				u8 command, int size,
118279e9024SJean Delvare 				union i2c_smbus_data *data)
119279e9024SJean Delvare {
120279e9024SJean Delvare 	/* CPU2: channel 3 enabled */
121279e9024SJean Delvare 	return nforce2_access_channel(adap, addr, flags, read_write, command,
122279e9024SJean Delvare 				      size, data, 0x08);
123279e9024SJean Delvare }
124279e9024SJean Delvare 
nforce2_access_virt4(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)125279e9024SJean Delvare static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr,
126279e9024SJean Delvare 				unsigned short flags, char read_write,
127279e9024SJean Delvare 				u8 command, int size,
128279e9024SJean Delvare 				union i2c_smbus_data *data)
129279e9024SJean Delvare {
130279e9024SJean Delvare 	/* CPU3: channel 4 enabled */
131279e9024SJean Delvare 	return nforce2_access_channel(adap, addr, flags, read_write, command,
132279e9024SJean Delvare 				      size, data, 0x10);
133279e9024SJean Delvare }
134279e9024SJean Delvare 
nforce2_s4985_init(void)135279e9024SJean Delvare static int __init nforce2_s4985_init(void)
136279e9024SJean Delvare {
137279e9024SJean Delvare 	int i, error;
138279e9024SJean Delvare 	union i2c_smbus_data ioconfig;
139279e9024SJean Delvare 
140399d6b26SJean Delvare 	if (!nforce2_smbus)
141399d6b26SJean Delvare 		return -ENODEV;
142399d6b26SJean Delvare 
143bd4bc3dbSJean Delvare 	/* Configure the PCA9556 multiplexer */
144bd4bc3dbSJean Delvare 	ioconfig.byte = 0x00; /* All I/O to output mode */
145bd4bc3dbSJean Delvare 	error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
146bd4bc3dbSJean Delvare 			       I2C_SMBUS_BYTE_DATA, &ioconfig);
147bd4bc3dbSJean Delvare 	if (error) {
148bd4bc3dbSJean Delvare 		dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n");
149bd4bc3dbSJean Delvare 		error = -EIO;
150bd4bc3dbSJean Delvare 		goto ERROR0;
151bd4bc3dbSJean Delvare 	}
152bd4bc3dbSJean Delvare 
153279e9024SJean Delvare 	/* Unregister physical bus */
154bf51a8c5SLars-Peter Clausen 	i2c_del_adapter(nforce2_smbus);
155279e9024SJean Delvare 
156279e9024SJean Delvare 	printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n");
157279e9024SJean Delvare 	/* Define the 5 virtual adapters and algorithms structures */
1586396bb22SKees Cook 	s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL);
159279e9024SJean Delvare 	if (!s4985_adapter) {
160279e9024SJean Delvare 		error = -ENOMEM;
161279e9024SJean Delvare 		goto ERROR1;
162279e9024SJean Delvare 	}
1636396bb22SKees Cook 	s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL);
164279e9024SJean Delvare 	if (!s4985_algo) {
165279e9024SJean Delvare 		error = -ENOMEM;
166279e9024SJean Delvare 		goto ERROR2;
167279e9024SJean Delvare 	}
168279e9024SJean Delvare 
169279e9024SJean Delvare 	/* Fill in the new structures */
170279e9024SJean Delvare 	s4985_algo[0] = *(nforce2_smbus->algo);
171279e9024SJean Delvare 	s4985_algo[0].smbus_xfer = nforce2_access_virt0;
172279e9024SJean Delvare 	s4985_adapter[0] = *nforce2_smbus;
173279e9024SJean Delvare 	s4985_adapter[0].algo = s4985_algo;
174279e9024SJean Delvare 	s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent;
175279e9024SJean Delvare 	for (i = 1; i < 5; i++) {
176279e9024SJean Delvare 		s4985_algo[i] = *(nforce2_smbus->algo);
177279e9024SJean Delvare 		s4985_adapter[i] = *nforce2_smbus;
178279e9024SJean Delvare 		snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name),
179279e9024SJean Delvare 			 "SMBus nForce2 adapter (CPU%d)", i - 1);
180279e9024SJean Delvare 		s4985_adapter[i].algo = s4985_algo + i;
181279e9024SJean Delvare 		s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent;
182279e9024SJean Delvare 	}
183279e9024SJean Delvare 	s4985_algo[1].smbus_xfer = nforce2_access_virt1;
184279e9024SJean Delvare 	s4985_algo[2].smbus_xfer = nforce2_access_virt2;
185279e9024SJean Delvare 	s4985_algo[3].smbus_xfer = nforce2_access_virt3;
186279e9024SJean Delvare 	s4985_algo[4].smbus_xfer = nforce2_access_virt4;
187279e9024SJean Delvare 
188279e9024SJean Delvare 	/* Register virtual adapters */
189279e9024SJean Delvare 	for (i = 0; i < 5; i++) {
190279e9024SJean Delvare 		error = i2c_add_adapter(s4985_adapter + i);
191279e9024SJean Delvare 		if (error) {
192bd4bc3dbSJean Delvare 			printk(KERN_ERR "i2c-nforce2-s4985: "
193279e9024SJean Delvare 			       "Virtual adapter %d registration "
194279e9024SJean Delvare 			       "failed, module not inserted\n", i);
195279e9024SJean Delvare 			for (i--; i >= 0; i--)
196279e9024SJean Delvare 				i2c_del_adapter(s4985_adapter + i);
197279e9024SJean Delvare 			goto ERROR3;
198279e9024SJean Delvare 		}
199279e9024SJean Delvare 	}
200279e9024SJean Delvare 
201279e9024SJean Delvare 	return 0;
202279e9024SJean Delvare 
203279e9024SJean Delvare ERROR3:
204279e9024SJean Delvare 	kfree(s4985_algo);
205279e9024SJean Delvare 	s4985_algo = NULL;
206279e9024SJean Delvare ERROR2:
207279e9024SJean Delvare 	kfree(s4985_adapter);
208279e9024SJean Delvare 	s4985_adapter = NULL;
209279e9024SJean Delvare ERROR1:
210279e9024SJean Delvare 	/* Restore physical bus */
211279e9024SJean Delvare 	i2c_add_adapter(nforce2_smbus);
212279e9024SJean Delvare ERROR0:
213279e9024SJean Delvare 	return error;
214279e9024SJean Delvare }
215279e9024SJean Delvare 
nforce2_s4985_exit(void)216279e9024SJean Delvare static void __exit nforce2_s4985_exit(void)
217279e9024SJean Delvare {
218279e9024SJean Delvare 	if (s4985_adapter) {
219279e9024SJean Delvare 		int i;
220279e9024SJean Delvare 
221279e9024SJean Delvare 		for (i = 0; i < 5; i++)
222279e9024SJean Delvare 			i2c_del_adapter(s4985_adapter+i);
223279e9024SJean Delvare 		kfree(s4985_adapter);
224279e9024SJean Delvare 		s4985_adapter = NULL;
225279e9024SJean Delvare 	}
226279e9024SJean Delvare 	kfree(s4985_algo);
227279e9024SJean Delvare 	s4985_algo = NULL;
228279e9024SJean Delvare 
229279e9024SJean Delvare 	/* Restore physical bus */
230279e9024SJean Delvare 	if (i2c_add_adapter(nforce2_smbus))
231bd4bc3dbSJean Delvare 		printk(KERN_ERR "i2c-nforce2-s4985: "
232bd4bc3dbSJean Delvare 		       "Physical bus restoration failed\n");
233279e9024SJean Delvare }
234279e9024SJean Delvare 
2357c81c60fSJean Delvare MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
236279e9024SJean Delvare MODULE_DESCRIPTION("S4985 SMBus multiplexing");
237279e9024SJean Delvare MODULE_LICENSE("GPL");
238279e9024SJean Delvare 
239279e9024SJean Delvare module_init(nforce2_s4985_init);
240279e9024SJean Delvare module_exit(nforce2_s4985_exit);
241