diff options
Diffstat (limited to 'src/soc/broadcom/cygnus/i2c.c')
-rw-r--r-- | src/soc/broadcom/cygnus/i2c.c | 266 |
1 files changed, 0 insertions, 266 deletions
diff --git a/src/soc/broadcom/cygnus/i2c.c b/src/soc/broadcom/cygnus/i2c.c deleted file mode 100644 index ac431e734a..0000000000 --- a/src/soc/broadcom/cygnus/i2c.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * 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. - */ - -#include <arch/io.h> -#include <assert.h> -#include <console/console.h> -#include <delay.h> -#include <device/i2c_simple.h> -#include <soc/i2c.h> - -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); -} - -static int i2c_write(struct cygnus_i2c_regs *reg_addr, - struct i2c_msg *segment) -{ - uint8_t *data = segment->buf; - unsigned int val, status; - int i, ret; - - write32(®_addr->i2c_master_data_wr, segment->slave << 1); - - 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; -} - -static int i2c_read(struct cygnus_i2c_regs *reg_addr, struct i2c_msg *segment) -{ - uint8_t *data = segment->buf; - int i, ret; - unsigned int status; - - write32(®_addr->i2c_master_data_wr, segment->slave << 1 | 1); - - /* - * 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; - - return 0; - -flush_fifo: - i2c_flush_fifo(reg_addr); - return ret; -} - -static int i2c_do_xfer(struct cygnus_i2c_regs *reg_addr, - struct i2c_msg *segment) -{ - 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; - } - - if (segment->flags & I2C_M_RD) - ret = i2c_read(reg_addr, segment); - else - ret = i2c_write(reg_addr, segment); - - return ret; -} - -int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, - int seg_count) -{ - int i; - int res = 0; - struct cygnus_i2c_regs *regs = i2c_bus[bus]; - struct i2c_msg *seg = segments; - - for (i = 0; i < seg_count; i++, seg++) { - res = i2c_do_xfer(regs, seg); - if (res) - break; - } - return res; -} - -void i2c_init(unsigned int bus, unsigned int hz) -{ - 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); -} |