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