1a96e5ab8SDaniel Scheller /* 2*22e74389SDaniel Scheller * ddbridge-i2c.c: Digital Devices bridge i2c driver 3a96e5ab8SDaniel Scheller * 4*22e74389SDaniel Scheller * Copyright (C) 2010-2017 Digital Devices GmbH 5*22e74389SDaniel Scheller * Ralph Metzler <rjkm@metzlerbros.de> 6*22e74389SDaniel 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" 35*22e74389SDaniel Scheller #include "ddbridge-regs.h" 36a96e5ab8SDaniel Scheller 37a96e5ab8SDaniel Scheller /******************************************************************************/ 38a96e5ab8SDaniel Scheller 39a96e5ab8SDaniel Scheller static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) 40a96e5ab8SDaniel Scheller { 41a96e5ab8SDaniel Scheller struct ddb *dev = i2c->dev; 42*22e74389SDaniel Scheller unsigned long stat; 43a96e5ab8SDaniel Scheller u32 val; 44a96e5ab8SDaniel Scheller 45*22e74389SDaniel Scheller ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); 46*22e74389SDaniel Scheller stat = wait_for_completion_timeout(&i2c->completion, HZ); 47*22e74389SDaniel Scheller val = ddbreadl(dev, i2c->regs + I2C_COMMAND); 48a96e5ab8SDaniel Scheller if (stat == 0) { 49*22e74389SDaniel Scheller dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", 50*22e74389SDaniel Scheller dev->nr, i2c->nr, i2c->link); 51*22e74389SDaniel Scheller { 52*22e74389SDaniel Scheller u32 istat = ddbreadl(dev, INTERRUPT_STATUS); 53*22e74389SDaniel Scheller 54*22e74389SDaniel Scheller dev_err(dev->dev, "DDBridge IRS %08x\n", istat); 55*22e74389SDaniel Scheller if (i2c->link) { 56*22e74389SDaniel Scheller u32 listat = ddbreadl(dev, 57*22e74389SDaniel Scheller DDB_LINK_TAG(i2c->link) | 58*22e74389SDaniel Scheller INTERRUPT_STATUS); 59*22e74389SDaniel Scheller 60*22e74389SDaniel Scheller dev_err(dev->dev, "DDBridge link %u IRS %08x\n", 61*22e74389SDaniel Scheller i2c->link, listat); 62*22e74389SDaniel Scheller } 63*22e74389SDaniel Scheller if (istat & 1) { 64*22e74389SDaniel Scheller ddbwritel(dev, istat & 1, INTERRUPT_ACK); 65*22e74389SDaniel Scheller } else { 66*22e74389SDaniel Scheller u32 mon = ddbreadl(dev, 67*22e74389SDaniel Scheller i2c->regs + I2C_MONITOR); 68*22e74389SDaniel Scheller 69*22e74389SDaniel Scheller dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", 70*22e74389SDaniel Scheller val, mon); 71*22e74389SDaniel Scheller } 72a96e5ab8SDaniel Scheller } 73a96e5ab8SDaniel Scheller return -EIO; 74a96e5ab8SDaniel Scheller } 75a96e5ab8SDaniel Scheller if (val & 0x70000) 76a96e5ab8SDaniel Scheller return -EIO; 77a96e5ab8SDaniel Scheller return 0; 78a96e5ab8SDaniel Scheller } 79a96e5ab8SDaniel Scheller 80a96e5ab8SDaniel Scheller static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, 81a96e5ab8SDaniel Scheller struct i2c_msg msg[], int num) 82a96e5ab8SDaniel Scheller { 83a96e5ab8SDaniel Scheller struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter); 84a96e5ab8SDaniel Scheller struct ddb *dev = i2c->dev; 85a96e5ab8SDaniel Scheller u8 addr = 0; 86a96e5ab8SDaniel Scheller 87a96e5ab8SDaniel Scheller addr = msg[0].addr; 88*22e74389SDaniel Scheller if (msg[0].len > i2c->bsize) 89*22e74389SDaniel Scheller return -EIO; 90*22e74389SDaniel Scheller switch (num) { 91*22e74389SDaniel Scheller case 1: 92*22e74389SDaniel Scheller if (msg[0].flags & I2C_M_RD) { 93*22e74389SDaniel Scheller ddbwritel(dev, msg[0].len << 16, 94a96e5ab8SDaniel Scheller i2c->regs + I2C_TASKLENGTH); 95*22e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 3)) 96*22e74389SDaniel Scheller break; 97*22e74389SDaniel Scheller ddbcpyfrom(dev, msg[0].buf, 98*22e74389SDaniel Scheller i2c->rbuf, msg[0].len); 99*22e74389SDaniel Scheller return num; 100*22e74389SDaniel Scheller } 101*22e74389SDaniel Scheller ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); 102*22e74389SDaniel Scheller ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); 103*22e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 2)) 104*22e74389SDaniel Scheller break; 105*22e74389SDaniel Scheller return num; 106*22e74389SDaniel Scheller case 2: 107*22e74389SDaniel Scheller if ((msg[0].flags & I2C_M_RD) == I2C_M_RD) 108*22e74389SDaniel Scheller break; 109*22e74389SDaniel Scheller if ((msg[1].flags & I2C_M_RD) != I2C_M_RD) 110*22e74389SDaniel Scheller break; 111*22e74389SDaniel Scheller if (msg[1].len > i2c->bsize) 112*22e74389SDaniel Scheller break; 113*22e74389SDaniel Scheller ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len); 114*22e74389SDaniel Scheller ddbwritel(dev, msg[0].len | (msg[1].len << 16), 115*22e74389SDaniel Scheller i2c->regs + I2C_TASKLENGTH); 116*22e74389SDaniel Scheller if (ddb_i2c_cmd(i2c, addr, 1)) 117*22e74389SDaniel Scheller break; 118*22e74389SDaniel Scheller ddbcpyfrom(dev, msg[1].buf, 119*22e74389SDaniel Scheller i2c->rbuf, 120a96e5ab8SDaniel Scheller msg[1].len); 121a96e5ab8SDaniel Scheller return num; 122*22e74389SDaniel Scheller default: 123*22e74389SDaniel Scheller break; 124a96e5ab8SDaniel Scheller } 125a96e5ab8SDaniel Scheller return -EIO; 126a96e5ab8SDaniel Scheller } 127a96e5ab8SDaniel Scheller 128a96e5ab8SDaniel Scheller static u32 ddb_i2c_functionality(struct i2c_adapter *adap) 129a96e5ab8SDaniel Scheller { 130*22e74389SDaniel Scheller return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 131a96e5ab8SDaniel Scheller } 132a96e5ab8SDaniel Scheller 133a96e5ab8SDaniel Scheller static const struct i2c_algorithm ddb_i2c_algo = { 134a96e5ab8SDaniel Scheller .master_xfer = ddb_i2c_master_xfer, 135a96e5ab8SDaniel Scheller .functionality = ddb_i2c_functionality, 136a96e5ab8SDaniel Scheller }; 137a96e5ab8SDaniel Scheller 138a96e5ab8SDaniel Scheller void ddb_i2c_release(struct ddb *dev) 139a96e5ab8SDaniel Scheller { 140a96e5ab8SDaniel Scheller int i; 141a96e5ab8SDaniel Scheller struct ddb_i2c *i2c; 142a96e5ab8SDaniel Scheller 143*22e74389SDaniel Scheller for (i = 0; i < dev->i2c_num; i++) { 144a96e5ab8SDaniel Scheller i2c = &dev->i2c[i]; 145*22e74389SDaniel Scheller i2c_del_adapter(&i2c->adap); 146a96e5ab8SDaniel Scheller } 147a96e5ab8SDaniel Scheller } 148a96e5ab8SDaniel Scheller 149*22e74389SDaniel Scheller static void i2c_handler(unsigned long priv) 150a96e5ab8SDaniel Scheller { 151*22e74389SDaniel Scheller struct ddb_i2c *i2c = (struct ddb_i2c *) priv; 152*22e74389SDaniel Scheller 153*22e74389SDaniel Scheller complete(&i2c->completion); 154*22e74389SDaniel Scheller } 155*22e74389SDaniel Scheller 156*22e74389SDaniel Scheller static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c, 157*22e74389SDaniel Scheller struct ddb_regmap *regmap, int link, int i, int num) 158*22e74389SDaniel Scheller { 159a96e5ab8SDaniel Scheller struct i2c_adapter *adap; 160a96e5ab8SDaniel Scheller 161a96e5ab8SDaniel Scheller i2c->nr = i; 162*22e74389SDaniel Scheller i2c->dev = dev; 163*22e74389SDaniel Scheller i2c->link = link; 164*22e74389SDaniel Scheller i2c->bsize = regmap->i2c_buf->size; 165*22e74389SDaniel Scheller i2c->wbuf = DDB_LINK_TAG(link) | 166*22e74389SDaniel Scheller (regmap->i2c_buf->base + i2c->bsize * i); 167*22e74389SDaniel Scheller i2c->rbuf = i2c->wbuf; /* + i2c->bsize / 2 */ 168*22e74389SDaniel Scheller i2c->regs = DDB_LINK_TAG(link) | 169*22e74389SDaniel Scheller (regmap->i2c->base + regmap->i2c->size * i); 170*22e74389SDaniel Scheller ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); 171*22e74389SDaniel Scheller ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff), 172a96e5ab8SDaniel Scheller i2c->regs + I2C_TASKADDRESS); 173*22e74389SDaniel Scheller init_completion(&i2c->completion); 174a96e5ab8SDaniel Scheller 175a96e5ab8SDaniel Scheller adap = &i2c->adap; 176a96e5ab8SDaniel Scheller i2c_set_adapdata(adap, i2c); 177a96e5ab8SDaniel Scheller #ifdef I2C_ADAP_CLASS_TV_DIGITAL 178a96e5ab8SDaniel Scheller adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG; 179a96e5ab8SDaniel Scheller #else 180a96e5ab8SDaniel Scheller #ifdef I2C_CLASS_TV_ANALOG 181a96e5ab8SDaniel Scheller adap->class = I2C_CLASS_TV_ANALOG; 182a96e5ab8SDaniel Scheller #endif 183a96e5ab8SDaniel Scheller #endif 184*22e74389SDaniel Scheller snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x", 185*22e74389SDaniel Scheller dev->nr, i2c->link, i); 186a96e5ab8SDaniel Scheller adap->algo = &ddb_i2c_algo; 187a96e5ab8SDaniel Scheller adap->algo_data = (void *)i2c; 188*22e74389SDaniel Scheller adap->dev.parent = dev->dev; 189*22e74389SDaniel Scheller return i2c_add_adapter(adap); 190*22e74389SDaniel Scheller } 191*22e74389SDaniel Scheller 192*22e74389SDaniel Scheller int ddb_i2c_init(struct ddb *dev) 193*22e74389SDaniel Scheller { 194*22e74389SDaniel Scheller int stat = 0; 195*22e74389SDaniel Scheller u32 i, j, num = 0, l, base; 196*22e74389SDaniel Scheller struct ddb_i2c *i2c; 197*22e74389SDaniel Scheller struct i2c_adapter *adap; 198*22e74389SDaniel Scheller struct ddb_regmap *regmap; 199*22e74389SDaniel Scheller 200*22e74389SDaniel Scheller for (l = 0; l < DDB_MAX_LINK; l++) { 201*22e74389SDaniel Scheller if (!dev->link[l].info) 202*22e74389SDaniel Scheller continue; 203*22e74389SDaniel Scheller regmap = dev->link[l].info->regmap; 204*22e74389SDaniel Scheller if (!regmap || !regmap->i2c) 205*22e74389SDaniel Scheller continue; 206*22e74389SDaniel Scheller base = regmap->irq_base_i2c; 207*22e74389SDaniel Scheller for (i = 0; i < regmap->i2c->num; i++) { 208*22e74389SDaniel Scheller if (!(dev->link[l].info->i2c_mask & (1 << i))) 209*22e74389SDaniel Scheller continue; 210*22e74389SDaniel Scheller i2c = &dev->i2c[num]; 211*22e74389SDaniel Scheller dev->handler_data[l][i + base] = (unsigned long) i2c; 212*22e74389SDaniel Scheller dev->handler[l][i + base] = i2c_handler; 213*22e74389SDaniel Scheller stat = ddb_i2c_add(dev, i2c, regmap, l, i, num); 214a96e5ab8SDaniel Scheller if (stat) 215a96e5ab8SDaniel Scheller break; 216*22e74389SDaniel Scheller num++; 217a96e5ab8SDaniel Scheller } 218*22e74389SDaniel Scheller } 219*22e74389SDaniel Scheller if (stat) { 220*22e74389SDaniel Scheller for (j = 0; j < num; j++) { 221a96e5ab8SDaniel Scheller i2c = &dev->i2c[j]; 222a96e5ab8SDaniel Scheller adap = &i2c->adap; 223a96e5ab8SDaniel Scheller i2c_del_adapter(adap); 224a96e5ab8SDaniel Scheller } 225*22e74389SDaniel Scheller } else 226*22e74389SDaniel Scheller dev->i2c_num = num; 227a96e5ab8SDaniel Scheller return stat; 228a96e5ab8SDaniel Scheller } 229