2015-01-23 19:06:19 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the coreboot project.
|
|
|
|
*
|
|
|
|
* Copyright 2015 Google Inc.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*/
|
|
|
|
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
#include <arch/io.h>
|
|
|
|
#include <assert.h>
|
2015-01-23 19:06:19 +01:00
|
|
|
#include <console/console.h>
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
#include <delay.h>
|
2017-08-01 14:02:40 +02:00
|
|
|
#include <device/i2c_simple.h>
|
2015-01-23 19:06:19 +01:00
|
|
|
#include <soc/i2c.h>
|
|
|
|
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
struct cygnus_i2c_regs {
|
|
|
|
u32 i2c_con;
|
|
|
|
u32 i2c_timing_con;
|
|
|
|
u32 i2c_addr;
|
|
|
|
u32 i2c_fifo_master;
|
|
|
|
u32 i2c_fifo_slave;
|
|
|
|
u32 i2c_bit_bang;
|
|
|
|
u32 reserved0[(0x30 - 0x18) / 4];
|
|
|
|
u32 i2c_master_comm;
|
|
|
|
u32 i2c_slave_comm;
|
|
|
|
u32 i2c_int_en;
|
|
|
|
u32 i2c_int_status;
|
|
|
|
u32 i2c_master_data_wr;
|
|
|
|
u32 i2c_master_data_rd;
|
|
|
|
u32 i2c_slave_data_wr;
|
|
|
|
u32 i2c_slave_data_rd;
|
|
|
|
u32 reserved1[(0xb0 - 0x50) / 4];
|
|
|
|
u32 i2c_timing_con2;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct cygnus_i2c_regs *i2c_bus[] = {
|
|
|
|
(struct cygnus_i2c_regs *)0x18008000,
|
|
|
|
(struct cygnus_i2c_regs *)0x1800b000,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define I2C_TIMEOUT_US 100000 /* 100ms */
|
|
|
|
#define I2C_FIFO_MAX_SIZE 64
|
|
|
|
|
|
|
|
#define ETIMEDOUT 1
|
|
|
|
#define EINVAL 2
|
|
|
|
#define EBUSY 3
|
|
|
|
|
|
|
|
/* Configuration (0x0) */
|
|
|
|
#define I2C_SMB_RESET (1 << 31)
|
|
|
|
#define I2C_SMB_EN (1 << 30)
|
|
|
|
|
|
|
|
/* Timing configuration (0x4) */
|
|
|
|
#define I2C_MODE_400 (1 << 31)
|
|
|
|
|
|
|
|
/* Master FIFO control (0xc) */
|
|
|
|
#define I2C_MASTER_RX_FIFO_FLUSH (1 << 31)
|
|
|
|
#define I2C_MASTER_TX_FIFO_FLUSH (1 << 30)
|
|
|
|
|
|
|
|
/* Master command (0x30) */
|
|
|
|
#define I2C_MASTER_START_BUSY (1 << 31)
|
|
|
|
#define I2C_MASTER_STATUS_SFT 25
|
|
|
|
#define I2C_MASTER_STATUS_MASK (0x7 << I2C_MASTER_STATUS_SFT)
|
|
|
|
#define I2C_MASTER_PROT_SFT 9
|
|
|
|
#define I2C_MASTER_PROT_BLK_WR (0x7 << I2C_MASTER_PROT_SFT)
|
|
|
|
#define I2C_MASTER_PROT_BLK_RD (0x8 << I2C_MASTER_PROT_SFT)
|
|
|
|
|
|
|
|
/* Master data write (0x40) */
|
|
|
|
#define I2C_MASTER_WR_STATUS (1 << 31)
|
|
|
|
|
|
|
|
/* Master data read (0x44) */
|
|
|
|
#define I2C_MASTER_RD_DATA_MASK 0xff
|
|
|
|
|
|
|
|
static unsigned int i2c_bus_busy(struct cygnus_i2c_regs *reg_addr)
|
|
|
|
{
|
|
|
|
return read32(®_addr->i2c_master_comm) & I2C_MASTER_START_BUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int i2c_wait_bus_busy(struct cygnus_i2c_regs *reg_addr)
|
|
|
|
{
|
|
|
|
int timeout = I2C_TIMEOUT_US;
|
|
|
|
while (timeout--) {
|
|
|
|
if (!i2c_bus_busy(reg_addr))
|
|
|
|
break;
|
|
|
|
udelay(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout <= 0)
|
|
|
|
return ETIMEDOUT;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void i2c_flush_fifo(struct cygnus_i2c_regs *reg_addr)
|
|
|
|
{
|
|
|
|
write32(®_addr->i2c_fifo_master,
|
|
|
|
I2C_MASTER_RX_FIFO_FLUSH | I2C_MASTER_TX_FIFO_FLUSH);
|
|
|
|
}
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
static int i2c_write(struct cygnus_i2c_regs *reg_addr,
|
|
|
|
struct i2c_msg *segment)
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
{
|
|
|
|
uint8_t *data = segment->buf;
|
|
|
|
unsigned int val, status;
|
|
|
|
int i, ret;
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
write32(®_addr->i2c_master_data_wr, segment->slave << 1);
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
|
|
|
|
for (i = 0; i < segment->len; i++) {
|
|
|
|
val = data[i];
|
|
|
|
|
|
|
|
/* mark the last byte */
|
|
|
|
if (i == segment->len - 1)
|
|
|
|
val |= I2C_MASTER_WR_STATUS;
|
|
|
|
|
|
|
|
write32(®_addr->i2c_master_data_wr, val);
|
|
|
|
}
|
|
|
|
if (segment->len == 0)
|
|
|
|
write32(®_addr->i2c_master_data_wr, I2C_MASTER_WR_STATUS);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we can activate the transfer.
|
|
|
|
*/
|
|
|
|
write32(®_addr->i2c_master_comm,
|
|
|
|
I2C_MASTER_START_BUSY | I2C_MASTER_PROT_BLK_WR);
|
|
|
|
|
|
|
|
ret = i2c_wait_bus_busy(reg_addr);
|
|
|
|
if (ret) {
|
|
|
|
printk(BIOS_ERR, "I2C bus timeout\n");
|
|
|
|
goto flush_fifo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check transaction successful */
|
|
|
|
status = read32(®_addr->i2c_master_comm);
|
|
|
|
ret = (status & I2C_MASTER_STATUS_MASK) >> I2C_MASTER_STATUS_SFT;
|
|
|
|
if (ret) {
|
|
|
|
printk(BIOS_ERR, "I2C write error %u\n", status);
|
|
|
|
goto flush_fifo;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
flush_fifo:
|
|
|
|
i2c_flush_fifo(reg_addr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
static int i2c_read(struct cygnus_i2c_regs *reg_addr, struct i2c_msg *segment)
|
2015-01-23 19:06:19 +01:00
|
|
|
{
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
uint8_t *data = segment->buf;
|
|
|
|
int i, ret;
|
|
|
|
unsigned int status;
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
write32(®_addr->i2c_master_data_wr, segment->slave << 1 | 1);
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we can activate the transfer. Specify the number of bytes to read
|
|
|
|
*/
|
|
|
|
write32(®_addr->i2c_master_comm,
|
|
|
|
I2C_MASTER_START_BUSY | I2C_MASTER_PROT_BLK_RD | segment->len);
|
|
|
|
|
|
|
|
ret = i2c_wait_bus_busy(reg_addr);
|
|
|
|
if (ret) {
|
|
|
|
printk(BIOS_ERR, "I2C bus timeout\n");
|
|
|
|
goto flush_fifo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check transaction successful */
|
|
|
|
status = read32(®_addr->i2c_master_comm);
|
|
|
|
ret = (status & I2C_MASTER_STATUS_MASK) >> I2C_MASTER_STATUS_SFT;
|
|
|
|
if (ret) {
|
|
|
|
printk(BIOS_ERR, "I2C read error %u\n", status);
|
|
|
|
goto flush_fifo;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < segment->len; i++)
|
|
|
|
data[i] = read32(®_addr->i2c_master_data_rd) &
|
|
|
|
I2C_MASTER_RD_DATA_MASK;
|
|
|
|
|
2015-01-23 19:06:19 +01:00
|
|
|
return 0;
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
|
|
|
|
flush_fifo:
|
|
|
|
i2c_flush_fifo(reg_addr);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int i2c_do_xfer(struct cygnus_i2c_regs *reg_addr,
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
struct i2c_msg *segment)
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (segment->len > I2C_FIFO_MAX_SIZE - 1) {
|
|
|
|
printk(BIOS_ERR,
|
|
|
|
"I2C transfer error: segment size (%d) is larger than limit (%d)\n",
|
|
|
|
segment->len, I2C_FIFO_MAX_SIZE);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i2c_bus_busy(reg_addr)) {
|
|
|
|
printk(BIOS_WARNING, "I2C transfer error: bus is busy\n");
|
|
|
|
return EBUSY;
|
|
|
|
}
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
if (segment->flags & I2C_M_RD)
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
ret = i2c_read(reg_addr, segment);
|
|
|
|
else
|
|
|
|
ret = i2c_write(reg_addr, segment);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments,
|
|
|
|
int seg_count)
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int res = 0;
|
|
|
|
struct cygnus_i2c_regs *regs = i2c_bus[bus];
|
i2c: Move to Linux like `struct i2c_msg`
Our current struct for I2C segments `i2c_seg` was close to being compa-
tible to the Linux version `i2c_msg`, close to being compatible to SMBus
and close to being readable (e.g. what was `chip` supposed to mean?) but
turned out to be hard to fix.
Instead of extending it in a backwards compatible way (and not touching
current controller drivers), replace it with a Linux source compatible
`struct i2c_msg` and patch all the drivers and users with Coccinelle.
The new `struct i2c_msg` should ease porting drivers from Linux and help
to write SMBus compatible controller drivers.
Beside integer type changes, the field `read` is replaced with a generic
field `flags` and `chip` is renamed to `slave`.
Patched with Coccinelle using the clumsy spatch below and some manual
changes:
* Nested struct initializers and one field access skipped by Coccinelle.
* Removed assumption in the code that I2C_M_RD is 1.
* In `i2c.h`, changed all occurences of `chip` to `slave`.
@@ @@
-struct i2c_seg
+struct i2c_msg
@@ identifier msg; expression e; @@
(
struct i2c_msg msg = {
- .read = 0,
+ .flags = 0,
};
|
struct i2c_msg msg = {
- .read = 1,
+ .flags = I2C_M_RD,
};
|
struct i2c_msg msg = {
- .chip = e,
+ .slave = e,
};
)
@@ struct i2c_msg msg; statement S1, S2; @@
(
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1 else S2
|
-if (msg.read)
+if (msg.flags & I2C_M_RD)
S1
)
@@ struct i2c_msg *msg; statement S1, S2; @@
(
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1 else S2
|
-if (msg->read)
+if (msg->flags & I2C_M_RD)
S1
)
@@ struct i2c_msg msg; expression e; @@
(
-msg.read = 0;
+msg.flags = 0;
|
-msg.read = 1;
+msg.flags = I2C_M_RD;
|
-msg.read = e;
+msg.flags = e ? I2C_M_RD : 0;
|
-!!(msg.read)
+(msg.flags & I2C_M_RD)
|
-(msg.read)
+(msg.flags & I2C_M_RD)
)
@@ struct i2c_msg *msg; expression e; @@
(
-msg->read = 0;
+msg->flags = 0;
|
-msg->read = 1;
+msg->flags = I2C_M_RD;
|
-msg->read = e;
+msg->flags = e ? I2C_M_RD : 0;
|
-!!(msg->read)
+(msg->flags & I2C_M_RD)
|
-(msg->read)
+(msg->flags & I2C_M_RD)
)
@@ struct i2c_msg msg; @@
-msg.chip
+msg.slave
@@ struct i2c_msg *msg; expression e; @@
-msg[e].chip
+msg[e].slave
@ slave disable ptr_to_array @ struct i2c_msg *msg; @@
-msg->chip
+msg->slave
Change-Id: Ifd7cabf0a18ffd7a1def25d1d7059b713d0b7ea9
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: https://review.coreboot.org/20542
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Werner Zeh <werner.zeh@siemens.com>
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
2017-07-12 17:59:16 +02:00
|
|
|
struct i2c_msg *seg = segments;
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
|
|
|
|
for (i = 0; i < seg_count; i++, seg++) {
|
|
|
|
res = i2c_do_xfer(regs, seg);
|
|
|
|
if (res)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return res;
|
2015-01-23 19:06:19 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void i2c_init(unsigned int bus, unsigned int hz)
|
|
|
|
{
|
broadcom/cygnus: Implement I2C driver
BUG=chrome-os-partner:35810
BRANCH=purin
TEST=Enable I2C1, reset devboard codec, read a register.
Here is the code that demonstrates how I2C works:
i2c_init(1, 100*KHz);
mdelay(50);
int rc = i2c_writeb(1, 0x18, 1, 0x80); // reset codec
printk(BIOS_INFO, "I2C reset rc=%d\n", rc);
mdelay(50);
uint8_t data = 0;
rc = i2c_readb(1, 0x18, 43, &data);
printk(BIOS_INFO, "I2C read rc=%d data=%x\n", rc, data); // data == 0x80
Change-Id: I0d202f8b0375b5ccd9f71b23fb0cadd5a70ae779
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: 6bbe9afe3dccd104f39c2c286d3765a28ea20141
Original-Signed-off-by: Anatol Pomazau <anatol@google.com>
Original-Reviewed-on: https://chrome-internal-review.googlesource.com/195706
Original-Reviewed-by: Daisuke Nojiri <dnojiri@google.com>
Original-Reviewed-by: Anatol Pomazau <anatol@google.com>
Original-Commit-Queue: Anatol Pomazau <anatol@google.com>
Original-Tested-by: Anatol Pomazau <anatol@google.com>
Original-Change-Id: I178acef9de18fa854983294edcd2c05886795e2a
Original-Reviewed-on: https://chromium-review.googlesource.com/263496
Original-Commit-Queue: Daisuke Nojiri <dnojiri@chromium.org>
Original-Trybot-Ready: Daisuke Nojiri <dnojiri@chromium.org>
Original-Tested-by: Daisuke Nojiri <dnojiri@chromium.org>
Original-Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
Reviewed-on: http://review.coreboot.org/9908
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-02-04 19:09:27 +01:00
|
|
|
struct cygnus_i2c_regs *regs = i2c_bus[bus];
|
|
|
|
|
|
|
|
assert(bus >= 0 && bus <= 1);
|
|
|
|
|
|
|
|
setbits_le32(®s->i2c_con, I2C_SMB_RESET);
|
|
|
|
udelay(100); /* wait 100 usec per spec */
|
|
|
|
clrbits_le32(®s->i2c_con, I2C_SMB_RESET);
|
|
|
|
|
|
|
|
switch (hz) {
|
|
|
|
case 100000:
|
|
|
|
clrbits_le32(®s->i2c_timing_con, I2C_MODE_400);
|
|
|
|
break;
|
|
|
|
case 400000:
|
|
|
|
setbits_le32(®s->i2c_timing_con, I2C_MODE_400);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk(BIOS_ERR, "I2C bus does not support frequency %d Hz\n",
|
|
|
|
hz);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i2c_flush_fifo(regs);
|
|
|
|
|
|
|
|
/* disable all interrupts */
|
|
|
|
write32(®s->i2c_int_en, 0);
|
|
|
|
|
|
|
|
/* clear all pending interrupts */
|
|
|
|
write32(®s->i2c_int_status, 0xffffffff);
|
|
|
|
|
|
|
|
write32(®s->i2c_con, I2C_SMB_EN);
|
2015-01-23 19:06:19 +01:00
|
|
|
}
|