162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Mantis PCI bridge driver
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci*/
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/io.h>
1062306a36Sopenharmony_ci#include <linux/ioport.h>
1162306a36Sopenharmony_ci#include <linux/pci.h>
1262306a36Sopenharmony_ci#include <linux/i2c.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <media/dmxdev.h>
1562306a36Sopenharmony_ci#include <media/dvbdev.h>
1662306a36Sopenharmony_ci#include <media/dvb_demux.h>
1762306a36Sopenharmony_ci#include <media/dvb_frontend.h>
1862306a36Sopenharmony_ci#include <media/dvb_net.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "mantis_common.h"
2162306a36Sopenharmony_ci#include "mantis_reg.h"
2262306a36Sopenharmony_ci#include "mantis_i2c.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define TRIALS			10000
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	u32 rxd, i, stat, trials;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
3162306a36Sopenharmony_ci		__func__, msg->addr);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++) {
3462306a36Sopenharmony_ci		rxd = (msg->addr << 25) | (1 << 24)
3562306a36Sopenharmony_ci					| MANTIS_I2C_RATE_3
3662306a36Sopenharmony_ci					| MANTIS_I2C_STOP
3762306a36Sopenharmony_ci					| MANTIS_I2C_PGMODE;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci		if (i == (msg->len - 1))
4062306a36Sopenharmony_ci			rxd &= ~MANTIS_I2C_STOP;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
4362306a36Sopenharmony_ci		mmwrite(rxd, MANTIS_I2CDATA_CTL);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci		/* wait for xfer completion */
4662306a36Sopenharmony_ci		for (trials = 0; trials < TRIALS; trials++) {
4762306a36Sopenharmony_ci			stat = mmread(MANTIS_INT_STAT);
4862306a36Sopenharmony_ci			if (stat & MANTIS_INT_I2CDONE)
4962306a36Sopenharmony_ci				break;
5062306a36Sopenharmony_ci		}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		/* wait for xfer completion */
5562306a36Sopenharmony_ci		for (trials = 0; trials < TRIALS; trials++) {
5662306a36Sopenharmony_ci			stat = mmread(MANTIS_INT_STAT);
5762306a36Sopenharmony_ci			if (stat & MANTIS_INT_I2CRACK)
5862306a36Sopenharmony_ci				break;
5962306a36Sopenharmony_ci		}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		rxd = mmread(MANTIS_I2CDATA_CTL);
6462306a36Sopenharmony_ci		msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
6562306a36Sopenharmony_ci		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci	dprintk(MANTIS_INFO, 0, "]\n");
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int i;
7562306a36Sopenharmony_ci	u32 txd = 0, stat, trials;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
7862306a36Sopenharmony_ci		__func__, msg->addr);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	for (i = 0; i < msg->len; i++) {
8162306a36Sopenharmony_ci		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
8262306a36Sopenharmony_ci		txd = (msg->addr << 25) | (msg->buf[i] << 8)
8362306a36Sopenharmony_ci					| MANTIS_I2C_RATE_3
8462306a36Sopenharmony_ci					| MANTIS_I2C_STOP
8562306a36Sopenharmony_ci					| MANTIS_I2C_PGMODE;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci		if (i == (msg->len - 1))
8862306a36Sopenharmony_ci			txd &= ~MANTIS_I2C_STOP;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
9162306a36Sopenharmony_ci		mmwrite(txd, MANTIS_I2CDATA_CTL);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		/* wait for xfer completion */
9462306a36Sopenharmony_ci		for (trials = 0; trials < TRIALS; trials++) {
9562306a36Sopenharmony_ci			stat = mmread(MANTIS_INT_STAT);
9662306a36Sopenharmony_ci			if (stat & MANTIS_INT_I2CDONE)
9762306a36Sopenharmony_ci				break;
9862306a36Sopenharmony_ci		}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci		/* wait for xfer completion */
10362306a36Sopenharmony_ci		for (trials = 0; trials < TRIALS; trials++) {
10462306a36Sopenharmony_ci			stat = mmread(MANTIS_INT_STAT);
10562306a36Sopenharmony_ci			if (stat & MANTIS_INT_I2CRACK)
10662306a36Sopenharmony_ci				break;
10762306a36Sopenharmony_ci		}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci	dprintk(MANTIS_INFO, 0, "]\n");
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	int ret = 0, i = 0, trials;
11962306a36Sopenharmony_ci	u32 stat, data, txd;
12062306a36Sopenharmony_ci	struct mantis_pci *mantis;
12162306a36Sopenharmony_ci	struct mantis_hwconfig *config;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	mantis = i2c_get_adapdata(adapter);
12462306a36Sopenharmony_ci	BUG_ON(!mantis);
12562306a36Sopenharmony_ci	config = mantis->hwconfig;
12662306a36Sopenharmony_ci	BUG_ON(!config);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
12962306a36Sopenharmony_ci	mutex_lock(&mantis->i2c_lock);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	while (i < num) {
13262306a36Sopenharmony_ci		/* Byte MODE */
13362306a36Sopenharmony_ci		if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
13462306a36Sopenharmony_ci		    ((i + 1) < num)			&&
13562306a36Sopenharmony_ci		    (msgs[i].len < 2)			&&
13662306a36Sopenharmony_ci		    (msgs[i + 1].len < 2)		&&
13762306a36Sopenharmony_ci		    (msgs[i + 1].flags & I2C_M_RD)) {
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci			/* Read operation */
14262306a36Sopenharmony_ci			txd = msgs[i].addr << 25 | (0x1 << 24)
14362306a36Sopenharmony_ci						 | (msgs[i].buf[0] << 16)
14462306a36Sopenharmony_ci						 | MANTIS_I2C_RATE_3;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci			mmwrite(txd, MANTIS_I2CDATA_CTL);
14762306a36Sopenharmony_ci			/* wait for xfer completion */
14862306a36Sopenharmony_ci			for (trials = 0; trials < TRIALS; trials++) {
14962306a36Sopenharmony_ci				stat = mmread(MANTIS_INT_STAT);
15062306a36Sopenharmony_ci				if (stat & MANTIS_INT_I2CDONE)
15162306a36Sopenharmony_ci					break;
15262306a36Sopenharmony_ci			}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci			/* check for xfer completion */
15562306a36Sopenharmony_ci			if (stat & MANTIS_INT_I2CDONE) {
15662306a36Sopenharmony_ci				/* check xfer was acknowledged */
15762306a36Sopenharmony_ci				if (stat & MANTIS_INT_I2CRACK) {
15862306a36Sopenharmony_ci					data = mmread(MANTIS_I2CDATA_CTL);
15962306a36Sopenharmony_ci					msgs[i + 1].buf[0] = (data >> 8) & 0xff;
16062306a36Sopenharmony_ci					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
16162306a36Sopenharmony_ci				} else {
16262306a36Sopenharmony_ci					/* I/O error */
16362306a36Sopenharmony_ci					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
16462306a36Sopenharmony_ci					ret = -EIO;
16562306a36Sopenharmony_ci					break;
16662306a36Sopenharmony_ci				}
16762306a36Sopenharmony_ci			} else {
16862306a36Sopenharmony_ci				/* I/O error */
16962306a36Sopenharmony_ci				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
17062306a36Sopenharmony_ci				ret = -EIO;
17162306a36Sopenharmony_ci				break;
17262306a36Sopenharmony_ci			}
17362306a36Sopenharmony_ci			i += 2; /* Write/Read operation in one go */
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		if (i < num) {
17762306a36Sopenharmony_ci			if (msgs[i].flags & I2C_M_RD)
17862306a36Sopenharmony_ci				ret = mantis_i2c_read(mantis, &msgs[i]);
17962306a36Sopenharmony_ci			else
18062306a36Sopenharmony_ci				ret = mantis_i2c_write(mantis, &msgs[i]);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci			i++;
18362306a36Sopenharmony_ci			if (ret < 0)
18462306a36Sopenharmony_ci				goto bail_out;
18562306a36Sopenharmony_ci		}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	mutex_unlock(&mantis->i2c_lock);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return num;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cibail_out:
19462306a36Sopenharmony_ci	mutex_unlock(&mantis->i2c_lock);
19562306a36Sopenharmony_ci	return ret;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic u32 mantis_i2c_func(struct i2c_adapter *adapter)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	return I2C_FUNC_SMBUS_EMUL;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic const struct i2c_algorithm mantis_algo = {
20462306a36Sopenharmony_ci	.master_xfer		= mantis_i2c_xfer,
20562306a36Sopenharmony_ci	.functionality		= mantis_i2c_func,
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ciint mantis_i2c_init(struct mantis_pci *mantis)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	u32 intstat;
21162306a36Sopenharmony_ci	struct i2c_adapter *i2c_adapter = &mantis->adapter;
21262306a36Sopenharmony_ci	struct pci_dev *pdev		= mantis->pdev;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	init_waitqueue_head(&mantis->i2c_wq);
21562306a36Sopenharmony_ci	mutex_init(&mantis->i2c_lock);
21662306a36Sopenharmony_ci	strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
21762306a36Sopenharmony_ci	i2c_set_adapdata(i2c_adapter, mantis);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	i2c_adapter->owner	= THIS_MODULE;
22062306a36Sopenharmony_ci	i2c_adapter->algo	= &mantis_algo;
22162306a36Sopenharmony_ci	i2c_adapter->algo_data	= NULL;
22262306a36Sopenharmony_ci	i2c_adapter->timeout	= 500;
22362306a36Sopenharmony_ci	i2c_adapter->retries	= 3;
22462306a36Sopenharmony_ci	i2c_adapter->dev.parent	= &pdev->dev;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter);
22762306a36Sopenharmony_ci	if (mantis->i2c_rc < 0)
22862306a36Sopenharmony_ci		return mantis->i2c_rc;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	intstat = mmread(MANTIS_INT_STAT);
23362306a36Sopenharmony_ci	mmread(MANTIS_INT_MASK);
23462306a36Sopenharmony_ci	mmwrite(intstat, MANTIS_INT_STAT);
23562306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
23662306a36Sopenharmony_ci	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_init);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciint mantis_i2c_exit(struct mantis_pci *mantis)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
24562306a36Sopenharmony_ci	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
24862306a36Sopenharmony_ci	i2c_del_adapter(&mantis->adapter);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	return 0;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mantis_i2c_exit);
253