diff options
Diffstat (limited to 'src/cpu/allwinner/a10/twi.c')
-rw-r--r-- | src/cpu/allwinner/a10/twi.c | 217 |
1 files changed, 0 insertions, 217 deletions
diff --git a/src/cpu/allwinner/a10/twi.c b/src/cpu/allwinner/a10/twi.c deleted file mode 100644 index 01ee5a5c6f..0000000000 --- a/src/cpu/allwinner/a10/twi.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2012 Henrik Nordstrom <henrik@henriknordstrom.net> - * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> - * - * 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 or (at your option) - * any later version. - * - * 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. - * - * Setup helpers for Two Wire Interface (TWI) (I2C) Allwinner CPUs - * - * Only functionality for I2C master is provided. - * Largely based on the uboot-sunxi code. - */ - -#include <device/mmio.h> -#include <delay.h> -#include <device/i2c_simple.h> -#include <types.h> - -#include "memmap.h" -#include "twi.h" - -#define TWI_BASE(n) (A1X_TWI0_BASE + 0x400 * (n)) - -#define TWI_TIMEOUT (50 * 1000) - -static u8 is_busy(struct a1x_twi *twi) -{ - return (read32(&twi->stat) != TWI_STAT_IDLE); -} - -static enum cb_err wait_until_idle(struct a1x_twi *twi) -{ - u32 i = TWI_TIMEOUT; - while (i-- && is_busy((twi))) - udelay(1); - return i ? CB_SUCCESS : CB_ERR; -} - -/* FIXME: This function is basic, and unintelligent */ -static void configure_clock(struct a1x_twi *twi, u32 speed_hz) -{ - /* FIXME: We assume clock is 24MHz, which may not be the case */ - u32 apb_clk = 24000000, m, n; - - /* Pre-divide the clock by 8 */ - n = 3; - m = (apb_clk >> n) / speed_hz; - write32(&twi->clk, TWI_CLK_M(m) | TWI_CLK_N(n)); -} - -void a1x_twi_init(u8 bus, u32 speed_hz) -{ - u32 i = TWI_TIMEOUT; - struct a1x_twi *twi = (void *)TWI_BASE(bus); - - configure_clock(twi, speed_hz); - - /* Enable the I2C bus */ - write32(&twi->ctl, TWI_CTL_BUS_EN); - /* Issue soft reset */ - write32(&twi->reset, 1); - - while (i-- && read32(&twi->reset)) - udelay(1); -} - -static void clear_interrupt_flag(struct a1x_twi *twi) -{ - write32(&twi->ctl, read32(&twi->ctl) & ~TWI_CTL_INT_FLAG); -} - -static void i2c_send_data(struct a1x_twi *twi, u8 data) -{ - write32(&twi->data, data); - clear_interrupt_flag(twi); -} - -static enum twi_status wait_for_status(struct a1x_twi *twi) -{ - u32 i = TWI_TIMEOUT; - /* Wait until interrupt is asserted again */ - while (i-- && !(read32(&twi->ctl) & TWI_CTL_INT_FLAG)) - udelay(1); - /* A timeout here most likely indicates a bus error */ - return i ? read32(&twi->stat) : TWI_STAT_BUS_ERROR; -} - -static void i2c_send_start(struct a1x_twi *twi) -{ - u32 reg32, i; - - /* Send START condition */ - reg32 = read32(&twi->ctl); - reg32 &= ~TWI_CTL_INT_FLAG; - reg32 |= TWI_CTL_M_START; - write32(&twi->ctl, reg32); - - /* M_START is automatically cleared after condition is transmitted */ - i = TWI_TIMEOUT; - while (i-- && (read32(&twi->ctl) & TWI_CTL_M_START)) - udelay(1); -} - -static void i2c_send_stop(struct a1x_twi *twi) -{ - u32 reg32; - - /* Send STOP condition */ - reg32 = read32(&twi->ctl); - reg32 &= ~TWI_CTL_INT_FLAG; - reg32 |= TWI_CTL_M_STOP; - write32(&twi->ctl, reg32); -} - -static int i2c_read(struct a1x_twi *twi, uint8_t chip, - uint8_t *buf, size_t len) -{ - unsigned count = len; - enum twi_status expected_status; - - /* Send restart for read */ - i2c_send_start(twi); - if (wait_for_status(twi) != TWI_STAT_TX_RSTART) - return CB_ERR; - - /* Send chip address */ - i2c_send_data(twi, chip << 1 | 1); - if (wait_for_status(twi) != TWI_STAT_TX_AR_ACK) - return CB_ERR; - - /* Start ACK-ing received data */ - setbits_le32(&twi->ctl, TWI_CTL_A_ACK); - expected_status = TWI_STAT_RXD_ACK; - - /* Read data */ - while (count > 0) { - if (count == 1) { - /* Do not ACK the last byte */ - clrbits_le32(&twi->ctl, TWI_CTL_A_ACK); - expected_status = TWI_STAT_RXD_NAK; - } - - clear_interrupt_flag(twi); - - if (wait_for_status(twi) != expected_status) - return CB_ERR; - - *buf++ = read32(&twi->data); - count--; - } - - return len; -} - -static int i2c_write(struct a1x_twi *twi, uint8_t chip, - const uint8_t *buf, size_t len) -{ - size_t count = len; - - i2c_send_start(twi); - if (wait_for_status(twi) != TWI_STAT_TX_START) - return CB_ERR; - - /* Send chip address */ - i2c_send_data(twi, chip << 1); - if (wait_for_status(twi) != TWI_STAT_TX_AW_ACK) - return CB_ERR; - - /* Send data */ - while (count > 0) { - i2c_send_data(twi, *buf++); - if (wait_for_status(twi) != TWI_STAT_TXD_ACK) - return CB_ERR; - count--; - } - - return len; -} - -int platform_i2c_transfer(unsigned bus, struct i2c_msg *segments, int count) -{ - int i, ret = CB_SUCCESS; - struct i2c_msg *seg = segments; - struct a1x_twi *twi = (void *)TWI_BASE(bus); - - - if (wait_until_idle(twi) != CB_SUCCESS) - return CB_ERR; - - for (i = 0; i < count; i++) { - seg = segments + i; - - if (seg->flags & I2C_M_RD) { - ret = i2c_read(twi, seg->slave, seg->buf, seg->len); - if (ret < 0) - break; - } else { - ret = i2c_write(twi, seg->slave, seg->buf, seg->len); - if (ret < 0) - break; - } - } - - /* Don't worry about the status. STOP is on a best-effort basis */ - i2c_send_stop(twi); - - return ret; -} |