162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * i2c-algo-pcf.c i2c driver algorithms for PCF8584 adapters
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Copyright (C) 1995-1997 Simon G. Vogl
662306a36Sopenharmony_ci *		   1998-2000 Hans Berglund
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
962306a36Sopenharmony_ci * Frodo Looijaard <frodol@dds.nl>, and also from Martin Bailey
1062306a36Sopenharmony_ci * <mbailey@littlefeet-inc.com>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Partially rewriten by Oleg I. Vdovikin <vdovikin@jscc.ru> to handle multiple
1362306a36Sopenharmony_ci * messages, proper stop/repstart signaling during receive, added detect code
1462306a36Sopenharmony_ci */
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/delay.h>
1962306a36Sopenharmony_ci#include <linux/errno.h>
2062306a36Sopenharmony_ci#include <linux/i2c.h>
2162306a36Sopenharmony_ci#include <linux/i2c-algo-pcf.h>
2262306a36Sopenharmony_ci#include "i2c-algo-pcf.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DEB2(x) if (i2c_debug >= 2) x
2662306a36Sopenharmony_ci#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */
2762306a36Sopenharmony_ci#define DEBPROTO(x) if (i2c_debug >= 9) x;
2862306a36Sopenharmony_ci	/* debug the protocol by showing transferred bits */
2962306a36Sopenharmony_ci#define DEF_TIMEOUT 16
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*
3262306a36Sopenharmony_ci * module parameters:
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistatic int i2c_debug;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* setting states on the bus with the right timing: */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val)
3962306a36Sopenharmony_ci#define get_pcf(adap, ctl) adap->getpcf(adap->data, ctl)
4062306a36Sopenharmony_ci#define get_own(adap) adap->getown(adap->data)
4162306a36Sopenharmony_ci#define get_clock(adap) adap->getclock(adap->data)
4262306a36Sopenharmony_ci#define i2c_outb(adap, val) adap->setpcf(adap->data, 0, val)
4362306a36Sopenharmony_ci#define i2c_inb(adap) adap->getpcf(adap->data, 0)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* other auxiliary functions */
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic void i2c_start(struct i2c_algo_pcf_data *adap)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	DEBPROTO(printk(KERN_DEBUG "S "));
5062306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_START);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void i2c_repstart(struct i2c_algo_pcf_data *adap)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	DEBPROTO(printk(" Sr "));
5662306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_REPSTART);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void i2c_stop(struct i2c_algo_pcf_data *adap)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	DEBPROTO(printk("P\n"));
6262306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_STOP);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void handle_lab(struct i2c_algo_pcf_data *adap, const int *status)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	DEB2(printk(KERN_INFO
6862306a36Sopenharmony_ci		"i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n",
6962306a36Sopenharmony_ci		*status));
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * Cleanup from LAB -- reset and enable ESO.
7262306a36Sopenharmony_ci	 * This resets the PCF8584; since we've lost the bus, no
7362306a36Sopenharmony_ci	 * further attempts should be made by callers to clean up
7462306a36Sopenharmony_ci	 * (no i2c_stop() etc.)
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_PIN);
7762306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_ESO);
7862306a36Sopenharmony_ci	/*
7962306a36Sopenharmony_ci	 * We pause for a time period sufficient for any running
8062306a36Sopenharmony_ci	 * I2C transaction to complete -- the arbitration logic won't
8162306a36Sopenharmony_ci	 * work properly until the next START is seen.
8262306a36Sopenharmony_ci	 * It is assumed the bus driver or client has set a proper value.
8362306a36Sopenharmony_ci	 *
8462306a36Sopenharmony_ci	 * REVISIT: should probably use msleep instead of mdelay if we
8562306a36Sopenharmony_ci	 * know we can sleep.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	if (adap->lab_mdelay)
8862306a36Sopenharmony_ci		mdelay(adap->lab_mdelay);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	DEB2(printk(KERN_INFO
9162306a36Sopenharmony_ci		"i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n",
9262306a36Sopenharmony_ci		get_pcf(adap, 1)));
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int wait_for_bb(struct i2c_algo_pcf_data *adap)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	int timeout = DEF_TIMEOUT;
9962306a36Sopenharmony_ci	int status;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	status = get_pcf(adap, 1);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	while (!(status & I2C_PCF_BB) && --timeout) {
10462306a36Sopenharmony_ci		udelay(100); /* wait for 100 us */
10562306a36Sopenharmony_ci		status = get_pcf(adap, 1);
10662306a36Sopenharmony_ci	}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (timeout == 0) {
10962306a36Sopenharmony_ci		printk(KERN_ERR "Timeout waiting for Bus Busy\n");
11062306a36Sopenharmony_ci		return -ETIMEDOUT;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	return 0;
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	int timeout = DEF_TIMEOUT;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	*status = get_pcf(adap, 1);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	while ((*status & I2C_PCF_PIN) && --timeout) {
12462306a36Sopenharmony_ci		adap->waitforpin(adap->data);
12562306a36Sopenharmony_ci		*status = get_pcf(adap, 1);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci	if (*status & I2C_PCF_LAB) {
12862306a36Sopenharmony_ci		handle_lab(adap, status);
12962306a36Sopenharmony_ci		return -EINTR;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (timeout == 0)
13362306a36Sopenharmony_ci		return -ETIMEDOUT;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * This should perform the 'PCF8584 initialization sequence' as described
14062306a36Sopenharmony_ci * in the Philips IC12 data book (1995, Aug 29).
14162306a36Sopenharmony_ci * There should be a 30 clock cycle wait after reset, I assume this
14262306a36Sopenharmony_ci * has been fulfilled.
14362306a36Sopenharmony_ci * There should be a delay at the end equal to the longest I2C message
14462306a36Sopenharmony_ci * to synchronize the BB-bit (in multimaster systems). How long is
14562306a36Sopenharmony_ci * this? I assume 1 second is always long enough.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * vdovikin: added detect code for PCF8584
14862306a36Sopenharmony_ci */
14962306a36Sopenharmony_cistatic int pcf_init_8584 (struct i2c_algo_pcf_data *adap)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	unsigned char temp;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n",
15462306a36Sopenharmony_ci				get_pcf(adap, 1)));
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* S1=0x80: S0 selected, serial interface off */
15762306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_PIN);
15862306a36Sopenharmony_ci	/*
15962306a36Sopenharmony_ci	 * check to see S1 now used as R/W ctrl -
16062306a36Sopenharmony_ci	 * PCF8584 does that when ESO is zero
16162306a36Sopenharmony_ci	 */
16262306a36Sopenharmony_ci	if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) {
16362306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp));
16462306a36Sopenharmony_ci		return -ENXIO; /* definitely not PCF8584 */
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* load own address in S0, effective address is (own << 1) */
16862306a36Sopenharmony_ci	i2c_outb(adap, get_own(adap));
16962306a36Sopenharmony_ci	/* check it's really written */
17062306a36Sopenharmony_ci	if ((temp = i2c_inb(adap)) != get_own(adap)) {
17162306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp));
17262306a36Sopenharmony_ci		return -ENXIO;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* S1=0xA0, next byte in S2 */
17662306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1);
17762306a36Sopenharmony_ci	/* check to see S2 now selected */
17862306a36Sopenharmony_ci	if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) {
17962306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp));
18062306a36Sopenharmony_ci		return -ENXIO;
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* load clock register S2 */
18462306a36Sopenharmony_ci	i2c_outb(adap, get_clock(adap));
18562306a36Sopenharmony_ci	/* check it's really written, the only 5 lowest bits does matter */
18662306a36Sopenharmony_ci	if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) {
18762306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp));
18862306a36Sopenharmony_ci		return -ENXIO;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Enable serial interface, idle, S0 selected */
19262306a36Sopenharmony_ci	set_pcf(adap, 1, I2C_PCF_IDLE);
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* check to see PCF is really idled and we can access status register */
19562306a36Sopenharmony_ci	if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) {
19662306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp));
19762306a36Sopenharmony_ci		return -ENXIO;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n");
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
20662306a36Sopenharmony_ci			 int count, int last)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
20962306a36Sopenharmony_ci	int wrcount, status, timeout;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	for (wrcount=0; wrcount<count; ++wrcount) {
21262306a36Sopenharmony_ci		DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n",
21362306a36Sopenharmony_ci				buf[wrcount] & 0xff));
21462306a36Sopenharmony_ci		i2c_outb(adap, buf[wrcount]);
21562306a36Sopenharmony_ci		timeout = wait_for_pin(adap, &status);
21662306a36Sopenharmony_ci		if (timeout) {
21762306a36Sopenharmony_ci			if (timeout == -EINTR)
21862306a36Sopenharmony_ci				return -EINTR; /* arbitration lost */
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci			i2c_stop(adap);
22162306a36Sopenharmony_ci			dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n");
22262306a36Sopenharmony_ci			return -EREMOTEIO; /* got a better one ?? */
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci		if (status & I2C_PCF_LRB) {
22562306a36Sopenharmony_ci			i2c_stop(adap);
22662306a36Sopenharmony_ci			dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n");
22762306a36Sopenharmony_ci			return -EREMOTEIO; /* got a better one ?? */
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci	if (last)
23162306a36Sopenharmony_ci		i2c_stop(adap);
23262306a36Sopenharmony_ci	else
23362306a36Sopenharmony_ci		i2c_repstart(adap);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return wrcount;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf,
23962306a36Sopenharmony_ci			 int count, int last)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int i, status;
24262306a36Sopenharmony_ci	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
24362306a36Sopenharmony_ci	int wfp;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* increment number of bytes to read by one -- read dummy byte */
24662306a36Sopenharmony_ci	for (i = 0; i <= count; i++) {
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		if ((wfp = wait_for_pin(adap, &status))) {
24962306a36Sopenharmony_ci			if (wfp == -EINTR)
25062306a36Sopenharmony_ci				return -EINTR; /* arbitration lost */
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci			i2c_stop(adap);
25362306a36Sopenharmony_ci			dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n");
25462306a36Sopenharmony_ci			return -1;
25562306a36Sopenharmony_ci		}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci		if ((status & I2C_PCF_LRB) && (i != count)) {
25862306a36Sopenharmony_ci			i2c_stop(adap);
25962306a36Sopenharmony_ci			dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n");
26062306a36Sopenharmony_ci			return -1;
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (i == count - 1) {
26462306a36Sopenharmony_ci			set_pcf(adap, 1, I2C_PCF_ESO);
26562306a36Sopenharmony_ci		} else if (i == count) {
26662306a36Sopenharmony_ci			if (last)
26762306a36Sopenharmony_ci				i2c_stop(adap);
26862306a36Sopenharmony_ci			else
26962306a36Sopenharmony_ci				i2c_repstart(adap);
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		if (i)
27362306a36Sopenharmony_ci			buf[i - 1] = i2c_inb(adap);
27462306a36Sopenharmony_ci		else
27562306a36Sopenharmony_ci			i2c_inb(adap); /* dummy read */
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	return i - 1;
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int pcf_doAddress(struct i2c_algo_pcf_data *adap,
28362306a36Sopenharmony_ci			 struct i2c_msg *msg)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	unsigned char addr = i2c_8bit_addr_from_msg(msg);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (msg->flags & I2C_M_REV_DIR_ADDR)
28862306a36Sopenharmony_ci		addr ^= 1;
28962306a36Sopenharmony_ci	i2c_outb(adap, addr);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int pcf_xfer(struct i2c_adapter *i2c_adap,
29562306a36Sopenharmony_ci		    struct i2c_msg *msgs,
29662306a36Sopenharmony_ci		    int num)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
29962306a36Sopenharmony_ci	struct i2c_msg *pmsg;
30062306a36Sopenharmony_ci	int i;
30162306a36Sopenharmony_ci	int ret=0, timeout, status;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (adap->xfer_begin)
30462306a36Sopenharmony_ci		adap->xfer_begin(adap->data);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Check for bus busy */
30762306a36Sopenharmony_ci	timeout = wait_for_bb(adap);
30862306a36Sopenharmony_ci	if (timeout) {
30962306a36Sopenharmony_ci		DEB2(printk(KERN_ERR "i2c-algo-pcf.o: "
31062306a36Sopenharmony_ci			    "Timeout waiting for BB in pcf_xfer\n");)
31162306a36Sopenharmony_ci		i = -EIO;
31262306a36Sopenharmony_ci		goto out;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	for (i = 0;ret >= 0 && i < num; i++) {
31662306a36Sopenharmony_ci		pmsg = &msgs[i];
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
31962306a36Sopenharmony_ci		     pmsg->flags & I2C_M_RD ? "read" : "write",
32062306a36Sopenharmony_ci		     pmsg->len, pmsg->addr, i + 1, num);)
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		ret = pcf_doAddress(adap, pmsg);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		/* Send START */
32562306a36Sopenharmony_ci		if (i == 0)
32662306a36Sopenharmony_ci			i2c_start(adap);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/* Wait for PIN (pending interrupt NOT) */
32962306a36Sopenharmony_ci		timeout = wait_for_pin(adap, &status);
33062306a36Sopenharmony_ci		if (timeout) {
33162306a36Sopenharmony_ci			if (timeout == -EINTR) {
33262306a36Sopenharmony_ci				/* arbitration lost */
33362306a36Sopenharmony_ci				i = -EINTR;
33462306a36Sopenharmony_ci				goto out;
33562306a36Sopenharmony_ci			}
33662306a36Sopenharmony_ci			i2c_stop(adap);
33762306a36Sopenharmony_ci			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting "
33862306a36Sopenharmony_ci				    "for PIN(1) in pcf_xfer\n");)
33962306a36Sopenharmony_ci			i = -EREMOTEIO;
34062306a36Sopenharmony_ci			goto out;
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		/* Check LRB (last rcvd bit - slave ack) */
34462306a36Sopenharmony_ci		if (status & I2C_PCF_LRB) {
34562306a36Sopenharmony_ci			i2c_stop(adap);
34662306a36Sopenharmony_ci			DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");)
34762306a36Sopenharmony_ci			i = -EREMOTEIO;
34862306a36Sopenharmony_ci			goto out;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
35262306a36Sopenharmony_ci			    i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		if (pmsg->flags & I2C_M_RD) {
35562306a36Sopenharmony_ci			ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len,
35662306a36Sopenharmony_ci					    (i + 1 == num));
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci			if (ret != pmsg->len) {
35962306a36Sopenharmony_ci				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
36062306a36Sopenharmony_ci					    "only read %d bytes.\n",ret));
36162306a36Sopenharmony_ci			} else {
36262306a36Sopenharmony_ci				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret));
36362306a36Sopenharmony_ci			}
36462306a36Sopenharmony_ci		} else {
36562306a36Sopenharmony_ci			ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len,
36662306a36Sopenharmony_ci					    (i + 1 == num));
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci			if (ret != pmsg->len) {
36962306a36Sopenharmony_ci				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: "
37062306a36Sopenharmony_ci					    "only wrote %d bytes.\n",ret));
37162306a36Sopenharmony_ci			} else {
37262306a36Sopenharmony_ci				DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret));
37362306a36Sopenharmony_ci			}
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ciout:
37862306a36Sopenharmony_ci	if (adap->xfer_end)
37962306a36Sopenharmony_ci		adap->xfer_end(adap->data);
38062306a36Sopenharmony_ci	return i;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic u32 pcf_func(struct i2c_adapter *adap)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
38662306a36Sopenharmony_ci	       I2C_FUNC_PROTOCOL_MANGLING;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/* exported algorithm data: */
39062306a36Sopenharmony_cistatic const struct i2c_algorithm pcf_algo = {
39162306a36Sopenharmony_ci	.master_xfer	= pcf_xfer,
39262306a36Sopenharmony_ci	.functionality	= pcf_func,
39362306a36Sopenharmony_ci};
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/*
39662306a36Sopenharmony_ci * registering functions to load algorithms at runtime
39762306a36Sopenharmony_ci */
39862306a36Sopenharmony_ciint i2c_pcf_add_bus(struct i2c_adapter *adap)
39962306a36Sopenharmony_ci{
40062306a36Sopenharmony_ci	struct i2c_algo_pcf_data *pcf_adap = adap->algo_data;
40162306a36Sopenharmony_ci	int rval;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* register new adapter to i2c module... */
40662306a36Sopenharmony_ci	adap->algo = &pcf_algo;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if ((rval = pcf_init_8584(pcf_adap)))
40962306a36Sopenharmony_ci		return rval;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	rval = i2c_add_adapter(adap);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return rval;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ciEXPORT_SYMBOL(i2c_pcf_add_bus);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ciMODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
41862306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
41962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cimodule_param(i2c_debug, int, S_IRUGO | S_IWUSR);
42262306a36Sopenharmony_ciMODULE_PARM_DESC(i2c_debug,
42362306a36Sopenharmony_ci	"debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
424