162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  cobalt I2C functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Derived from cx18-i2c.c
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates.
862306a36Sopenharmony_ci *  All rights reserved.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "cobalt-driver.h"
1262306a36Sopenharmony_ci#include "cobalt-i2c.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct cobalt_i2c_regs {
1562306a36Sopenharmony_ci	/* Clock prescaler register lo-byte */
1662306a36Sopenharmony_ci	u8 prerlo;
1762306a36Sopenharmony_ci	u8 dummy0[3];
1862306a36Sopenharmony_ci	/* Clock prescaler register high-byte */
1962306a36Sopenharmony_ci	u8 prerhi;
2062306a36Sopenharmony_ci	u8 dummy1[3];
2162306a36Sopenharmony_ci	/* Control register */
2262306a36Sopenharmony_ci	u8 ctr;
2362306a36Sopenharmony_ci	u8 dummy2[3];
2462306a36Sopenharmony_ci	/* Transmit/Receive register */
2562306a36Sopenharmony_ci	u8 txr_rxr;
2662306a36Sopenharmony_ci	u8 dummy3[3];
2762306a36Sopenharmony_ci	/* Command and Status register */
2862306a36Sopenharmony_ci	u8 cr_sr;
2962306a36Sopenharmony_ci	u8 dummy4[3];
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* CTR[7:0] - Control register */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* I2C Core enable bit */
3562306a36Sopenharmony_ci#define M00018_CTR_BITMAP_EN_MSK	(1 << 7)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* I2C Core interrupt enable bit */
3862306a36Sopenharmony_ci#define M00018_CTR_BITMAP_IEN_MSK	(1 << 6)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* CR[7:0] - Command register */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* I2C start condition */
4362306a36Sopenharmony_ci#define M00018_CR_BITMAP_STA_MSK	(1 << 7)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* I2C stop condition */
4662306a36Sopenharmony_ci#define M00018_CR_BITMAP_STO_MSK	(1 << 6)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* I2C read from slave */
4962306a36Sopenharmony_ci#define M00018_CR_BITMAP_RD_MSK		(1 << 5)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* I2C write to slave */
5262306a36Sopenharmony_ci#define M00018_CR_BITMAP_WR_MSK		(1 << 4)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* I2C ack */
5562306a36Sopenharmony_ci#define M00018_CR_BITMAP_ACK_MSK	(1 << 3)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* I2C Interrupt ack */
5862306a36Sopenharmony_ci#define M00018_CR_BITMAP_IACK_MSK	(1 << 0)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* SR[7:0] - Status register */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Receive acknowledge from slave */
6362306a36Sopenharmony_ci#define M00018_SR_BITMAP_RXACK_MSK	(1 << 7)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* Busy, I2C bus busy (as defined by start / stop bits) */
6662306a36Sopenharmony_ci#define M00018_SR_BITMAP_BUSY_MSK	(1 << 6)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Arbitration lost - core lost arbitration */
6962306a36Sopenharmony_ci#define M00018_SR_BITMAP_AL_MSK		(1 << 5)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Transfer in progress */
7262306a36Sopenharmony_ci#define M00018_SR_BITMAP_TIP_MSK	(1 << 1)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Interrupt flag */
7562306a36Sopenharmony_ci#define M00018_SR_BITMAP_IF_MSK		(1 << 0)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* Frequency, in Hz */
7862306a36Sopenharmony_ci#define I2C_FREQUENCY			400000
7962306a36Sopenharmony_ci#define ALT_CPU_FREQ			83333333
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic struct cobalt_i2c_regs __iomem *
8262306a36Sopenharmony_cicobalt_i2c_regs(struct cobalt *cobalt, unsigned idx)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	switch (idx) {
8562306a36Sopenharmony_ci	case 0:
8662306a36Sopenharmony_ci	default:
8762306a36Sopenharmony_ci		return (struct cobalt_i2c_regs __iomem *)
8862306a36Sopenharmony_ci			(cobalt->bar1 + COBALT_I2C_0_BASE);
8962306a36Sopenharmony_ci	case 1:
9062306a36Sopenharmony_ci		return (struct cobalt_i2c_regs __iomem *)
9162306a36Sopenharmony_ci			(cobalt->bar1 + COBALT_I2C_1_BASE);
9262306a36Sopenharmony_ci	case 2:
9362306a36Sopenharmony_ci		return (struct cobalt_i2c_regs __iomem *)
9462306a36Sopenharmony_ci			(cobalt->bar1 + COBALT_I2C_2_BASE);
9562306a36Sopenharmony_ci	case 3:
9662306a36Sopenharmony_ci		return (struct cobalt_i2c_regs __iomem *)
9762306a36Sopenharmony_ci			(cobalt->bar1 + COBALT_I2C_3_BASE);
9862306a36Sopenharmony_ci	case 4:
9962306a36Sopenharmony_ci		return (struct cobalt_i2c_regs __iomem *)
10062306a36Sopenharmony_ci			(cobalt->bar1 + COBALT_I2C_HSMA_BASE);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* Do low-level i2c byte transfer.
10562306a36Sopenharmony_ci * Returns -1 in case of an error or 0 otherwise.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_cistatic int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs,
10862306a36Sopenharmony_ci		struct i2c_adapter *adap, bool start, bool stop,
10962306a36Sopenharmony_ci		u8 *data, u16 len)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	unsigned long start_time;
11262306a36Sopenharmony_ci	int status;
11362306a36Sopenharmony_ci	int cmd;
11462306a36Sopenharmony_ci	int i;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
11762306a36Sopenharmony_ci		/* Setup data */
11862306a36Sopenharmony_ci		iowrite8(data[i], &regs->txr_rxr);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		/* Setup command */
12162306a36Sopenharmony_ci		if (i == 0 && start) {
12262306a36Sopenharmony_ci			/* Write + Start */
12362306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_WR_MSK |
12462306a36Sopenharmony_ci			      M00018_CR_BITMAP_STA_MSK;
12562306a36Sopenharmony_ci		} else if (i == len - 1 && stop) {
12662306a36Sopenharmony_ci			/* Write + Stop */
12762306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_WR_MSK |
12862306a36Sopenharmony_ci			      M00018_CR_BITMAP_STO_MSK;
12962306a36Sopenharmony_ci		} else {
13062306a36Sopenharmony_ci			/* Write only */
13162306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_WR_MSK;
13262306a36Sopenharmony_ci		}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		/* Execute command */
13562306a36Sopenharmony_ci		iowrite8(cmd, &regs->cr_sr);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		/* Wait for transfer to complete (TIP = 0) */
13862306a36Sopenharmony_ci		start_time = jiffies;
13962306a36Sopenharmony_ci		status = ioread8(&regs->cr_sr);
14062306a36Sopenharmony_ci		while (status & M00018_SR_BITMAP_TIP_MSK) {
14162306a36Sopenharmony_ci			if (time_after(jiffies, start_time + adap->timeout))
14262306a36Sopenharmony_ci				return -ETIMEDOUT;
14362306a36Sopenharmony_ci			cond_resched();
14462306a36Sopenharmony_ci			status = ioread8(&regs->cr_sr);
14562306a36Sopenharmony_ci		}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		/* Verify ACK */
14862306a36Sopenharmony_ci		if (status & M00018_SR_BITMAP_RXACK_MSK) {
14962306a36Sopenharmony_ci			/* NO ACK! */
15062306a36Sopenharmony_ci			return -EIO;
15162306a36Sopenharmony_ci		}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		/* Verify arbitration */
15462306a36Sopenharmony_ci		if (status & M00018_SR_BITMAP_AL_MSK) {
15562306a36Sopenharmony_ci			/* Arbitration lost! */
15662306a36Sopenharmony_ci			return -EIO;
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci	}
15962306a36Sopenharmony_ci	return 0;
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* Do low-level i2c byte read.
16362306a36Sopenharmony_ci * Returns -1 in case of an error or 0 otherwise.
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cistatic int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs,
16662306a36Sopenharmony_ci		struct i2c_adapter *adap, bool start, bool stop,
16762306a36Sopenharmony_ci		u8 *data, u16 len)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	unsigned long start_time;
17062306a36Sopenharmony_ci	int status;
17162306a36Sopenharmony_ci	int cmd;
17262306a36Sopenharmony_ci	int i;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
17562306a36Sopenharmony_ci		/* Setup command */
17662306a36Sopenharmony_ci		if (i == 0 && start) {
17762306a36Sopenharmony_ci			/* Read + Start */
17862306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_RD_MSK |
17962306a36Sopenharmony_ci			      M00018_CR_BITMAP_STA_MSK;
18062306a36Sopenharmony_ci		} else if (i == len - 1 && stop) {
18162306a36Sopenharmony_ci			/* Read + Stop */
18262306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_RD_MSK |
18362306a36Sopenharmony_ci			      M00018_CR_BITMAP_STO_MSK;
18462306a36Sopenharmony_ci		} else {
18562306a36Sopenharmony_ci			/* Read only */
18662306a36Sopenharmony_ci			cmd = M00018_CR_BITMAP_RD_MSK;
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		/* Last byte to read, no ACK */
19062306a36Sopenharmony_ci		if (i == len - 1)
19162306a36Sopenharmony_ci			cmd |= M00018_CR_BITMAP_ACK_MSK;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		/* Execute command */
19462306a36Sopenharmony_ci		iowrite8(cmd, &regs->cr_sr);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		/* Wait for transfer to complete (TIP = 0) */
19762306a36Sopenharmony_ci		start_time = jiffies;
19862306a36Sopenharmony_ci		status = ioread8(&regs->cr_sr);
19962306a36Sopenharmony_ci		while (status & M00018_SR_BITMAP_TIP_MSK) {
20062306a36Sopenharmony_ci			if (time_after(jiffies, start_time + adap->timeout))
20162306a36Sopenharmony_ci				return -ETIMEDOUT;
20262306a36Sopenharmony_ci			cond_resched();
20362306a36Sopenharmony_ci			status = ioread8(&regs->cr_sr);
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		/* Verify arbitration */
20762306a36Sopenharmony_ci		if (status & M00018_SR_BITMAP_AL_MSK) {
20862306a36Sopenharmony_ci			/* Arbitration lost! */
20962306a36Sopenharmony_ci			return -EIO;
21062306a36Sopenharmony_ci		}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		/* Store data */
21362306a36Sopenharmony_ci		data[i] = ioread8(&regs->txr_rxr);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci/* Generate stop condition on i2c bus.
21962306a36Sopenharmony_ci * The m00018 stop isn't doing the right thing (wrong timing).
22062306a36Sopenharmony_ci * So instead send a start condition, 8 zeroes and a stop condition.
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic int cobalt_stop(struct cobalt_i2c_regs __iomem *regs,
22362306a36Sopenharmony_ci		struct i2c_adapter *adap)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	u8 data = 0;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return cobalt_tx_bytes(regs, adap, true, true, &data, 1);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int cobalt_xfer(struct i2c_adapter *adap,
23162306a36Sopenharmony_ci			struct i2c_msg msgs[], int num)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct cobalt_i2c_data *data = adap->algo_data;
23462306a36Sopenharmony_ci	struct cobalt_i2c_regs __iomem *regs = data->regs;
23562306a36Sopenharmony_ci	struct i2c_msg *pmsg;
23662306a36Sopenharmony_ci	unsigned short flags;
23762306a36Sopenharmony_ci	int ret = 0;
23862306a36Sopenharmony_ci	int i, j;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
24162306a36Sopenharmony_ci		int stop = (i == num - 1);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		pmsg = &msgs[i];
24462306a36Sopenharmony_ci		flags = pmsg->flags;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		if (!(pmsg->flags & I2C_M_NOSTART)) {
24762306a36Sopenharmony_ci			u8 addr = pmsg->addr << 1;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			if (flags & I2C_M_RD)
25062306a36Sopenharmony_ci				addr |= 1;
25162306a36Sopenharmony_ci			if (flags & I2C_M_REV_DIR_ADDR)
25262306a36Sopenharmony_ci				addr ^= 1;
25362306a36Sopenharmony_ci			for (j = 0; j < adap->retries; j++) {
25462306a36Sopenharmony_ci				ret = cobalt_tx_bytes(regs, adap, true, false,
25562306a36Sopenharmony_ci						      &addr, 1);
25662306a36Sopenharmony_ci				if (!ret)
25762306a36Sopenharmony_ci					break;
25862306a36Sopenharmony_ci				cobalt_stop(regs, adap);
25962306a36Sopenharmony_ci			}
26062306a36Sopenharmony_ci			if (ret < 0)
26162306a36Sopenharmony_ci				return ret;
26262306a36Sopenharmony_ci			ret = 0;
26362306a36Sopenharmony_ci		}
26462306a36Sopenharmony_ci		if (pmsg->flags & I2C_M_RD) {
26562306a36Sopenharmony_ci			/* read bytes into buffer */
26662306a36Sopenharmony_ci			ret = cobalt_rx_bytes(regs, adap, false, stop,
26762306a36Sopenharmony_ci					pmsg->buf, pmsg->len);
26862306a36Sopenharmony_ci			if (ret < 0)
26962306a36Sopenharmony_ci				goto bailout;
27062306a36Sopenharmony_ci		} else {
27162306a36Sopenharmony_ci			/* write bytes from buffer */
27262306a36Sopenharmony_ci			ret = cobalt_tx_bytes(regs, adap, false, stop,
27362306a36Sopenharmony_ci					pmsg->buf, pmsg->len);
27462306a36Sopenharmony_ci			if (ret < 0)
27562306a36Sopenharmony_ci				goto bailout;
27662306a36Sopenharmony_ci		}
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci	ret = i;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cibailout:
28162306a36Sopenharmony_ci	if (ret < 0)
28262306a36Sopenharmony_ci		cobalt_stop(regs, adap);
28362306a36Sopenharmony_ci	return ret;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic u32 cobalt_func(struct i2c_adapter *adap)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/* template for i2c-bit-algo */
29262306a36Sopenharmony_cistatic const struct i2c_adapter cobalt_i2c_adap_template = {
29362306a36Sopenharmony_ci	.name = "cobalt i2c driver",
29462306a36Sopenharmony_ci	.algo = NULL,                   /* set by i2c-algo-bit */
29562306a36Sopenharmony_ci	.algo_data = NULL,              /* filled from template */
29662306a36Sopenharmony_ci	.owner = THIS_MODULE,
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic const struct i2c_algorithm cobalt_algo = {
30062306a36Sopenharmony_ci	.master_xfer	= cobalt_xfer,
30162306a36Sopenharmony_ci	.functionality	= cobalt_func,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/* init + register i2c algo-bit adapter */
30562306a36Sopenharmony_ciint cobalt_i2c_init(struct cobalt *cobalt)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	int i, err;
30862306a36Sopenharmony_ci	int status;
30962306a36Sopenharmony_ci	int prescale;
31062306a36Sopenharmony_ci	unsigned long start_time;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	cobalt_dbg(1, "i2c init\n");
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* Define I2C clock prescaler */
31562306a36Sopenharmony_ci	prescale = ((ALT_CPU_FREQ) / (5 * I2C_FREQUENCY)) - 1;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
31862306a36Sopenharmony_ci		struct cobalt_i2c_regs __iomem *regs =
31962306a36Sopenharmony_ci			cobalt_i2c_regs(cobalt, i);
32062306a36Sopenharmony_ci		struct i2c_adapter *adap = &cobalt->i2c_adap[i];
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		/* Disable I2C */
32362306a36Sopenharmony_ci		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->cr_sr);
32462306a36Sopenharmony_ci		iowrite8(0, &regs->ctr);
32562306a36Sopenharmony_ci		iowrite8(0, &regs->cr_sr);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		start_time = jiffies;
32862306a36Sopenharmony_ci		do {
32962306a36Sopenharmony_ci			if (time_after(jiffies, start_time + HZ)) {
33062306a36Sopenharmony_ci				if (cobalt_ignore_err) {
33162306a36Sopenharmony_ci					adap->dev.parent = NULL;
33262306a36Sopenharmony_ci					return 0;
33362306a36Sopenharmony_ci				}
33462306a36Sopenharmony_ci				return -ETIMEDOUT;
33562306a36Sopenharmony_ci			}
33662306a36Sopenharmony_ci			status = ioread8(&regs->cr_sr);
33762306a36Sopenharmony_ci		} while (status & M00018_SR_BITMAP_TIP_MSK);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		/* Disable I2C */
34062306a36Sopenharmony_ci		iowrite8(0, &regs->ctr);
34162306a36Sopenharmony_ci		iowrite8(0, &regs->cr_sr);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		/* Calculate i2c prescaler */
34462306a36Sopenharmony_ci		iowrite8(prescale & 0xff, &regs->prerlo);
34562306a36Sopenharmony_ci		iowrite8((prescale >> 8) & 0xff, &regs->prerhi);
34662306a36Sopenharmony_ci		/* Enable I2C, interrupts disabled */
34762306a36Sopenharmony_ci		iowrite8(M00018_CTR_BITMAP_EN_MSK, &regs->ctr);
34862306a36Sopenharmony_ci		/* Setup algorithm for adapter */
34962306a36Sopenharmony_ci		cobalt->i2c_data[i].cobalt = cobalt;
35062306a36Sopenharmony_ci		cobalt->i2c_data[i].regs = regs;
35162306a36Sopenharmony_ci		*adap = cobalt_i2c_adap_template;
35262306a36Sopenharmony_ci		adap->algo = &cobalt_algo;
35362306a36Sopenharmony_ci		adap->algo_data = &cobalt->i2c_data[i];
35462306a36Sopenharmony_ci		adap->retries = 3;
35562306a36Sopenharmony_ci		sprintf(adap->name + strlen(adap->name),
35662306a36Sopenharmony_ci				" #%d-%d", cobalt->instance, i);
35762306a36Sopenharmony_ci		i2c_set_adapdata(adap, &cobalt->v4l2_dev);
35862306a36Sopenharmony_ci		adap->dev.parent = &cobalt->pci_dev->dev;
35962306a36Sopenharmony_ci		err = i2c_add_adapter(adap);
36062306a36Sopenharmony_ci		if (err) {
36162306a36Sopenharmony_ci			if (cobalt_ignore_err) {
36262306a36Sopenharmony_ci				adap->dev.parent = NULL;
36362306a36Sopenharmony_ci				return 0;
36462306a36Sopenharmony_ci			}
36562306a36Sopenharmony_ci			while (i--)
36662306a36Sopenharmony_ci				i2c_del_adapter(&cobalt->i2c_adap[i]);
36762306a36Sopenharmony_ci			return err;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		cobalt_info("registered bus %s\n", adap->name);
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_civoid cobalt_i2c_exit(struct cobalt *cobalt)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	int i;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	cobalt_dbg(1, "i2c exit\n");
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	for (i = 0; i < COBALT_NUM_ADAPTERS; i++) {
38162306a36Sopenharmony_ci		cobalt_err("unregistered bus %s\n", cobalt->i2c_adap[i].name);
38262306a36Sopenharmony_ci		i2c_del_adapter(&cobalt->i2c_adap[i]);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci}
385