mantis_i2c.c 6.5 KB
Newer Older
1 2 3
/*
	Mantis PCI bridge driver

4
	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <asm/io.h>
#include <linux/ioport.h>
23 24 25 26 27 28 29 30 31
#include <linux/pci.h>
#include <linux/i2c.h>

#include "dmxdev.h"
#include "dvbdev.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "dvb_net.h"

32
#include "mantis_common.h"
33 34
#include "mantis_reg.h"
#include "mantis_i2c.h"
35

36 37
#define TRIALS			10000

38 39
static int mantis_i2c_read(struct mantis_pci *mantis, const struct i2c_msg *msg)
{
40
	u32 rxd, i, stat, trials;
41

42
	dprintk(MANTIS_INFO, 0, "        %s:  Address=[0x%02x] <R>[ ",
43 44
		__func__, msg->addr);

45 46 47 48 49 50 51 52 53
	for (i = 0; i < msg->len; i++) {
		rxd = (msg->addr << 25) | (1 << 24)
					| MANTIS_I2C_RATE_3
					| MANTIS_I2C_STOP
					| MANTIS_I2C_PGMODE;

		if (i == (msg->len - 1))
			rxd &= ~MANTIS_I2C_STOP;

54
		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
55
		mmwrite(rxd, MANTIS_I2CDATA_CTL);
56 57

		/* wait for xfer completion */
58
		for (trials = 0; trials < TRIALS; trials++) {
59 60 61
			stat = mmread(MANTIS_INT_STAT);
			if (stat & MANTIS_INT_I2CDONE)
				break;
62
		}
63

64 65 66 67 68 69 70 71 72 73 74
		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);

		/* wait for xfer completion */
		for (trials = 0; trials < TRIALS; trials++) {
			stat = mmread(MANTIS_INT_STAT);
			if (stat & MANTIS_INT_I2CRACK)
				break;
		}

		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);

75 76
		rxd = mmread(MANTIS_I2CDATA_CTL);
		msg->buf[i] = (u8)((rxd >> 8) & 0xFF);
77
		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
78
	}
79
	dprintk(MANTIS_INFO, 0, "]\n");
80 81 82 83 84 85 86

	return 0;
}

static int mantis_i2c_write(struct mantis_pci *mantis, const struct i2c_msg *msg)
{
	int i;
87
	u32 txd = 0, stat, trials;
88

89
	dprintk(MANTIS_INFO, 0, "        %s: Address=[0x%02x] <W>[ ",
90 91
		__func__, msg->addr);

92
	for (i = 0; i < msg->len; i++) {
93
		dprintk(MANTIS_INFO, 0, "%02x ", msg->buf[i]);
94 95 96 97 98 99 100 101
		txd = (msg->addr << 25) | (msg->buf[i] << 8)
					| MANTIS_I2C_RATE_3
					| MANTIS_I2C_STOP
					| MANTIS_I2C_PGMODE;

		if (i == (msg->len - 1))
			txd &= ~MANTIS_I2C_STOP;

102
		mmwrite(MANTIS_INT_I2CDONE, MANTIS_INT_STAT);
103
		mmwrite(txd, MANTIS_I2CDATA_CTL);
104 105

		/* wait for xfer completion */
106
		for (trials = 0; trials < TRIALS; trials++) {
107 108 109
			stat = mmread(MANTIS_INT_STAT);
			if (stat & MANTIS_INT_I2CDONE)
				break;
110
		}
111 112 113 114 115 116 117 118 119 120 121

		dprintk(MANTIS_TMG, 0, "I2CDONE: trials=%d\n", trials);

		/* wait for xfer completion */
		for (trials = 0; trials < TRIALS; trials++) {
			stat = mmread(MANTIS_INT_STAT);
			if (stat & MANTIS_INT_I2CRACK)
				break;
		}

		dprintk(MANTIS_TMG, 0, "I2CRACK: trials=%d\n", trials);
122
	}
123
	dprintk(MANTIS_INFO, 0, "]\n");
124 125 126 127 128 129

	return 0;
}

static int mantis_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
130 131
	int ret = 0, i = 0, trials;
	u32 stat, data, txd;
132
	struct mantis_pci *mantis;
133
	struct mantis_hwconfig *config;
134 135

	mantis = i2c_get_adapdata(adapter);
136 137 138 139 140
	BUG_ON(!mantis);
	config = mantis->hwconfig;
	BUG_ON(!config);

	dprintk(MANTIS_DEBUG, 1, "Messages:%d", num);
141
	mutex_lock(&mantis->i2c_lock);
142 143 144

	while (i < num) {
		/* Byte MODE */
145 146 147 148 149
		if ((config->i2c_mode & MANTIS_BYTE_MODE) &&
		    ((i + 1) < num)			&&
		    (msgs[i].len < 2)			&&
		    (msgs[i + 1].len < 2)		&&
		    (msgs[i + 1].flags & I2C_M_RD)) {
150 151 152 153 154 155 156 157 158 159

			dprintk(MANTIS_DEBUG, 0, "        Byte MODE:\n");

			/* Read operation */
			txd = msgs[i].addr << 25 | (0x1 << 24)
						 | (msgs[i].buf[0] << 16)
						 | MANTIS_I2C_RATE_3;

			mmwrite(txd, MANTIS_I2CDATA_CTL);
			/* wait for xfer completion */
160
			for (trials = 0; trials < TRIALS; trials++) {
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
				stat = mmread(MANTIS_INT_STAT);
				if (stat & MANTIS_INT_I2CDONE)
					break;
			}

			/* check for xfer completion */
			if (stat & MANTIS_INT_I2CDONE) {
				/* check xfer was acknowledged */
				if (stat & MANTIS_INT_I2CRACK) {
					data = mmread(MANTIS_I2CDATA_CTL);
					msgs[i + 1].buf[0] = (data >> 8) & 0xff;
					dprintk(MANTIS_DEBUG, 0, "        Byte <%d> RXD=0x%02x  [%02x]\n", 0x0, data, msgs[i + 1].buf[0]);
				} else {
					/* I/O error */
					dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
					ret = -EIO;
					break;
				}
			} else {
				/* I/O error */
				dprintk(MANTIS_ERROR, 1, "        I/O error, LINE:%d", __LINE__);
				ret = -EIO;
				break;
			}
			i += 2; /* Write/Read operation in one go */
		}

		if (i < num) {
			if (msgs[i].flags & I2C_M_RD)
				ret = mantis_i2c_read(mantis, &msgs[i]);
			else
				ret = mantis_i2c_write(mantis, &msgs[i]);

			i++;
			if (ret < 0)
				goto bail_out;
		}

199
	}
200

201
	mutex_unlock(&mantis->i2c_lock);
202 203

	return num;
204 205 206 207

bail_out:
	mutex_unlock(&mantis->i2c_lock);
	return ret;
208 209 210 211 212 213 214
}

static u32 mantis_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_SMBUS_EMUL;
}

215
static const struct i2c_algorithm mantis_algo = {
216 217 218 219
	.master_xfer		= mantis_i2c_xfer,
	.functionality		= mantis_i2c_func,
};

220
int mantis_i2c_init(struct mantis_pci *mantis)
221
{
222
	u32 intstat;
223 224
	struct i2c_adapter *i2c_adapter = &mantis->adapter;
	struct pci_dev *pdev		= mantis->pdev;
225

226
	init_waitqueue_head(&mantis->i2c_wq);
227
	mutex_init(&mantis->i2c_lock);
228
	strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name));
229 230
	i2c_set_adapdata(i2c_adapter, mantis);

231 232 233 234 235 236 237
	i2c_adapter->owner	= THIS_MODULE;
	i2c_adapter->algo	= &mantis_algo;
	i2c_adapter->algo_data	= NULL;
	i2c_adapter->timeout	= 500;
	i2c_adapter->retries	= 3;
	i2c_adapter->dev.parent	= &pdev->dev;

238
	mantis->i2c_rc		= i2c_add_adapter(i2c_adapter);
239 240 241
	if (mantis->i2c_rc < 0)
		return mantis->i2c_rc;

242
	dprintk(MANTIS_DEBUG, 1, "Initializing I2C ..");
243 244

	intstat = mmread(MANTIS_INT_STAT);
245
	mmread(MANTIS_INT_MASK);
246
	mmwrite(intstat, MANTIS_INT_STAT);
247
	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
248
	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
249 250 251

	return 0;
}
252
EXPORT_SYMBOL_GPL(mantis_i2c_init);
253

254
int mantis_i2c_exit(struct mantis_pci *mantis)
255
{
256
	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
257
	mantis_mask_ints(mantis, MANTIS_INT_I2CDONE);
258

259
	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
260 261 262
	i2c_del_adapter(&mantis->adapter);

	return 0;
263
}
264
EXPORT_SYMBOL_GPL(mantis_i2c_exit);