* [PATCH 2.6.38 1/1] scx200_acb.c: Add plain i2c (master_xfer / I2C_FUNC_I2C)
@ 2011-08-08 19:29 Tomas
[not found] ` <CAN=yz1iG02kqUm0pJ8sXgJ81JJerJTmWuGAkPo6UUGBTE_6Zpw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: Tomas @ 2011-08-08 19:29 UTC (permalink / raw)
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA; +Cc: jim.cromie-Re5JQEeQqe8AvxtiuMwx3w
From: Tomas Menzl <tomasamot-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Add master_xfer / I2C_FUNC_I2C by simply reusing existing FSM
scx200_acb_machine.
This adds possibility to do direct read/write on an i2c device or use
I2C_RDWR ioctl in addition to existing SM Bus API.
Signed-off-by: Tomas Menzl <tomasamot-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
----
Added plain I2C interface so that one can use plain read/write (among
others). Needed plain I2C multibyte read which is not possible with SM
bus.
Tested on Voyage Linux 0.75 (http://linux.voyage.hk/, based on Debian
Squeeze, 2.6.38, this module is original/vanilla - i.e. patch
applicable to any current version) on PC Engine WRAP 2C with Microchip
ADC MCP3421.
SM BUS interface intact, read/write worked for me (only tested single
message transactions, do not have HW to test combined transaction but
they are there...).
--- linux-source-2.6.38-voyage/drivers/i2c/busses/scx200_acb.c 2011-08-05
19:44:11.000000000 +0200
+++ linux-source-2.6.38-voyage.new/drivers/i2c/busses/scx200_acb.c 2011-08-05
22:06:18.000000000 +0200
@@ -86,6 +86,7 @@ struct scx200_acb_iface {
u8 *ptr;
char needs_reset;
unsigned len;
+ char skip_stop;
};
/* Register Definitions */
@@ -130,6 +131,7 @@ static void scx200_acb_machine(struct sc
scx200_acb_state_name[iface->state]);
iface->state = state_idle;
+ iface->skip_stop = 0;
iface->result = -ENXIO;
outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
@@ -191,7 +193,8 @@ static void scx200_acb_machine(struct sc
if (iface->len == 1) {
iface->result = 0;
iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ if (!iface->skip_stop)
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
}
*iface->ptr++ = inb(ACBSDA);
@@ -203,7 +206,8 @@ static void scx200_acb_machine(struct sc
if (iface->len == 0) {
iface->result = 0;
iface->state = state_idle;
- outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+ if (!iface->skip_stop)
+ outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
break;
}
@@ -222,6 +226,7 @@ static void scx200_acb_machine(struct sc
iface->len, status);
iface->state = state_idle;
+ iface->skip_stop = 0;
iface->result = -EIO;
iface->needs_reset = 1;
}
@@ -277,6 +282,104 @@ static void scx200_acb_reset(struct scx2
outb(inb(ACBCST) | ACBCST_BB, ACBCST);
}
+/*
+ * Generic i2c master transfer entrypoint.
+ *
+ * Basically copy of part of scx200_acb_smbus_xfer where we use existing
+ * scx200_acb_machine which already supports simple i2c with any data length
+ * (not only 0 and 1 as used by smbus) by using:
+ *
+ * state_quick -> ( state_read | state_write )+ -> state_idle
+ *
+ * Added flag skip_stop to support multimessage ops in scx200_acb_machine
+ * to be able skip stop bit between messages in state_read/state_write:
+ *
+ * S Addr Rd [A] [Data] NA S Addr Wr [A] Data [A] P
+ * ^--- no stop bit! ^--- stop bit
+ *
+ * Still missing 10b address, pec, etc...
+ */
+static int scx200_acb_i2c_master_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs,
+ int num)
+{
+ struct scx200_acb_iface *iface = i2c_get_adapdata(adapter);
+ int rc = 0;
+ char rw;
+ int len;
+ u8 *buffer;
+ u16 address;
+
+ mutex_lock(&iface->mutex);
+ while (num > 0) {
+ if (msgs->flags & I2C_M_TEN) {
+ dev_err(&adapter->dev,
+ "10b i2c address supported\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ rw = (msgs->flags & I2C_M_RD) != 0;
+ address = (msgs->addr << 1) | rw;
+ len = msgs->len;
+ buffer = msgs->buf;
+
+ dev_dbg(&adapter->dev,
+ "address=0x%x, len=%d, read=%d\n", msgs->addr, len, rw);
+
+ if (!len && rw == I2C_SMBUS_READ) {
+ dev_dbg(&adapter->dev, "zero length read\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ iface->address_byte = address;
+ iface->command = 0;
+ iface->ptr = buffer;
+ iface->len = len;
+ iface->result = -EINVAL;
+ iface->needs_reset = 0;
+ if (num > 1)
+ iface->skip_stop = 1;
+ else
+ iface->skip_stop = 0;
+
+ /* send start */
+ outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+ /* no command */
+ iface->state = state_quick;
+
+ while (iface->state != state_idle)
+ scx200_acb_poll(iface);
+
+ if (iface->needs_reset)
+ scx200_acb_reset(iface);
+
+ if (iface->result)
+ break;
+
+#ifdef DEBUG
+ dev_dbg(&adapter->dev, "transfer done, result: %d", rc);
+ if (buffer) {
+ int i;
+ printk(KERN_DEBUG " data:");
+ for (i = 0; i < len; ++i)
+ printk(KERN_DEBUG " %02x", buffer[i]);
+ }
+ printk(KERN_DEBUG "\n");
+#endif
+ ++rc;
+ --num;
+ ++msgs;
+ }
+ mutex_unlock(&iface->mutex);
+
+ iface->skip_stop = 0;
+ return rc;
+}
+
+
static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
u16 address, unsigned short flags,
char rw, u8 command, int size,
@@ -338,6 +441,7 @@ static s32 scx200_acb_smbus_xfer(struct
iface->len = len;
iface->result = -EINVAL;
iface->needs_reset = 0;
+ iface->skip_stop = 0;
outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
@@ -377,12 +481,13 @@ static u32 scx200_acb_func(struct i2c_ad
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK;
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_I2C;
}
/* For now, we only handle combined mode (smbus) */
static const struct i2c_algorithm scx200_acb_algorithm = {
.smbus_xfer = scx200_acb_smbus_xfer,
+ .master_xfer = scx200_acb_i2c_master_xfer,
.functionality = scx200_acb_func,
};
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH 2.6.38 1/1] scx200_acb.c: Add plain i2c (master_xfer / I2C_FUNC_I2C)
[not found] ` <CAN=yz1iG02kqUm0pJ8sXgJ81JJerJTmWuGAkPo6UUGBTE_6Zpw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
@ 2011-08-09 20:51 ` Jim Cromie
0 siblings, 0 replies; 2+ messages in thread
From: Jim Cromie @ 2011-08-09 20:51 UTC (permalink / raw)
To: Tomas; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA
On Mon, Aug 8, 2011 at 1:29 PM, Tomas <tomasamot-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:
> From: Tomas Menzl <tomasamot-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>
> Add master_xfer / I2C_FUNC_I2C by simply reusing existing FSM
> scx200_acb_machine.
> This adds possibility to do direct read/write on an i2c device or use
> I2C_RDWR ioctl in addition to existing SM Bus API.
>
> Signed-off-by: Tomas Menzl <tomasamot-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi Tomas,
I cannot properly test this, as the (baseline) module doesnt
initialize properly.
It fails thusly:
scx200_acb: NatSemi SCx200 ACCESS.bus Driver
scx200_acb: ACBCTL2 readback failed
scx200_acb: probe failed
scx200_acb: ACBCTL2 readback failed
scx200_acb: probe failed
root@voyage:~#
I presume Im lacking proper base values:
parm: base:Base addresses for the ACCESS.bus controllers
(array of int)
voyage distro ships with these, but my impression is that theyre
for ALIX boxes, IIRC Tomas is using them.
scx200_acb base=0x810,0x820
Does anyone know the correct base for a Soekris net4801 ?
Im trying brute force right now, with the following script.
it avoids reserved ranges in /proc/ioport,
assuming other drivers wont claim things they arent using (correct ?)
and increments addresses by 2,
Id like to skip by 16, but fast and incomplete isnt reassuring.
Are there any rules/conventions regarding what starting-addresses are ?
(for this kind of device, or others)
Tomas, can you send me your /proc/ioports on your ALIX ?
Is the scx200_acb reservations in there ?
Also, I dont have a proper way to test for success of the probe,
the modprobe succeeds despite the probe failure.
So I have to just watch output.
Is there a sysfs file I could read (or check presence of)
to determine when the probe succeeds ?
Is there a way to tell installed module to re-probe with different addys,
perhaps with a uevent ??
#!/usr/bin/perl
use Data::Dumper;
$Data::Dumper::Sortkeys = 1; #sub { [sort {$a <=> $b} keys %$_] };
my $addr = 0;
my %reserved;
open(my $IO, "/proc/ioports") or die;
while (<$IO>) {
s/^\s+//;
my ($from,$to,@r) = split /[:-\s]/, $_;
# print "$from,$to\n";
printf "hex: %x,%x\n", hex($from), hex($to);
$reserved{hex($from)} = hex($to);
}
print Dumper \%reserved;
$opt_x = 1;
while ($addr < 0x8000) {
if ($reserved{$addr}) {
print "skipping $addr\n";
$addr = $reserved{$addr} + 1;
print "skip to $addr\n";
next;
}
printf "%x\n", $addr;
$cmd = sprintf "modprobe scx200_acb base=0x%x\n", $addr;
if ($opt_x) {
print `rmmod scx200_acb`;
print $cmd;
$resp = `$cmd`;
# modprobe succeeds despite addr-probe failure
# need ok way to test..
}
$addr += 2; # bloody small steps16;
$addr++ if $addr % 2;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2011-08-09 20:51 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-08 19:29 [PATCH 2.6.38 1/1] scx200_acb.c: Add plain i2c (master_xfer / I2C_FUNC_I2C) Tomas
[not found] ` <CAN=yz1iG02kqUm0pJ8sXgJ81JJerJTmWuGAkPo6UUGBTE_6Zpw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-08-09 20:51 ` Jim Cromie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).