131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs/*
27dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs * Copyright 2012 Red Hat Inc.
331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs *
431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * copy of this software and associated documentation files (the "Software"),
631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * to deal in the Software without restriction, including without limitation
731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * and/or sell copies of the Software, and to permit persons to whom the
931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * Software is furnished to do so, subject to the following conditions:
1031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs *
1131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * The above copyright notice and this permission notice shall be included in
1231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * all copies or substantial portions of the Software.
1331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs *
1431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * OTHER DEALINGS IN THE SOFTWARE.
2131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs *
2231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs * Authors: Ben Skeggs
2331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs */
2431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
257dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs#include "nv50.h"
2631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
27d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggsvoid
28d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggsnv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
29d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs{
30d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	u32 intr = nv_rd32(i2c, 0x00e06c);
31d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
32d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
33d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
34d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
35d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
36d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
37d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	}
38d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	nv_wr32(i2c, 0x00e06c, intr);
39d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs}
40d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs
41d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggsvoid
42d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggsnv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
43d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs{
44d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	u32 temp = nv_rd32(i2c, 0x00e068), i;
45d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	for (i = 0; i < 8; i++) {
46d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		if (mask & (1 << i)) {
47d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs			if (!(data & (1 << i))) {
48d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs				temp &= ~(type << (i * 4));
49d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs				continue;
50d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs			}
51d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs			temp |= type << (i * 4);
52d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs		}
53d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	}
54d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	nv_wr32(i2c, 0x00e068, temp);
55d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs}
56d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs
5731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
5831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
5931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
6031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsstatic void
6131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsauxch_fini(struct nouveau_i2c *aux, int ch)
6231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs{
6331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
6431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs}
6531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
6631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsstatic int
6731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsauxch_init(struct nouveau_i2c *aux, int ch)
6831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs{
6931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	const u32 unksel = 1; /* nfi which to use, or if it matters.. */
7031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	const u32 ureq = unksel ? 0x00100000 : 0x00200000;
7131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	const u32 urep = unksel ? 0x01000000 : 0x02000000;
7231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	u32 ctrl, timeout;
7331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
7431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	/* wait up to 1ms for any previous transaction to be done... */
7531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	timeout = 1000;
7631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	do {
7731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
7831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		udelay(1);
7931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		if (!timeout--) {
8031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
8131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			return -EBUSY;
8231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		}
8331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	} while (ctrl & 0x03010000);
8431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
8531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	/* set some magic, and wait up to 1ms for it to appear */
8631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
8731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	timeout = 1000;
8831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	do {
8931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
9031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		udelay(1);
9131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		if (!timeout--) {
9231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			AUX_ERR("magic wait 0x%08x\n", ctrl);
9331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			auxch_fini(aux, ch);
9431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			return -EBUSY;
9531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		}
9631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	} while ((ctrl & 0x03000000) != urep);
9731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
9831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	return 0;
9931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs}
10031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
10131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsint
102842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggsnv94_aux(struct nouveau_i2c_port *base, bool retry,
103842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs	 u8 type, u32 addr, u8 *data, u8 size)
10431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs{
1057dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct nouveau_i2c *aux = nouveau_i2c(base);
1067dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct nv50_i2c_port *port = (void *)base;
10731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	u32 ctrl, stat, timeout, retries;
10831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	u32 xbuf[4] = {};
1097dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	int ch = port->addr;
11031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	int ret, i;
11131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
11231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
11331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
11431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	ret = auxch_init(aux, ch);
11531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	if (ret)
11631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		goto out;
11731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
11831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
11931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	if (!(stat & 0x10000000)) {
12031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		AUX_DBG("sink not detected\n");
12131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		ret = -ENXIO;
12231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		goto out;
12331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	}
12431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
12531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	if (!(type & 1)) {
12631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		memcpy(xbuf, data, size);
12731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		for (i = 0; i < 16; i += 4) {
12831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
12931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
13031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		}
13131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	}
13231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
13331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	ctrl  = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
13431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	ctrl &= ~0x0001f0ff;
13531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	ctrl |= type << 12;
13631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	ctrl |= size - 1;
13731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
13831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
139842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs	/* (maybe) retry transaction a number of times on failure... */
140842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs	for (retries = 0; !ret && retries < 32; retries++) {
14131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		/* reset, and delay a while if this is a retry */
14231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
14331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
14431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		if (retries)
14531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			udelay(400);
14631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
14731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		/* transaction request, wait up to 1ms for it to complete */
14831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
14931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
15031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		timeout = 1000;
15131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		do {
15231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
15331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			udelay(1);
15431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			if (!timeout--) {
15531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs				AUX_ERR("tx req timeout 0x%08x\n", ctrl);
156842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs				ret = -EIO;
15731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs				goto out;
15831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			}
15931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		} while (ctrl & 0x00010000);
160842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs		ret = 1;
16131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
16231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		/* read status, and check if transaction completed ok */
16331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
164842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs		if ((stat & 0x000f0000) == 0x00080000 ||
165842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs		    (stat & 0x000f0000) == 0x00020000)
166842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs			ret = retry ? 0 : 1;
167842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs		if ((stat & 0x00000100))
168842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs			ret = -ETIMEDOUT;
169842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs		if ((stat & 0x00000e00))
170842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs			ret = -EIO;
17131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
17231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
17331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	}
17431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
17531a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	if (type & 1) {
17631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		for (i = 0; i < 16; i += 4) {
17731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
17831a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs			AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
17931a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		}
18031a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs		memcpy(data, xbuf, size);
18131a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	}
18231a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
18331a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggsout:
18431a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs	auxch_fini(aux, ch);
185842c2953fc360f9661d7b8bdd90303d4c946f1efBen Skeggs	return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
18631a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs}
18731a34aa421032cfe3b2b892c929e7539e747a7acBen Skeggs
1887dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsstatic const struct nouveau_i2c_func
1897dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsnv94_i2c_func = {
1907dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	.drive_scl = nv50_i2c_drive_scl,
1917dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	.drive_sda = nv50_i2c_drive_sda,
1927dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	.sense_scl = nv50_i2c_sense_scl,
1937dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	.sense_sda = nv50_i2c_sense_sda,
1947dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs};
1957dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
1967dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsstatic int
1977dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsnv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
1987dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		   struct nouveau_oclass *oclass, void *data, u32 index,
1997dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		   struct nouveau_object **pobject)
2007dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs{
2017dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct dcb_i2c_entry *info = data;
2027dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct nv50_i2c_port *port;
2037dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	int ret;
2047dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2057dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
206c865534f1e5b5b4ef03f4a55cf4730f4b70dd75bIlia Mirkin				      &nouveau_i2c_bit_algo, &nv94_i2c_func,
207c865534f1e5b5b4ef03f4a55cf4730f4b70dd75bIlia Mirkin				      &port);
2087dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	*pobject = nv_object(port);
2097dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	if (ret)
2107dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		return ret;
2117dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2127dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	if (info->drive >= nv50_i2c_addr_nr)
2137dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		return -EINVAL;
2147dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2157dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	port->state = 7;
2167dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	port->addr = nv50_i2c_addr[info->drive];
2177dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	if (info->share != DCB_I2C_UNUSED) {
2187dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		port->ctrl = 0x00e500 + (info->share * 0x50);
2197dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		port->data = 0x0000e001;
2207dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	}
2217dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	return 0;
2227dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs}
2237dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2247dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsstatic const struct nouveau_i2c_func
2257dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsnv94_aux_func = {
2267dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	.aux       = nv94_aux,
2277dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs};
2287dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2297dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsint
2307dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsnv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
2317dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		   struct nouveau_oclass *oclass, void *data, u32 index,
2327dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		   struct nouveau_object **pobject)
2337dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs{
2347dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct dcb_i2c_entry *info = data;
2357dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	struct nv50_i2c_port *port;
2367dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	int ret;
2377dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2387dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	ret = nouveau_i2c_port_create(parent, engine, oclass, index,
239c865534f1e5b5b4ef03f4a55cf4730f4b70dd75bIlia Mirkin				      &nouveau_i2c_aux_algo, &nv94_aux_func,
240c865534f1e5b5b4ef03f4a55cf4730f4b70dd75bIlia Mirkin				      &port);
2417dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	*pobject = nv_object(port);
2427dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	if (ret)
2437dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		return ret;
2447dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2453668a339d6e7d47f777b8ce86bd7ca53451df6bbBen Skeggs	port->base.aux = info->drive;
2467dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	port->addr = info->drive;
2477dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	if (info->share != DCB_I2C_UNUSED) {
2487dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		port->ctrl = 0x00e500 + (info->drive * 0x50);
2497dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		port->data = 0x00002002;
2507dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	}
2517dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2527dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	return 0;
2537dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs}
2547dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
2557dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsstatic struct nouveau_oclass
2567dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggsnv94_i2c_sclass[] = {
2577dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
2587dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	  .ofuncs = &(struct nouveau_ofuncs) {
2597dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .ctor = nv94_i2c_port_ctor,
2607dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .dtor = _nouveau_i2c_port_dtor,
2617dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .init = nv50_i2c_port_init,
2627dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .fini = _nouveau_i2c_port_fini,
2637dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	  },
2647dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	},
2657dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	{ .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
2667dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	  .ofuncs = &(struct nouveau_ofuncs) {
2677dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .ctor = nv94_aux_port_ctor,
2687dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .dtor = _nouveau_i2c_port_dtor,
2697dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .init = _nouveau_i2c_port_init,
2707dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		  .fini = _nouveau_i2c_port_fini,
2717dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	  },
2727dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	},
2737dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	{}
2747dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs};
2757dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs
276c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggsstruct nouveau_oclass *
277c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggsnv94_i2c_oclass = &(struct nouveau_i2c_impl) {
278c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggs	.base.handle = NV_SUBDEV(I2C, 0x94),
279c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggs	.base.ofuncs = &(struct nouveau_ofuncs) {
280c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggs		.ctor = _nouveau_i2c_ctor,
2817dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		.dtor = _nouveau_i2c_dtor,
2827dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		.init = _nouveau_i2c_init,
2837dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs		.fini = _nouveau_i2c_fini,
2847dcd060c0e6e4f76ce7eea94c66437ce8f546530Ben Skeggs	},
285c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggs	.sclass = nv94_i2c_sclass,
2869efc583ea9a474a8d89421da8aad4a2265f2ac5aBen Skeggs	.pad_x = &nv04_i2c_pad_oclass,
2879efc583ea9a474a8d89421da8aad4a2265f2ac5aBen Skeggs	.pad_s = &nv94_i2c_pad_oclass,
288d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	.aux = 4,
289d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	.aux_stat = nv94_aux_stat,
290d78fa39a2b766b680e6c703f52553afc6c532e11Ben Skeggs	.aux_mask = nv94_aux_mask,
291c26fe843560fe01b4b652ee21952d33f60f4e699Ben Skeggs}.base;
292