linux/drivers/i2c/busses/i2c-amd756-s4882.c
<<
>>
Prefs
   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
  30extern struct i2c_adapter amd756_smbus;
  31
  32static struct i2c_adapter *s4882_adapter;
  33static struct i2c_algorithm *s4882_algo;
  34
  35/* Wrapper access functions for multiplexed SMBus */
  36static DEFINE_MUTEX(amd756_lock);
  37
  38static 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. */
  64static u8 last_channels;
  65
  66static 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
  95UNLOCK:
  96        mutex_unlock(&amd756_lock);
  97        return error;
  98}
  99
 100static 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
 110static 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
 120static 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
 130static 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
 140static 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
 208ERROR3:
 209        kfree(s4882_algo);
 210        s4882_algo = NULL;
 211ERROR2:
 212        kfree(s4882_adapter);
 213        s4882_adapter = NULL;
 214ERROR1:
 215        /* Restore physical bus */
 216        i2c_add_adapter(&amd756_smbus);
 217ERROR0:
 218        return error;
 219}
 220
 221static 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
 240MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 241MODULE_DESCRIPTION("S4882 SMBus multiplexing");
 242MODULE_LICENSE("GPL");
 243
 244module_init(amd756_s4882_init);
 245module_exit(amd756_s4882_exit);
 246