Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
0004  *
0005  * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de>
0006  */
0007  
0008 /*
0009  * We select the channels by sending commands to the Philips
0010  * PCA9556 chip at I2C address 0x18. The main adapter is used for
0011  * the non-multiplexed part of the bus, and 4 virtual adapters
0012  * are defined for the multiplexed addresses: 0x50-0x53 (memory
0013  * module EEPROM) located on channels 1-4, and 0x4c (LM63)
0014  * located on multiplexed channels 0 and 5-7. We define one
0015  * virtual adapter per CPU, which corresponds to two multiplexed
0016  * channels:
0017  *   CPU0: virtual adapter 1, channels 1 and 0
0018  *   CPU1: virtual adapter 2, channels 2 and 5
0019  *   CPU2: virtual adapter 3, channels 3 and 6
0020  *   CPU3: virtual adapter 4, channels 4 and 7
0021  */
0022 
0023 #include <linux/module.h>
0024 #include <linux/kernel.h>
0025 #include <linux/slab.h>
0026 #include <linux/init.h>
0027 #include <linux/i2c.h>
0028 #include <linux/mutex.h>
0029 
0030 extern struct i2c_adapter amd756_smbus;
0031 
0032 static struct i2c_adapter *s4882_adapter;
0033 static struct i2c_algorithm *s4882_algo;
0034 
0035 /* Wrapper access functions for multiplexed SMBus */
0036 static DEFINE_MUTEX(amd756_lock);
0037 
0038 static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr,
0039                    unsigned short flags, char read_write,
0040                    u8 command, int size,
0041                    union i2c_smbus_data * data)
0042 {
0043     int error;
0044 
0045     /* We exclude the multiplexed addresses */
0046     if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30
0047      || addr == 0x18)
0048         return -ENXIO;
0049 
0050     mutex_lock(&amd756_lock);
0051 
0052     error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
0053                           command, size, data);
0054 
0055     mutex_unlock(&amd756_lock);
0056 
0057     return error;
0058 }
0059 
0060 /* We remember the last used channels combination so as to only switch
0061    channels when it is really needed. This greatly reduces the SMBus
0062    overhead, but also assumes that nobody will be writing to the PCA9556
0063    in our back. */
0064 static u8 last_channels;
0065 
0066 static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr,
0067                     unsigned short flags, char read_write,
0068                     u8 command, int size,
0069                     union i2c_smbus_data * data,
0070                     u8 channels)
0071 {
0072     int error;
0073 
0074     /* We exclude the non-multiplexed addresses */
0075     if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30)
0076         return -ENXIO;
0077 
0078     mutex_lock(&amd756_lock);
0079 
0080     if (last_channels != channels) {
0081         union i2c_smbus_data mplxdata;
0082         mplxdata.byte = channels;
0083 
0084         error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0,
0085                               I2C_SMBUS_WRITE, 0x01,
0086                               I2C_SMBUS_BYTE_DATA,
0087                               &mplxdata);
0088         if (error)
0089             goto UNLOCK;
0090         last_channels = channels;
0091     }
0092     error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write,
0093                           command, size, data);
0094 
0095 UNLOCK:
0096     mutex_unlock(&amd756_lock);
0097     return error;
0098 }
0099 
0100 static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr,
0101                    unsigned short flags, char read_write,
0102                    u8 command, int size,
0103                    union i2c_smbus_data * data)
0104 {
0105     /* CPU0: channels 1 and 0 enabled */
0106     return amd756_access_channel(adap, addr, flags, read_write, command,
0107                      size, data, 0x03);
0108 }
0109 
0110 static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr,
0111                    unsigned short flags, char read_write,
0112                    u8 command, int size,
0113                    union i2c_smbus_data * data)
0114 {
0115     /* CPU1: channels 2 and 5 enabled */
0116     return amd756_access_channel(adap, addr, flags, read_write, command,
0117                      size, data, 0x24);
0118 }
0119 
0120 static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr,
0121                    unsigned short flags, char read_write,
0122                    u8 command, int size,
0123                    union i2c_smbus_data * data)
0124 {
0125     /* CPU2: channels 3 and 6 enabled */
0126     return amd756_access_channel(adap, addr, flags, read_write, command,
0127                      size, data, 0x48);
0128 }
0129 
0130 static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr,
0131                    unsigned short flags, char read_write,
0132                    u8 command, int size,
0133                    union i2c_smbus_data * data)
0134 {
0135     /* CPU3: channels 4 and 7 enabled */
0136     return amd756_access_channel(adap, addr, flags, read_write, command,
0137                      size, data, 0x90);
0138 }
0139 
0140 static int __init amd756_s4882_init(void)
0141 {
0142     int i, error;
0143     union i2c_smbus_data ioconfig;
0144 
0145     if (!amd756_smbus.dev.parent)
0146         return -ENODEV;
0147 
0148     /* Configure the PCA9556 multiplexer */
0149     ioconfig.byte = 0x00; /* All I/O to output mode */
0150     error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03,
0151                    I2C_SMBUS_BYTE_DATA, &ioconfig);
0152     if (error) {
0153         dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n");
0154         error = -EIO;
0155         goto ERROR0;
0156     }
0157 
0158     /* Unregister physical bus */
0159     i2c_del_adapter(&amd756_smbus);
0160 
0161     printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n");
0162     /* Define the 5 virtual adapters and algorithms structures */
0163     if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter),
0164                       GFP_KERNEL))) {
0165         error = -ENOMEM;
0166         goto ERROR1;
0167     }
0168     if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm),
0169                    GFP_KERNEL))) {
0170         error = -ENOMEM;
0171         goto ERROR2;
0172     }
0173 
0174     /* Fill in the new structures */
0175     s4882_algo[0] = *(amd756_smbus.algo);
0176     s4882_algo[0].smbus_xfer = amd756_access_virt0;
0177     s4882_adapter[0] = amd756_smbus;
0178     s4882_adapter[0].algo = s4882_algo;
0179     s4882_adapter[0].dev.parent = amd756_smbus.dev.parent;
0180     for (i = 1; i < 5; i++) {
0181         s4882_algo[i] = *(amd756_smbus.algo);
0182         s4882_adapter[i] = amd756_smbus;
0183         snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name),
0184              "SMBus 8111 adapter (CPU%d)", i-1);
0185         s4882_adapter[i].algo = s4882_algo+i;
0186         s4882_adapter[i].dev.parent = amd756_smbus.dev.parent;
0187     }
0188     s4882_algo[1].smbus_xfer = amd756_access_virt1;
0189     s4882_algo[2].smbus_xfer = amd756_access_virt2;
0190     s4882_algo[3].smbus_xfer = amd756_access_virt3;
0191     s4882_algo[4].smbus_xfer = amd756_access_virt4;
0192 
0193     /* Register virtual adapters */
0194     for (i = 0; i < 5; i++) {
0195         error = i2c_add_adapter(s4882_adapter+i);
0196         if (error) {
0197             printk(KERN_ERR "i2c-amd756-s4882: "
0198                    "Virtual adapter %d registration "
0199                    "failed, module not inserted\n", i);
0200             for (i--; i >= 0; i--)
0201                 i2c_del_adapter(s4882_adapter+i);
0202             goto ERROR3;
0203         }
0204     }
0205 
0206     return 0;
0207 
0208 ERROR3:
0209     kfree(s4882_algo);
0210     s4882_algo = NULL;
0211 ERROR2:
0212     kfree(s4882_adapter);
0213     s4882_adapter = NULL;
0214 ERROR1:
0215     /* Restore physical bus */
0216     i2c_add_adapter(&amd756_smbus);
0217 ERROR0:
0218     return error;
0219 }
0220 
0221 static void __exit amd756_s4882_exit(void)
0222 {
0223     if (s4882_adapter) {
0224         int i;
0225 
0226         for (i = 0; i < 5; i++)
0227             i2c_del_adapter(s4882_adapter+i);
0228         kfree(s4882_adapter);
0229         s4882_adapter = NULL;
0230     }
0231     kfree(s4882_algo);
0232     s4882_algo = NULL;
0233 
0234     /* Restore physical bus */
0235     if (i2c_add_adapter(&amd756_smbus))
0236         printk(KERN_ERR "i2c-amd756-s4882: "
0237                "Physical bus restoration failed\n");
0238 }
0239 
0240 MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
0241 MODULE_DESCRIPTION("S4882 SMBus multiplexing");
0242 MODULE_LICENSE("GPL");
0243 
0244 module_init(amd756_s4882_init);
0245 module_exit(amd756_s4882_exit);