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