Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b994d192 authored by Olivier Grenie's avatar Olivier Grenie Committed by Mauro Carvalho Chehab
Browse files

[media] DiBx000: add addition i2c-interface names



This patch adds the possibitity to use different I2C-ports to talk to
slave-devices than the standard ones.

Signed-off-by: default avatarOlivier Grenie <olivier.grenie@dibcom.fr>
Signed-off-by: default avatarPatrick Boettcher <patrick.boettcher@dibcom.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 4c70e074
Loading
Loading
Loading
Loading
+271 −13
Original line number Diff line number Diff line
@@ -17,9 +17,144 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
	struct i2c_msg msg = {
		.addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
	};

	return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}

static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
{
	u8 wb[2] = { reg >> 8, reg & 0xff };
	u8 rb[2];
	struct i2c_msg msg[2] = {
		{.addr = mst->i2c_addr,.flags = 0,.buf = wb,.len = 2},
		{.addr = mst->i2c_addr,.flags = I2C_M_RD,.buf = rb,.len = 2},
	};

	if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
		dprintk("i2c read error on %d", reg);

	return (rb[0] << 8) | rb[1];
}

static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
{
	int i = 100; // max_i2c_polls;
	u16 status;

	while (((status = dibx000_read_word(mst, mst->base_reg + 2)) & 0x0100) == 0 && --i > 0);

	/* i2c timed out */
	if (i == 0)
		return -EREMOTEIO;

	/* no acknowledge */
	if ((status & 0x0080) == 0)
		return -EREMOTEIO;

	return 0;
}

static int dibx000_master_i2c_write(struct dibx000_i2c_master *mst, struct i2c_msg *msg, u8 stop)
{
	u16 data;
	u16 da;
	u16 i;
	u16 txlen = msg->len, len;
	const u8 *b = msg->buf;

	while (txlen) {
		dibx000_read_word(mst, mst->base_reg + 2);   // reset fifo ptr

		len = txlen > 8 ? 8 : txlen;
		for (i = 0; i < len; i += 2) {
			data = *b++ << 8;
			if (i+1 < len)
				data |= *b++;
			dibx000_write_word(mst, mst->base_reg, data);
		}
		da = (((u8) (msg->addr))  << 9) | // addr
			(1           << 8) | // master
			(1           << 7) | // rq
			(0           << 6) | // stop
			(0           << 5) | // start
			((len & 0x7) << 2) | // nb 8 bytes == 0 here
			(0           << 1) | // rw
			(0           << 0);  // irqen

		if (txlen == msg->len)
			da |= 1 << 5; /* start */

		if (txlen-len == 0 && stop)
			da |= 1 << 6; /* stop */

		dibx000_write_word(mst, mst->base_reg+1, da);

		if (dibx000_is_i2c_done(mst) != 0)
			return -EREMOTEIO;
		txlen -= len;
	}

	return 0;
}

static int dibx000_master_i2c_read(struct dibx000_i2c_master *mst, struct i2c_msg *msg)
{
	u16 da;
	u8 *b = msg->buf;
	u16 rxlen = msg->len, len;

	while (rxlen) {
		len = rxlen > 8 ? 8 : rxlen;
		da = (((u8) (msg->addr)) << 9) | // addr
			(1           << 8) | // master
			(1           << 7) | // rq
			(0           << 6) | // stop
			(0           << 5) | // start
			((len & 0x7) << 2) | // nb
			(1           << 1) | // rw
			(0           << 0);  // irqen

		if (rxlen == msg->len)
			da |= 1 << 5; /* start */

		if (rxlen-len == 0)
			da |= 1 << 6; /* stop */
		dibx000_write_word(mst, mst->base_reg+1, da);

		if (dibx000_is_i2c_done(mst) != 0)
			return -EREMOTEIO;

		rxlen -= len;

		while (len) {
			da = dibx000_read_word(mst, mst->base_reg);
			*b++ = (da >> 8) & 0xff;
			len--;
			if (len >= 1) {
				*b++ =  da   & 0xff;
				len--;
			}
		}
	}

	return 0;
}

int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed)
{
	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);

	if (mst->device_rev < DIB7000MC && speed < 235)
		speed = 235;
	return dibx000_write_word(mst, mst->base_reg + 3, (u16)(60000 / speed));

}
EXPORT_SYMBOL(dibx000_i2c_set_speed);

static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
{
	return I2C_FUNC_I2C;
}

static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
					enum dibx000_i2c_interface intf)
@@ -32,6 +167,66 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst,
	return 0;
}

static int dibx000_i2c_master_xfer_gpio12(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
{
	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
	int msg_index;
	int ret = 0;

	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_1_2);
	for (msg_index = 0; msg_index<num; msg_index++) {
		if (msg[msg_index].flags & I2C_M_RD)
		{
			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
			if (ret != 0)
				return 0;
		}
		else
		{
			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
			if (ret != 0)
				return 0;
		}
	}

	return num;
}

static int dibx000_i2c_master_xfer_gpio34(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
{
	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
	int msg_index;
	int ret = 0;

	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_3_4);
	for (msg_index = 0; msg_index<num; msg_index++) {
		if (msg[msg_index].flags & I2C_M_RD)
		{
			ret = dibx000_master_i2c_read(mst, &msg[msg_index]);
			if (ret != 0)
				return 0;
		}
		else
		{
			ret = dibx000_master_i2c_write(mst, &msg[msg_index], 1);
			if (ret != 0)
				return 0;
		}
	}

	return num;
}

static struct i2c_algorithm dibx000_i2c_master_gpio12_xfer_algo = {
	.master_xfer = dibx000_i2c_master_xfer_gpio12,
	.functionality = dibx000_i2c_func,
};

static struct i2c_algorithm dibx000_i2c_master_gpio34_xfer_algo = {
	.master_xfer = dibx000_i2c_master_xfer_gpio34,
	.functionality = dibx000_i2c_func,
};

static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
				 u8 addr, int onoff)
{
@@ -54,11 +249,37 @@ static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4],
	return 0;
}

static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
					struct i2c_msg msg[], int num)
{
	return I2C_FUNC_I2C;
	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
	struct i2c_msg m[2 + num];
	u8 tx_open[4], tx_close[4];

	memset(m, 0, sizeof(struct i2c_msg) * (2 + num));

	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);

	dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
	m[0].addr = mst->i2c_addr;
	m[0].buf = tx_open;
	m[0].len = 4;

	memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);

	dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
	m[num + 1].addr = mst->i2c_addr;
	m[num + 1].buf = tx_close;
	m[num + 1].len = 4;

	return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
}

static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
	.master_xfer = dibx000_i2c_gated_gpio67_xfer,
	.functionality = dibx000_i2c_func,
};

static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
					struct i2c_msg msg[], int num)
{
@@ -101,6 +322,18 @@ struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst,
		if (gating)
			i2c = &mst->gated_tuner_i2c_adap;
		break;
	case DIBX000_I2C_INTERFACE_GPIO_1_2:
		if (!gating)
			i2c = &mst->master_i2c_adap_gpio12;
		break;
	case DIBX000_I2C_INTERFACE_GPIO_3_4:
		if (!gating)
			i2c = &mst->master_i2c_adap_gpio34;
		break;
	case DIBX000_I2C_INTERFACE_GPIO_6_7:
		if (gating)
			i2c = &mst->master_i2c_adap_gpio67;
		break;
	default:
		printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
		break;
@@ -153,12 +386,34 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
	else
		mst->base_reg = 768;

	mst->gated_tuner_i2c_adap.dev.parent = mst->i2c_adap->dev.parent;
	if (i2c_adapter_init
			(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo,
			 "DiBX000 tuner I2C bus", mst) != 0)
		printk(KERN_ERR
				"DiBX000: could not initialize the tuner i2c_adapter\n");

	mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent;
	if (i2c_adapter_init
			(&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo,
			 "DiBX000 master GPIO12 I2C bus", mst) != 0)
		printk(KERN_ERR
				"DiBX000: could not initialize the master i2c_adapter\n");

	mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent;
	if (i2c_adapter_init
			(&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo,
			 "DiBX000 master GPIO34 I2C bus", mst) != 0)
		printk(KERN_ERR
				"DiBX000: could not initialize the master i2c_adapter\n");

	mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent;
	if (i2c_adapter_init
			(&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo,
			 "DiBX000 master GPIO67 I2C bus", mst) != 0)
		printk(KERN_ERR
				"DiBX000: could not initialize the master i2c_adapter\n");

	/* initialize the i2c-master by closing the gate */
	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);

@@ -170,6 +425,9 @@ EXPORT_SYMBOL(dibx000_init_i2c_master);
void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
{
	i2c_del_adapter(&mst->gated_tuner_i2c_adap);
	i2c_del_adapter(&mst->master_i2c_adap_gpio12);
	i2c_del_adapter(&mst->master_i2c_adap_gpio34);
	i2c_del_adapter(&mst->master_i2c_adap_gpio67);
}
EXPORT_SYMBOL(dibx000_exit_i2c_master);

+14 −9
Original line number Diff line number Diff line
@@ -4,7 +4,8 @@
enum dibx000_i2c_interface {
	DIBX000_I2C_INTERFACE_TUNER = 0,
	DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
	DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
	DIBX000_I2C_INTERFACE_GPIO_3_4 = 2,
	DIBX000_I2C_INTERFACE_GPIO_6_7 = 3
};

struct dibx000_i2c_master {
@@ -19,6 +20,9 @@ struct dibx000_i2c_master {

//	struct i2c_adapter  tuner_i2c_adap;
	struct i2c_adapter gated_tuner_i2c_adap;
	struct i2c_adapter master_i2c_adap_gpio12;
	struct i2c_adapter master_i2c_adap_gpio34;
	struct i2c_adapter master_i2c_adap_gpio67;

	struct i2c_adapter *i2c_adap;
	u8 i2c_addr;
@@ -35,6 +39,7 @@ extern struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master
							intf, int gating);
extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst);
extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed);

extern u32 systime(void);