mantis_i2c.c 6.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
	Mantis PCI bridge driver

	Copyright (C) 2005, 2006 Manu Abraham (abraham.manu@gmail.com)

	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 215 216 217 218 219 220 221
}

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

static struct i2c_algorithm mantis_algo = {
	.master_xfer		= mantis_i2c_xfer,
	.functionality		= mantis_i2c_func,
};

int __devinit mantis_i2c_init(struct mantis_pci *mantis)
{
222
	u32 intstat, intmask;
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 238
	i2c_adapter->owner	= THIS_MODULE;
	i2c_adapter->class	= I2C_CLASS_TV_DIGITAL;
	i2c_adapter->algo	= &mantis_algo;
	i2c_adapter->algo_data	= NULL;
	i2c_adapter->timeout	= 500;
	i2c_adapter->retries	= 3;
	i2c_adapter->dev.parent	= &pdev->dev;

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

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

	intstat = mmread(MANTIS_INT_STAT);
246
	intmask = mmread(MANTIS_INT_MASK);
247
	mmwrite(intstat, MANTIS_INT_STAT);
248 249 250
	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
	intmask = mmread(MANTIS_INT_MASK);
	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);
251 252 253

	return 0;
}
254
EXPORT_SYMBOL_GPL(mantis_i2c_init);
255 256 257

int __devexit mantis_i2c_exit(struct mantis_pci *mantis)
{
258 259 260 261 262 263
	u32 intmask;

	dprintk(MANTIS_DEBUG, 1, "Disabling I2C interrupt");
	intmask = mmread(MANTIS_INT_MASK);
	mmwrite((intmask & ~MANTIS_INT_I2CDONE), MANTIS_INT_MASK);

264
	dprintk(MANTIS_DEBUG, 1, "Removing I2C adapter");
265 266
	return i2c_del_adapter(&mantis->adapter);
}
267
EXPORT_SYMBOL_GPL(mantis_i2c_exit);