1a96e5ab8SDaniel Scheller /* 222e74389SDaniel Scheller * ddbridge-i2c.c: Digital Devices bridge i2c driver 3a96e5ab8SDaniel Scheller * 422e74389SDaniel Scheller * Copyright (C) 2010-2017 Digital Devices GmbH 522e74389SDaniel Scheller * Ralph Metzler <rjkm@metzlerbros.de> 622e74389SDaniel Scheller * Marcus Metzler <mocm@metzlerbros.de> 7a96e5ab8SDaniel Scheller * 8a96e5ab8SDaniel Scheller * This program is free software; you can redistribute it and/or 9a96e5ab8SDaniel Scheller * modify it under the terms of the GNU General Public License 10a96e5ab8SDaniel Scheller * version 2 only, as published by the Free Software Foundation. 11a96e5ab8SDaniel Scheller * 12a96e5ab8SDaniel Scheller * This program is distributed in the hope that it will be useful, 13a96e5ab8SDaniel Scheller * but WITHOUT ANY WARRANTY; without even the implied warranty of 14a96e5ab8SDaniel Scheller * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15a96e5ab8SDaniel Scheller * GNU General Public License for more details. 16a96e5ab8SDaniel Scheller * 17a96e5ab8SDaniel Scheller */ 18a96e5ab8SDaniel Scheller 19a96e5ab8SDaniel Scheller #include <linux/module.h> 20a96e5ab8SDaniel Scheller #include <linux/init.h> 21a96e5ab8SDaniel Scheller #include <linux/interrupt.h> 22a96e5ab8SDaniel Scheller #include <linux/delay.h> 23a96e5ab8SDaniel Scheller #include <linux/slab.h> 24a96e5ab8SDaniel Scheller #include <linux/poll.h> 25a96e5ab8SDaniel Scheller #include <linux/io.h> 26a96e5ab8SDaniel Scheller #include <linux/pci.h> 27a96e5ab8SDaniel Scheller #include <linux/pci_ids.h> 28a96e5ab8SDaniel Scheller #include <linux/timer.h> 29a96e5ab8SDaniel Scheller #include <linux/i2c.h> 30a96e5ab8SDaniel Scheller #include <linux/swab.h> 31a96e5ab8SDaniel Scheller #include <linux/vmalloc.h> 32a96e5ab8SDaniel Scheller 33a96e5ab8SDaniel Scheller #include "ddbridge.h" 34a96e5ab8SDaniel Scheller #include "ddbridge-i2c.h" 3522e74389SDaniel Scheller #include "ddbridge-regs.h" 3614e27a10SDaniel Scheller #include "ddbridge-io.h" 37a96e5ab8SDaniel Scheller 38a96e5ab8SDaniel Scheller /******************************************************************************/ 39a96e5ab8SDaniel Scheller 40a96e5ab8SDaniel Scheller static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) 41a96e5ab8SDaniel Scheller { 42a96e5ab8SDaniel Scheller struct ddb *dev = i2c->dev; 4322e74389SDaniel Scheller unsigned long stat; 44a96e5ab8SDaniel Scheller u32 val; 45a96e5ab8SDaniel Scheller 4622e74389SDaniel Scheller ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); 4722e74389SDaniel Scheller stat = wait_for_completion_timeout(&i2c->completion, HZ); 4822e74389SDaniel Scheller val = ddbreadl(dev, i2c->regs + I2C_COMMAND); 49a96e5ab8SDaniel Scheller if (stat == 0) { 5022e74389SDaniel Scheller dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", 5122e74389SDaniel Scheller dev->nr, i2c->nr, i2c->link); 5222e74389SDaniel Scheller { 5322e74389SDaniel Scheller u32 istat = ddbreadl(dev, INTERRUPT_STATUS); 5422e74389SDaniel Scheller 5522e74389SDaniel Scheller dev_err(dev->dev, "DDBridge IRS %08x\n", istat); 5622e74389SDaniel Scheller if (i2c->link) { 5722e74389SDaniel Scheller u32 listat = ddbreadl(dev, 5822e74389SDaniel Scheller DDB_LINK_TAG(i2c->link) | 5922e74389SDaniel Scheller INTERRUPT_STATUS); 6022e74389SDaniel Scheller 6122e74389SDaniel Scheller dev_err(dev->dev, "DDBridge link %u IRS %08x\n", 6222e74389SDaniel Scheller i2c->link, listat); 6322e74389SDaniel Scheller } 6422e74389SDaniel Scheller if (istat & 1) { 6522e74389SDaniel Scheller ddbwritel(dev, istat & 1, INTERRUPT_ACK); 6622e74389SDaniel Scheller } else { 6722e74389SDaniel Scheller u32 mon = ddbreadl(dev, 6822e74389SDaniel Scheller i2c->regs + I2C_MONITOR); 6922e74389SDaniel Scheller 7022e74389SDaniel Scheller dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", 7122e74389SDaniel Scheller val, mon); 7222e74389SDaniel Scheller } 73a96e5ab8SDaniel Scheller } 74a96e5ab8SDaniel Scheller return -EIO; 75a96e5ab8SDaniel Scheller } 76a96e5ab8SDaniel Scheller if (val & 0x70000) 77a96e5ab8SDaniel Scheller return -EIO; 78a96e5ab8SDaniel Scheller return 0; 79a96e5ab8SDaniel Scheller } 80a96e5ab8SDaniel Scheller 81a96e5ab8SDaniel Scheller static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, 82a96e5ab8SDaniel Scheller struct i2c_msg msg[], int num) 83a96e5ab8SDaniel Scheller { 84a96e5ab8SDaniel Scheller struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); 85a96e5ab8SDaniel Scheller struct ddb *dev = i2c->dev; 86a96e5ab8SDaniel Scheller u8 addr = 0; 87a96e5ab8SDaniel Scheller 88a96e5ab8SDaniel Scheller addr = msg[0].addr; 8922e74389SDaniel Scheller if (msg[0].len > i2c->bsize) 9022e74389SDaniel Scheller return -EIO; 9122e74389SDaniel Scheller switch (num) { 9222e74389SDaniel Scheller case 1: 9322e74389SDaniel Scheller if (msg[0].flags & I2C_M_RD) { 9422e74389SDaniel Scheller ddbwritel(dev, msg[0].len << 16, 95a96e5ab8SDaniel Scheller i2c->regs + I2C_TASKLENGTH); 9622e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 3)) 9722e74389SDaniel Scheller break; 9822e74389SDaniel Scheller ddbcpyfrom(dev, msg[0].buf, 9922e74389SDaniel Scheller i2c->rbuf, msg[0].len); 10022e74389SDaniel Scheller return num; 10122e74389SDaniel Scheller } 10222e74389SDaniel Scheller ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); 10322e74389SDaniel Scheller ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); 10422e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 2)) 10522e74389SDaniel Scheller break; 10622e74389SDaniel Scheller return num; 10722e74389SDaniel Scheller case 2: 10822e74389SDaniel Scheller if ((msg[0].flags & I2C_M_RD) == I2C_M_RD) 10922e74389SDaniel Scheller break; 11022e74389SDaniel Scheller if ((msg[1].flags & I2C_M_RD) != I2C_M_RD) 11122e74389SDaniel Scheller break; 11222e74389SDaniel Scheller if (msg[1].len > i2c->bsize) 11322e74389SDaniel Scheller break; 11422e74389SDaniel Scheller ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); 11522e74389SDaniel Scheller ddbwritel(dev, msg[0].len | (msg[1].len << 16), 11622e74389SDaniel Scheller i2c->regs + I2C_TASKLENGTH); 11722e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 1)) 11822e74389SDaniel Scheller break; 11922e74389SDaniel Scheller ddbcpyfrom(dev, msg[1].buf, 12022e74389SDaniel Scheller i2c->rbuf, 121a96e5ab8SDaniel Scheller msg[1].len); 122a96e5ab8SDaniel Scheller return num; 12322e74389SDaniel Scheller default: 12422e74389SDaniel Scheller break; 125a96e5ab8SDaniel Scheller } 126a96e5ab8SDaniel Scheller return -EIO; 127a96e5ab8SDaniel Scheller } 128a96e5ab8SDaniel Scheller 129a96e5ab8SDaniel Scheller static u32 ddb_i2c_functionality(struct i2c_adapter *adap) 130a96e5ab8SDaniel Scheller { 13122e74389SDaniel Scheller return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 132a96e5ab8SDaniel Scheller } 133a96e5ab8SDaniel Scheller 134a96e5ab8SDaniel Scheller static const struct i2c_algorithm ddb_i2c_algo = { 135a96e5ab8SDaniel Scheller .master_xfer = ddb_i2c_master_xfer, 136a96e5ab8SDaniel Scheller .functionality = ddb_i2c_functionality, 137a96e5ab8SDaniel Scheller }; 138a96e5ab8SDaniel Scheller 139a96e5ab8SDaniel Scheller void ddb_i2c_release(struct ddb *dev) 140a96e5ab8SDaniel Scheller { 141a96e5ab8SDaniel Scheller int i; 142a96e5ab8SDaniel Scheller struct ddb_i2c *i2c; 143a96e5ab8SDaniel Scheller 14422e74389SDaniel Scheller for (i = 0; i < dev->i2c_num; i++) { 145a96e5ab8SDaniel Scheller i2c = &dev->i2c[i]; 14622e74389SDaniel Scheller i2c_del_adapter(&i2c->adap); 147a96e5ab8SDaniel Scheller } 148a96e5ab8SDaniel Scheller } 149a96e5ab8SDaniel Scheller 150*1dda87acSDaniel Scheller static void i2c_handler(void *priv) 151a96e5ab8SDaniel Scheller { 15222e74389SDaniel Scheller struct ddb_i2c *i2c = (struct ddb_i2c *)priv; 15322e74389SDaniel Scheller 15422e74389SDaniel Scheller complete(&i2c->completion); 15522e74389SDaniel Scheller } 15622e74389SDaniel Scheller 15722e74389SDaniel Scheller static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c, 1580937e7e7SDaniel Scheller const struct ddb_regmap *regmap, int link, 1590937e7e7SDaniel Scheller int i, int num) 16022e74389SDaniel Scheller { 161a96e5ab8SDaniel Scheller struct i2c_adapter *adap; 162a96e5ab8SDaniel Scheller 163a96e5ab8SDaniel Scheller i2c->nr = i; 16422e74389SDaniel Scheller i2c->dev = dev; 16522e74389SDaniel Scheller i2c->link = link; 16622e74389SDaniel Scheller i2c->bsize = regmap->i2c_buf->size; 16722e74389SDaniel Scheller i2c->wbuf = DDB_LINK_TAG(link) | 16822e74389SDaniel Scheller (regmap->i2c_buf->base + i2c->bsize * i); 16922e74389SDaniel Scheller i2c->rbuf = i2c->wbuf; /* + i2c->bsize / 2 */ 17022e74389SDaniel Scheller i2c->regs = DDB_LINK_TAG(link) | 17122e74389SDaniel Scheller (regmap->i2c->base + regmap->i2c->size * i); 17222e74389SDaniel Scheller ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); 17322e74389SDaniel Scheller ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff), 174a96e5ab8SDaniel Scheller i2c->regs + I2C_TASKADDRESS); 17522e74389SDaniel Scheller init_completion(&i2c->completion); 176a96e5ab8SDaniel Scheller 177a96e5ab8SDaniel Scheller adap = &i2c->adap; 178a96e5ab8SDaniel Scheller i2c_set_adapdata(adap, i2c); 179a96e5ab8SDaniel Scheller #ifdef I2C_ADAP_CLASS_TV_DIGITAL 180a96e5ab8SDaniel Scheller adap->class = I2C_ADAP_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG; 181a96e5ab8SDaniel Scheller #else 182a96e5ab8SDaniel Scheller #ifdef I2C_CLASS_TV_ANALOG 183a96e5ab8SDaniel Scheller adap->class = I2C_CLASS_TV_ANALOG; 184a96e5ab8SDaniel Scheller #endif 185a96e5ab8SDaniel Scheller #endif 18622e74389SDaniel Scheller snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x", 18722e74389SDaniel Scheller dev->nr, i2c->link, i); 188a96e5ab8SDaniel Scheller adap->algo = &ddb_i2c_algo; 189a96e5ab8SDaniel Scheller adap->algo_data = (void *)i2c; 19022e74389SDaniel Scheller adap->dev.parent = dev->dev; 19122e74389SDaniel Scheller return i2c_add_adapter(adap); 19222e74389SDaniel Scheller } 19322e74389SDaniel Scheller 19422e74389SDaniel Scheller int ddb_i2c_init(struct ddb *dev) 19522e74389SDaniel Scheller { 19622e74389SDaniel Scheller int stat = 0; 19722e74389SDaniel Scheller u32 i, j, num = 0, l, base; 19822e74389SDaniel Scheller struct ddb_i2c *i2c; 19922e74389SDaniel Scheller struct i2c_adapter *adap; 2000937e7e7SDaniel Scheller const struct ddb_regmap *regmap; 20122e74389SDaniel Scheller 20222e74389SDaniel Scheller for (l = 0; l < DDB_MAX_LINK; l++) { 20322e74389SDaniel Scheller if (!dev->link[l].info) 20422e74389SDaniel Scheller continue; 20522e74389SDaniel Scheller regmap = dev->link[l].info->regmap; 20622e74389SDaniel Scheller if (!regmap || !regmap->i2c) 20722e74389SDaniel Scheller continue; 20822e74389SDaniel Scheller base = regmap->irq_base_i2c; 20922e74389SDaniel Scheller for (i = 0; i < regmap->i2c->num; i++) { 21022e74389SDaniel Scheller if (!(dev->link[l].info->i2c_mask & (1 << i))) 21122e74389SDaniel Scheller continue; 21222e74389SDaniel Scheller i2c = &dev->i2c[num]; 213*1dda87acSDaniel Scheller ddb_irq_set(dev, l, i + base, i2c_handler, i2c); 21422e74389SDaniel Scheller stat = ddb_i2c_add(dev, i2c, regmap, l, i, num); 215a96e5ab8SDaniel Scheller if (stat) 216a96e5ab8SDaniel Scheller break; 21722e74389SDaniel Scheller num++; 218a96e5ab8SDaniel Scheller } 21922e74389SDaniel Scheller } 22022e74389SDaniel Scheller if (stat) { 22122e74389SDaniel Scheller for (j = 0; j < num; j++) { 222a96e5ab8SDaniel Scheller i2c = &dev->i2c[j]; 223a96e5ab8SDaniel Scheller adap = &i2c->adap; 224a96e5ab8SDaniel Scheller i2c_del_adapter(adap); 225a96e5ab8SDaniel Scheller } 226757d78d3SDaniel Scheller } else { 22722e74389SDaniel Scheller dev->i2c_num = num; 228757d78d3SDaniel Scheller } 229757d78d3SDaniel Scheller 230a96e5ab8SDaniel Scheller return stat; 231a96e5ab8SDaniel Scheller } 232