via_i2c.c (6588B)
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}