185756a06SHans Verkuil /*
285756a06SHans Verkuil  *  cobalt I2C functions
385756a06SHans Verkuil  *
485756a06SHans Verkuil  *  Derived from cx18-i2c.c
585756a06SHans Verkuil  *
685756a06SHans Verkuil  *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
785756a06SHans Verkuil  *  All rights reserved.
885756a06SHans Verkuil  *
985756a06SHans Verkuil  *  This program is free software; you may redistribute it and/or modify
1085756a06SHans Verkuil  *  it under the terms of the GNU General Public License as published by
1185756a06SHans Verkuil  *  the Free Software Foundation; version 2 of the License.
1285756a06SHans Verkuil  *
1385756a06SHans Verkuil  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1485756a06SHans Verkuil  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1585756a06SHans Verkuil  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1685756a06SHans Verkuil  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
1785756a06SHans Verkuil  *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1885756a06SHans Verkuil  *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1985756a06SHans Verkuil  *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2085756a06SHans Verkuil  *  SOFTWARE.
2185756a06SHans Verkuil  */
2285756a06SHans Verkuil 
2385756a06SHans Verkuil #include "cobalt-driver.h"
2485756a06SHans Verkuil #include "cobalt-i2c.h"
2585756a06SHans Verkuil 
2685756a06SHans Verkuil struct cobalt_i2c_regs {
2785756a06SHans Verkuil 	/* Clock prescaler register lo-byte */
2885756a06SHans Verkuil 	u8 prerlo;
2985756a06SHans Verkuil 	u8 dummy0[3];
3085756a06SHans Verkuil 	/* Clock prescaler register high-byte */
3185756a06SHans Verkuil 	u8 prerhi;
3285756a06SHans Verkuil 	u8 dummy1[3];
3385756a06SHans Verkuil 	/* Control register */
3485756a06SHans Verkuil 	u8 ctr;
3585756a06SHans Verkuil 	u8 dummy2[3];
3685756a06SHans Verkuil 	/* Transmit/Receive register */
3785756a06SHans Verkuil 	u8 txr_rxr;
3885756a06SHans Verkuil 	u8 dummy3[3];
3985756a06SHans Verkuil 	/* Command and Status register */
4085756a06SHans Verkuil 	u8 cr_sr;
4185756a06SHans Verkuil 	u8 dummy4[3];
4285756a06SHans Verkuil };
4385756a06SHans Verkuil 
4485756a06SHans Verkuil /* CTR[7:0] - Control register */
4585756a06SHans Verkuil 
4685756a06SHans Verkuil /* I2C Core enable bit */
4785756a06SHans Verkuil #define M00018_CTR_BITMAP_EN_MSK	(1 << 7)
4885756a06SHans Verkuil 
4985756a06SHans Verkuil /* I2C Core interrupt enable bit */
5085756a06SHans Verkuil #define M00018_CTR_BITMAP_IEN_MSK	(1 << 6)
5185756a06SHans Verkuil 
5285756a06SHans Verkuil /* CR[7:0] - Command register */
5385756a06SHans Verkuil 
5485756a06SHans Verkuil /* I2C start condition */
5585756a06SHans Verkuil #define M00018_CR_BITMAP_STA_MSK	(1 << 7)
5685756a06SHans Verkuil 
5785756a06SHans Verkuil /* I2C stop condition */
5885756a06SHans Verkuil #define M00018_CR_BITMAP_STO_MSK	(1 << 6)
5985756a06SHans Verkuil 
6085756a06SHans Verkuil /* I2C read from slave */
6185756a06SHans Verkuil #define M00018_CR_BITMAP_RD_MSK		(1 << 5)
6285756a06SHans Verkuil 
6385756a06SHans Verkuil /* I2C write to slave */
6485756a06SHans Verkuil #define M00018_CR_BITMAP_WR_MSK		(1 << 4)
6585756a06SHans Verkuil 
6685756a06SHans Verkuil /* I2C ack */
6785756a06SHans Verkuil #define M00018_CR_BITMAP_ACK_MSK	(1 << 3)
6885756a06SHans Verkuil 
6985756a06SHans Verkuil /* I2C Interrupt ack */
7085756a06SHans Verkuil #define M00018_CR_BITMAP_IACK_MSK	(1 << 0)
7185756a06SHans Verkuil 
7285756a06SHans Verkuil /* SR[7:0] - Status register */
7385756a06SHans Verkuil 
7485756a06SHans Verkuil /* Receive acknowledge from slave */
7585756a06SHans Verkuil #define M00018_SR_BITMAP_RXACK_MSK	(1 << 7)
7685756a06SHans Verkuil 
7785756a06SHans Verkuil /* Busy, I2C bus busy (as defined by start / stop bits) */
7885756a06SHans Verkuil #define M00018_SR_BITMAP_BUSY_MSK	(1 << 6)
7985756a06SHans Verkuil 
8085756a06SHans Verkuil /* Arbitration lost - core lost arbitration */
8185756a06SHans Verkuil #define M00018_SR_BITMAP_AL_MSK		(1 << 5)
8285756a06SHans Verkuil 
8385756a06SHans Verkuil /* Transfer in progress */
8485756a06SHans Verkuil #define M00018_SR_BITMAP_TIP_MSK	(1 << 1)
8585756a06SHans Verkuil 
8685756a06SHans Verkuil /* Interrupt flag */
8785756a06SHans Verkuil #define M00018_SR_BITMAP_IF_MSK		(1 << 0)
8885756a06SHans Verkuil 
8985756a06SHans Verkuil /* Frequency, in Hz */
9085756a06SHans Verkuil #define I2C_FREQUENCY			400000
9185756a06SHans Verkuil #define ALT_CPU_FREQ			83333333
9285756a06SHans Verkuil 
930664fb61SHans Verkuil static struct cobalt_i2c_regs __iomem *
9485756a06SHans Verkuil cobalt_i2c_regs(struct cobalt *cobalt, unsigned idx)
9585756a06SHans Verkuil {
9685756a06SHans Verkuil 	switch (idx) {
9785756a06SHans Verkuil 	case 0:
9885756a06SHans Verkuil 	default:
990664fb61SHans Verkuil 		return (struct cobalt_i2c_regs __iomem *)
10085756a06SHans Verkuil 			(cobalt->bar1 + COBALT_I2C_0_BASE);
10185756a06SHans Verkuil 	case 1:
1020664fb61SHans Verkuil 		return (struct cobalt_i2c_regs __iomem *)
10385756a06SHans Verkuil 			(cobalt->bar1 + COBALT_I2C_1_BASE);
10485756a06SHans Verkuil 	case 2:
1050664fb61SHans Verkuil 		return (struct cobalt_i2c_regs __iomem *)
10685756a06SHans Verkuil 			(cobalt->bar1 + COBALT_I2C_2_BASE);
10785756a06SHans Verkuil 	case 3:
1080664fb61SHans Verkuil 		return (struct cobalt_i2c_regs __iomem *)
10985756a06SHans Verkuil 			(cobalt->bar1 + COBALT_I2C_3_BASE);
11085756a06SHans Verkuil 	case 4:
1110664fb61SHans Verkuil 		return (struct cobalt_i2c_regs __iomem *)
11285756a06SHans Verkuil 			(cobalt->bar1 + COBALT_I2C_HSMA_BASE);
11385756a06SHans Verkuil 	}
11485756a06SHans Verkuil }
11585756a06SHans Verkuil 
11685756a06SHans Verkuil /* Do low-level i2c byte transfer.
11785756a06SHans Verkuil  * Returns -1 in case of an error or 0 otherwise.
11885756a06SHans Verkuil  */
1190664fb61SHans Verkuil static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs,
12085756a06SHans Verkuil 		struct i2c_adapter *adap, bool start, bool stop,
12185756a06SHans Verkuil 		u8 *data, u16 len)
12285756a06SHans Verkuil {
12385756a06SHans Verkuil 	unsigned long start_time;
12485756a06SHans Verkuil 	int status;
12585756a06SHans Verkuil 	int cmd;
12685756a06SHans Verkuil 	int i;
12785756a06SHans Verkuil 
12885756a06SHans Verkuil 	for (i = 0; i < len; i++) {
12985756a06SHans Verkuil 		/* Setup data */
1300664fb61SHans Verkuil 		iowrite8(data[i], &regs->txr_rxr);
13185756a06SHans Verkuil 
13285756a06SHans Verkuil 		/* Setup command */
13385756a06SHans Verkuil 		if (i == 0 && start != 0) {
13485756a06SHans Verkuil 			/* Write + Start */
13585756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_WR_MSK |
13685756a06SHans Verkuil 			      M00018_CR_BITMAP_STA_MSK;
13785756a06SHans Verkuil 		} else if (i == len - 1 && stop != 0) {
13885756a06SHans Verkuil 			/* Write + Stop */
13985756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_WR_MSK |
14085756a06SHans Verkuil 			      M00018_CR_BITMAP_STO_MSK;
14185756a06SHans Verkuil 		} else {
14285756a06SHans Verkuil 			/* Write only */
14385756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_WR_MSK;
14485756a06SHans Verkuil 		}
14585756a06SHans Verkuil 
14685756a06SHans Verkuil 		/* Execute command */
1470664fb61SHans Verkuil 		iowrite8(cmd, &regs->cr_sr);
14885756a06SHans Verkuil 
14985756a06SHans Verkuil 		/* Wait for transfer to complete (TIP = 0) */
15085756a06SHans Verkuil 		start_time = jiffies;
1510664fb61SHans Verkuil 		status = ioread8(&regs->cr_sr);
15285756a06SHans Verkuil 		while (status & M00018_SR_BITMAP_TIP_MSK) {
15385756a06SHans Verkuil 			if (time_after(jiffies, start_time + adap->timeout))
15485756a06SHans Verkuil 				return -ETIMEDOUT;
15585756a06SHans Verkuil 			cond_resched();
1560664fb61SHans Verkuil 			status = ioread8(&regs->cr_sr);
15785756a06SHans Verkuil 		}
15885756a06SHans Verkuil 
15985756a06SHans Verkuil 		/* Verify ACK */
16085756a06SHans Verkuil 		if (status & M00018_SR_BITMAP_RXACK_MSK) {
16185756a06SHans Verkuil 			/* NO ACK! */
16285756a06SHans Verkuil 			return -EIO;
16385756a06SHans Verkuil 		}
16485756a06SHans Verkuil 
16585756a06SHans Verkuil 		/* Verify arbitration */
16685756a06SHans Verkuil 		if (status & M00018_SR_BITMAP_AL_MSK) {
16785756a06SHans Verkuil 			/* Arbitration lost! */
16885756a06SHans Verkuil 			return -EIO;
16985756a06SHans Verkuil 		}
17085756a06SHans Verkuil 	}
17185756a06SHans Verkuil 	return 0;
17285756a06SHans Verkuil }
17385756a06SHans Verkuil 
17485756a06SHans Verkuil /* Do low-level i2c byte read.
17585756a06SHans Verkuil  * Returns -1 in case of an error or 0 otherwise.
17685756a06SHans Verkuil  */
1770664fb61SHans Verkuil static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs,
17885756a06SHans Verkuil 		struct i2c_adapter *adap, bool start, bool stop,
17985756a06SHans Verkuil 		u8 *data, u16 len)
18085756a06SHans Verkuil {
18185756a06SHans Verkuil 	unsigned long start_time;
18285756a06SHans Verkuil 	int status;
18385756a06SHans Verkuil 	int cmd;
18485756a06SHans Verkuil 	int i;
18585756a06SHans Verkuil 
18685756a06SHans Verkuil 	for (i = 0; i < len; i++) {
18785756a06SHans Verkuil 		/* Setup command */
18885756a06SHans Verkuil 		if (i == 0 && start != 0) {
18985756a06SHans Verkuil 			/* Read + Start */
19085756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_RD_MSK |
19185756a06SHans Verkuil 			      M00018_CR_BITMAP_STA_MSK;
19285756a06SHans Verkuil 		} else if (i == len - 1 && stop != 0) {
19385756a06SHans Verkuil 			/* Read + Stop */
19485756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_RD_MSK |
19585756a06SHans Verkuil 			      M00018_CR_BITMAP_STO_MSK;
19685756a06SHans Verkuil 		} else {
19785756a06SHans Verkuil 			/* Read only */
19885756a06SHans Verkuil 			cmd = M00018_CR_BITMAP_RD_MSK;
19985756a06SHans Verkuil 		}
20085756a06SHans Verkuil 
20185756a06SHans Verkuil 		/* Last byte to read, no ACK */
20285756a06SHans Verkuil 		if (i == len - 1)
20385756a06SHans Verkuil 			cmd |= M00018_CR_BITMAP_ACK_MSK;
20485756a06SHans Verkuil 
20585756a06SHans Verkuil 		/* Execute command */
2060664fb61SHans Verkuil 		iowrite8(cmd, &regs->cr_sr);
20785756a06SHans Verkuil 
20885756a06SHans Verkuil 		/* Wait for transfer to complete (TIP = 0) */
20985756a06SHans Verkuil 		start_time = jiffies;
2100664fb61SHans Verkuil 		status = ioread8(&regs->cr_sr);
21185756a06SHans Verkuil 		while (status & M00018_SR_BITMAP_TIP_MSK) {
21285756a06SHans Verkuil 			if (time_after(jiffies, start_time + adap->timeout))
21385756a06SHans Verkuil 				return -ETIMEDOUT;
21485756a06SHans Verkuil 			cond_resched();
2150664fb61SHans Verkuil 			status = ioread8(&regs->cr_sr);
21685756a06SHans Verkuil 		}
21785756a06SHans Verkuil 
21885756a06SHans Verkuil 		/* Verify arbitration */
21985756a06SHans Verkuil 		if (status & M00018_SR_BITMAP_AL_MSK) {
22085756a06SHans Verkuil 			/* Arbitration lost! */
22185756a06SHans Verkuil 			return -EIO;
22285756a06SHans Verkuil 		}
22385756a06SHans Verkuil 
22485756a06SHans Verkuil 		/* Store data */
2250664fb61SHans Verkuil 		data[i] = ioread8(&regs->txr_rxr);
22685756a06SHans Verkuil 	}
22785756a06SHans Verkuil 	return 0;
22885756a06SHans Verkuil }
22985756a06SHans Verkuil 
23085756a06SHans Verkuil /* Generate stop condition on i2c bus.
23185756a06SHans Verkuil  * The m00018 stop isn't doing the right thing (wrong timing).
23285756a06SHans Verkuil  * So instead send a start condition, 8 zeroes and a stop condition.
23385756a06SHans Verkuil  */
2340664fb61SHans Verkuil static int cobalt_stop(struct cobalt_i2c_regs __iomem *regs,
23585756a06SHans Verkuil 		struct i2c_adapter *adap)
23685756a06SHans Verkuil {
23785756a06SHans Verkuil 	u8 data = 0;
23885756a06SHans Verkuil 
23985756a06SHans Verkuil 	return cobalt_tx_bytes(regs, adap, true, true, &data, 1);
24085756a06SHans Verkuil }
24185756a06SHans Verkuil 
24285756a06SHans Verkuil static int cobalt_xfer(struct i2c_adapter *adap,
24385756a06SHans Verkuil 			struct i2c_msg msgs[], int num)
24485756a06SHans Verkuil {
24585756a06SHans Verkuil 	struct cobalt_i2c_data *data = adap->algo_data;
2460664fb61SHans Verkuil 	struct cobalt_i2c_regs __iomem *regs = data->regs;
24785756a06SHans Verkuil 	struct i2c_msg *pmsg;
24885756a06SHans Verkuil 	unsigned short flags;
24985756a06SHans Verkuil 	int ret = 0;
25085756a06SHans Verkuil 	int i, j;
25185756a06SHans Verkuil 
25285756a06SHans Verkuil 	for (i = 0; i < num; i++) {
25385756a06SHans Verkuil 		int stop = (i == num - 1);
25485756a06SHans Verkuil 
25585756a06SHans Verkuil 		pmsg = &msgs[i];
25685756a06SHans Verkuil 		flags = pmsg->flags;
25785756a06SHans Verkuil 
25885756a06SHans Verkuil 		if (!(pmsg->flags & I2C_M_NOSTART)) {
25985756a06SHans Verkuil 			u8 addr = pmsg->addr << 1;
26085756a06SHans Verkuil 
26185756a06SHans Verkuil 			if (flags & I2C_M_RD)
26285756a06SHans Verkuil 				addr |= 1;
26385756a06SHans Verkuil 			if (flags & I2C_M_REV_DIR_ADDR)
26485756a06SHans Verkuil 				addr ^= 1;
26585756a06SHans Verkuil 			for (j = 0; j < adap->retries; j++) {
26685756a06SHans Verkuil 				ret = cobalt_tx_bytes(regs, adap, true, false,
26785756a06SHans Verkuil 						      &addr, 1);
26885756a06SHans Verkuil 				if (!ret)
26985756a06SHans Verkuil 					break;
27085756a06SHans Verkuil 				cobalt_stop(regs, adap);
27185756a06SHans Verkuil 			}
27285756a06SHans Verkuil 			if (ret < 0)
27385756a06SHans Verkuil 				return ret;
27485756a06SHans Verkuil 			ret = 0;
27585756a06SHans Verkuil 		}
27685756a06SHans Verkuil 		if (pmsg->flags & I2C_M_RD) {
27785756a06SHans Verkuil 			/* read bytes into buffer */
27885756a06SHans Verkuil 			ret = cobalt_rx_bytes(regs, adap, false, stop,
27985756a06SHans Verkuil 					pmsg->buf, pmsg->len);
28085756a06SHans Verkuil 			if (ret < 0)
28185756a06SHans Verkuil 				goto bailout;
28285756a06SHans Verkuil 		} else {
28385756a06SHans Verkuil 			/* write bytes from buffer */
28485756a06SHans Verkuil 			ret = cobalt_tx_bytes(regs, adap, false, stop,
28585756a06SHans Verkuil 					pmsg->buf, pmsg->len);
28685756a06SHans Verkuil 			if (ret < 0)
28785756a06SHans Verkuil 				goto bailout;
28885756a06SHans Verkuil 		}
28985756a06SHans Verkuil 	}
29085756a06SHans Verkuil 	ret = i;
29185756a06SHans Verkuil 
29285756a06SHans Verkuil bailout:
29385756a06SHans Verkuil 	if (ret < 0)
29485756a06SHans Verkuil 		cobalt_stop(regs, adap);
29585756a06SHans Verkuil 	return ret;
29685756a06SHans Verkuil }
29785756a06SHans Verkuil 
29885756a06SHans Verkuil static u32 cobalt_func(struct i2c_adapter *adap)
29985756a06SHans Verkuil {
30085756a06SHans Verkuil 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
30185756a06SHans Verkuil }
30285756a06SHans Verkuil 
30385756a06SHans Verkuil /* template for i2c-bit-algo */
30485756a06SHans Verkuil static struct i2c_adapter cobalt_i2c_adap_template = {
30585756a06SHans Verkuil 	.name = "cobalt i2c driver",
30685756a06SHans Verkuil 	.algo = NULL,                   /* set by i2c-algo-bit */
30785756a06SHans Verkuil 	.algo_data = NULL,              /* filled from template */
30885756a06SHans Verkuil 	.owner = THIS_MODULE,
30985756a06SHans Verkuil };
31085756a06SHans Verkuil 
31185756a06SHans Verkuil static const struct i2c_algorithm cobalt_algo = {
31285756a06SHans Verkuil 	.master_xfer	= cobalt_xfer,
31385756a06SHans Verkuil 	.functionality	= cobalt_func,
31485756a06SHans Verkuil };
31585756a06SHans Verkuil 
31685756a06SHans Verkuil /* init + register i2c algo-bit adapter */
31785756a06SHans Verkuil int cobalt_i2c_init(struct cobalt *cobalt)
31885756a06SHans Verkuil {
31985756a06SHans Verkuil 	int i, err;
32085756a06SHans Verkuil 	int status;
32185756a06SHans Verkuil 	int prescale;
32285756a06SHans Verkuil 	unsigned long start_time;
32385756a06SHans Verkuil 
32485756a06SHans Verkuil 	cobalt_dbg(1, "i2c init\n");
32585756a06SHans Verkuil 
32685756a06SHans Verkuil 	/* Define I2C clock prescaler */
32785756a06SHans Verkuil 	prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1;
32885756a06SHans Verkuil 
32985756a06SHans Verkuil 	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
3300664fb61SHans Verkuil 		struct cobalt_i2c_regs __iomem *regs =
33185756a06SHans Verkuil 			cobalt_i2c_regs(cobalt, i);
33285756a06SHans Verkuil 		struct i2c_adapter *adap = &cobalt->i2c_adap[i];
33385756a06SHans Verkuil 
33485756a06SHans Verkuil 		/* Disable I2C */
3350664fb61SHans Verkuil 		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->cr_sr);
3360664fb61SHans Verkuil 		iowrite8(0, &regs->ctr);
3370664fb61SHans Verkuil 		iowrite8(0, &regs->cr_sr);
33885756a06SHans Verkuil 
33985756a06SHans Verkuil 		start_time = jiffies;
34085756a06SHans Verkuil 		do {
34185756a06SHans Verkuil 			if (time_after(jiffies, start_time + HZ)) {
34285756a06SHans Verkuil 				if (cobalt_ignore_err) {
34385756a06SHans Verkuil 					adap->dev.parent = NULL;
34485756a06SHans Verkuil 					return 0;
34585756a06SHans Verkuil 				}
34685756a06SHans Verkuil 				return -ETIMEDOUT;
34785756a06SHans Verkuil 			}
3480664fb61SHans Verkuil 			status = ioread8(&regs->cr_sr);
34985756a06SHans Verkuil 		} while (status & M00018_SR_BITMAP_TIP_MSK);
35085756a06SHans Verkuil 
35185756a06SHans Verkuil 		/* Disable I2C */
3520664fb61SHans Verkuil 		iowrite8(0, &regs->ctr);
3530664fb61SHans Verkuil 		iowrite8(0, &regs->cr_sr);
35485756a06SHans Verkuil 
35585756a06SHans Verkuil 		/* Calculate i2c prescaler */
3560664fb61SHans Verkuil 		iowrite8(prescale & 0xff, &regs->prerlo);
3570664fb61SHans Verkuil 		iowrite8((prescale >> 8) & 0xff, &regs->prerhi);
35885756a06SHans Verkuil 		/* Enable I2C, interrupts disabled */
3590664fb61SHans Verkuil 		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->ctr);
36085756a06SHans Verkuil 		/* Setup algorithm for adapter */
36185756a06SHans Verkuil 		cobalt->i2c_data[i].cobalt = cobalt;
36285756a06SHans Verkuil 		cobalt->i2c_data[i].regs = regs;
36385756a06SHans Verkuil 		*adap = cobalt_i2c_adap_template;
36485756a06SHans Verkuil 		adap->algo = &cobalt_algo;
36585756a06SHans Verkuil 		adap->algo_data = &cobalt->i2c_data[i];
36685756a06SHans Verkuil 		adap->retries = 3;
36785756a06SHans Verkuil 		sprintf(adap->name + strlen(adap->name),
36885756a06SHans Verkuil 				" #%d-%d", cobalt->instance, i);
36985756a06SHans Verkuil 		i2c_set_adapdata(adap, &cobalt->v4l2_dev);
37085756a06SHans Verkuil 		adap->dev.parent = &cobalt->pci_dev->dev;
37185756a06SHans Verkuil 		err = i2c_add_adapter(adap);
37285756a06SHans Verkuil 		if (err) {
37385756a06SHans Verkuil 			if (cobalt_ignore_err) {
37485756a06SHans Verkuil 				adap->dev.parent = NULL;
37585756a06SHans Verkuil 				return 0;
37685756a06SHans Verkuil 			}
37785756a06SHans Verkuil 			while (i--)
37885756a06SHans Verkuil 				i2c_del_adapter(&cobalt->i2c_adap[i]);
37985756a06SHans Verkuil 			return err;
38085756a06SHans Verkuil 		}
38185756a06SHans Verkuil 		cobalt_info("registered bus %s\n", adap->name);
38285756a06SHans Verkuil 	}
38385756a06SHans Verkuil 	return 0;
38485756a06SHans Verkuil }
38585756a06SHans Verkuil 
38685756a06SHans Verkuil void cobalt_i2c_exit(struct cobalt *cobalt)
38785756a06SHans Verkuil {
38885756a06SHans Verkuil 	int i;
38985756a06SHans Verkuil 
39085756a06SHans Verkuil 	cobalt_dbg(1, "i2c exit\n");
39185756a06SHans Verkuil 
39285756a06SHans Verkuil 	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
39385756a06SHans Verkuil 		cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name);
39485756a06SHans Verkuil 		i2c_del_adapter(&cobalt->i2c_adap[i]);
39585756a06SHans Verkuil 	}
39685756a06SHans Verkuil }
397