linux/drivers/video/fbdev/via/via_i2c.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
   4 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
   5
   6 */
   7
   8#include <linux/platform_device.h>
   9#include <linux/delay.h>
  10#include <linux/spinlock.h>
  11#include <linux/module.h>
  12#include <linux/via-core.h>
  13#include <linux/via_i2c.h>
  14
  15/*
  16 * There can only be one set of these, so there's no point in having
  17 * them be dynamically allocated...
  18 */
  19#define VIAFB_NUM_I2C           5
  20static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C];
  21static struct viafb_dev *i2c_vdev;  /* Passed in from core */
  22
  23static void via_i2c_setscl(void *data, int state)
  24{
  25        u8 val;
  26        struct via_port_cfg *adap_data = data;
  27        unsigned long flags;
  28
  29        spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
  30        val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
  31        if (state)
  32                val |= 0x20;
  33        else
  34                val &= ~0x20;
  35        switch (adap_data->type) {
  36        case VIA_PORT_I2C:
  37                val |= 0x01;
  38                break;
  39        case VIA_PORT_GPIO:
  40                val |= 0x82;
  41                break;
  42        default:
  43                printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
  44        }
  45        via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
  46        spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
  47}
  48
  49static int via_i2c_getscl(void *data)
  50{
  51        struct via_port_cfg *adap_data = data;
  52        unsigned long flags;
  53        int ret = 0;
  54
  55        spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
  56        if (adap_data->type == VIA_PORT_GPIO)
  57                via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
  58                        0, 0x80);
  59        if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08)
  60                ret = 1;
  61        spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
  62        return ret;
  63}
  64
  65static int via_i2c_getsda(void *data)
  66{
  67        struct via_port_cfg *adap_data = data;
  68        unsigned long flags;
  69        int ret = 0;
  70
  71        spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
  72        if (adap_data->type == VIA_PORT_GPIO)
  73                via_write_reg_mask(adap_data->io_port, adap_data->ioport_index,
  74                        0, 0x40);
  75        if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04)
  76                ret = 1;
  77        spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
  78        return ret;
  79}
  80
  81static void via_i2c_setsda(void *data, int state)
  82{
  83        u8 val;
  84        struct via_port_cfg *adap_data = data;
  85        unsigned long flags;
  86
  87        spin_lock_irqsave(&i2c_vdev->reg_lock, flags);
  88        val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0;
  89        if (state)
  90                val |= 0x10;
  91        else
  92                val &= ~0x10;
  93        switch (adap_data->type) {
  94        case VIA_PORT_I2C:
  95                val |= 0x01;
  96                break;
  97        case VIA_PORT_GPIO:
  98                val |= 0x42;
  99                break;
 100        default:
 101                printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n");
 102        }
 103        via_write_reg(adap_data->io_port, adap_data->ioport_index, val);
 104        spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags);
 105}
 106
 107int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata)
 108{
 109        int ret;
 110        u8 mm1[] = {0x00};
 111        struct i2c_msg msgs[2];
 112
 113        if (!via_i2c_par[adap].is_active)
 114                return -ENODEV;
 115        *pdata = 0;
 116        msgs[0].flags = 0;
 117        msgs[1].flags = I2C_M_RD;
 118        msgs[0].addr = msgs[1].addr = slave_addr / 2;
 119        mm1[0] = index;
 120        msgs[0].len = 1; msgs[1].len = 1;
 121        msgs[0].buf = mm1; msgs[1].buf = pdata;
 122        ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
 123        if (ret == 2)
 124                ret = 0;
 125        else if (ret >= 0)
 126                ret = -EIO;
 127
 128        return ret;
 129}
 130
 131int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data)
 132{
 133        int ret;
 134        u8 msg[2] = { index, data };
 135        struct i2c_msg msgs;
 136
 137        if (!via_i2c_par[adap].is_active)
 138                return -ENODEV;
 139        msgs.flags = 0;
 140        msgs.addr = slave_addr / 2;
 141        msgs.len = 2;
 142        msgs.buf = msg;
 143        ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1);
 144        if (ret == 1)
 145                ret = 0;
 146        else if (ret >= 0)
 147                ret = -EIO;
 148
 149        return ret;
 150}
 151
 152int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len)
 153{
 154        int ret;
 155        u8 mm1[] = {0x00};
 156        struct i2c_msg msgs[2];
 157
 158        if (!via_i2c_par[adap].is_active)
 159                return -ENODEV;
 160        msgs[0].flags = 0;
 161        msgs[1].flags = I2C_M_RD;
 162        msgs[0].addr = msgs[1].addr = slave_addr / 2;
 163        mm1[0] = index;
 164        msgs[0].len = 1; msgs[1].len = buff_len;
 165        msgs[0].buf = mm1; msgs[1].buf = buff;
 166        ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2);
 167        if (ret == 2)
 168                ret = 0;
 169        else if (ret >= 0)
 170                ret = -EIO;
 171
 172        return ret;
 173}
 174
 175/*
 176 * Allow other viafb subdevices to look up a specific adapter
 177 * by port name.
 178 */
 179struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which)
 180{
 181        struct via_i2c_stuff *stuff = &via_i2c_par[which];
 182
 183        return &stuff->adapter;
 184}
 185EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter);
 186
 187
 188static int create_i2c_bus(struct i2c_adapter *adapter,
 189                          struct i2c_algo_bit_data *algo,
 190                          struct via_port_cfg *adap_cfg,
 191                          struct pci_dev *pdev)
 192{
 193        algo->setsda = via_i2c_setsda;
 194        algo->setscl = via_i2c_setscl;
 195        algo->getsda = via_i2c_getsda;
 196        algo->getscl = via_i2c_getscl;
 197        algo->udelay = 10;
 198        algo->timeout = 2;
 199        algo->data = adap_cfg;
 200
 201        sprintf(adapter->name, "viafb i2c io_port idx 0x%02x",
 202                adap_cfg->ioport_index);
 203        adapter->owner = THIS_MODULE;
 204        adapter->class = I2C_CLASS_DDC;
 205        adapter->algo_data = algo;
 206        if (pdev)
 207                adapter->dev.parent = &pdev->dev;
 208        else
 209                adapter->dev.parent = NULL;
 210        /* i2c_set_adapdata(adapter, adap_cfg); */
 211
 212        /* Raise SCL and SDA */
 213        via_i2c_setsda(adap_cfg, 1);
 214        via_i2c_setscl(adap_cfg, 1);
 215        udelay(20);
 216
 217        return i2c_bit_add_bus(adapter);
 218}
 219
 220static int viafb_i2c_probe(struct platform_device *platdev)
 221{
 222        int i, ret;
 223        struct via_port_cfg *configs;
 224
 225        i2c_vdev = platdev->dev.platform_data;
 226        configs = i2c_vdev->port_cfg;
 227
 228        for (i = 0; i < VIAFB_NUM_PORTS; i++) {
 229                struct via_port_cfg *adap_cfg = configs++;
 230                struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
 231
 232                i2c_stuff->is_active = 0;
 233                if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C)
 234                        continue;
 235                ret = create_i2c_bus(&i2c_stuff->adapter,
 236                                     &i2c_stuff->algo, adap_cfg,
 237                                NULL); /* FIXME: PCIDEV */
 238                if (ret < 0) {
 239                        printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n",
 240                                i, ret);
 241                        continue;  /* Still try to make the rest */
 242                }
 243                i2c_stuff->is_active = 1;
 244        }
 245
 246        return 0;
 247}
 248
 249static int viafb_i2c_remove(struct platform_device *platdev)
 250{
 251        int i;
 252
 253        for (i = 0; i < VIAFB_NUM_PORTS; i++) {
 254                struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i];
 255                /*
 256                 * Only remove those entries in the array that we've
 257                 * actually used (and thus initialized algo_data)
 258                 */
 259                if (i2c_stuff->is_active)
 260                        i2c_del_adapter(&i2c_stuff->adapter);
 261        }
 262        return 0;
 263}
 264
 265static struct platform_driver via_i2c_driver = {
 266        .driver = {
 267                .name = "viafb-i2c",
 268        },
 269        .probe = viafb_i2c_probe,
 270        .remove = viafb_i2c_remove,
 271};
 272
 273int viafb_i2c_init(void)
 274{
 275        return platform_driver_register(&via_i2c_driver);
 276}
 277
 278void viafb_i2c_exit(void)
 279{
 280        platform_driver_unregister(&via_i2c_driver);
 281}
 282