mirror of
https://github.com/linux-sunxi/u-boot-sunxi.git
synced 2024-02-12 11:16:03 +08:00
Merge branch 'master' of git://git.denx.de/u-boot-arm
Small conflict over DRA7XX updates and adding SRAM_SCRATCH_SPACE_ADDR Conflicts: arch/arm/include/asm/arch-omap5/omap.h Signed-off-by: Tom Rini <trini@ti.com>
This commit is contained in:
@ -18,6 +18,20 @@
|
||||
*
|
||||
* Adapted for OMAP2420 I2C, r-woodruff2@ti.com
|
||||
*
|
||||
* Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
|
||||
* New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4
|
||||
* (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older
|
||||
* OMAPs and derivatives as well. The only anticipated exception would
|
||||
* be the OMAP2420, which shall require driver modification.
|
||||
* - Rewritten i2c_read to operate correctly with all types of chips
|
||||
* (old function could not read consistent data from some I2C slaves).
|
||||
* - Optimized i2c_write.
|
||||
* - New i2c_probe, performs write access vs read. The old probe could
|
||||
* hang the system under certain conditions (e.g. unconfigured pads).
|
||||
* - The read/write/probe functions try to identify unconfigured bus.
|
||||
* - Status functions now read irqstatus_raw as per TRM guidelines
|
||||
* (except for OMAP243X and OMAP34XX).
|
||||
* - Driver now supports up to I2C5 (OMAP5).
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
@ -31,8 +45,11 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define I2C_TIMEOUT 1000
|
||||
|
||||
/* Absolutely safe for status update at 100 kHz I2C: */
|
||||
#define I2C_WAIT 200
|
||||
|
||||
static int wait_for_bb(void);
|
||||
static u16 wait_for_pin(void);
|
||||
static u16 wait_for_event(void);
|
||||
static void flush_fifo(void);
|
||||
|
||||
/*
|
||||
@ -137,10 +154,14 @@ void i2c_init(int speed, int slaveadd)
|
||||
/* own address */
|
||||
writew(slaveadd, &i2c_base->oa);
|
||||
writew(I2C_CON_EN, &i2c_base->con);
|
||||
|
||||
/* have to enable intrrupts or OMAP i2c module doesn't work */
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
|
||||
/*
|
||||
* Have to enable interrupts for OMAP2/3, these IPs don't have
|
||||
* an 'irqstatus_raw' register and we shall have to poll 'stat'
|
||||
*/
|
||||
writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
|
||||
I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
|
||||
I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
|
||||
#endif
|
||||
udelay(1000);
|
||||
flush_fifo();
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
@ -150,88 +171,6 @@ void i2c_init(int speed, int slaveadd)
|
||||
bus_initialized[current_bus] = 1;
|
||||
}
|
||||
|
||||
static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)
|
||||
{
|
||||
int i2c_error = 0;
|
||||
u16 status;
|
||||
int i = 2 - alen;
|
||||
u8 tmpbuf[2] = {(regoffset) >> 8, regoffset & 0xff};
|
||||
u16 w;
|
||||
|
||||
/* wait until bus not busy */
|
||||
if (wait_for_bb())
|
||||
return 1;
|
||||
|
||||
/* one byte only */
|
||||
writew(alen, &i2c_base->cnt);
|
||||
/* set slave address */
|
||||
writew(devaddr, &i2c_base->sa);
|
||||
/* no stop bit needed here */
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
|
||||
I2C_CON_TRX, &i2c_base->con);
|
||||
|
||||
/* send register offset */
|
||||
while (1) {
|
||||
status = wait_for_pin();
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
goto read_exit;
|
||||
}
|
||||
if (status & I2C_STAT_XRDY) {
|
||||
w = tmpbuf[i++];
|
||||
#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
|
||||
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
|
||||
defined(CONFIG_OMAP54XX))
|
||||
w |= tmpbuf[i++] << 8;
|
||||
#endif
|
||||
writew(w, &i2c_base->data);
|
||||
writew(I2C_STAT_XRDY, &i2c_base->stat);
|
||||
}
|
||||
if (status & I2C_STAT_ARDY) {
|
||||
writew(I2C_STAT_ARDY, &i2c_base->stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set slave address */
|
||||
writew(devaddr, &i2c_base->sa);
|
||||
/* read one byte from slave */
|
||||
writew(1, &i2c_base->cnt);
|
||||
/* need stop bit here */
|
||||
writew(I2C_CON_EN | I2C_CON_MST |
|
||||
I2C_CON_STT | I2C_CON_STP,
|
||||
&i2c_base->con);
|
||||
|
||||
/* receive data */
|
||||
while (1) {
|
||||
status = wait_for_pin();
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
goto read_exit;
|
||||
}
|
||||
if (status & I2C_STAT_RRDY) {
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
|
||||
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
|
||||
defined(CONFIG_OMAP54XX)
|
||||
*value = readb(&i2c_base->data);
|
||||
#else
|
||||
*value = readw(&i2c_base->data);
|
||||
#endif
|
||||
writew(I2C_STAT_RRDY, &i2c_base->stat);
|
||||
}
|
||||
if (status & I2C_STAT_ARDY) {
|
||||
writew(I2C_STAT_ARDY, &i2c_base->stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_exit:
|
||||
flush_fifo();
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
writew(0, &i2c_base->cnt);
|
||||
return i2c_error;
|
||||
}
|
||||
|
||||
static void flush_fifo(void)
|
||||
{ u16 stat;
|
||||
|
||||
@ -241,13 +180,7 @@ static void flush_fifo(void)
|
||||
while (1) {
|
||||
stat = readw(&i2c_base->stat);
|
||||
if (stat == I2C_STAT_RRDY) {
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
|
||||
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
|
||||
defined(CONFIG_OMAP54XX)
|
||||
readb(&i2c_base->data);
|
||||
#else
|
||||
readw(&i2c_base->data);
|
||||
#endif
|
||||
writew(I2C_STAT_RRDY, &i2c_base->stat);
|
||||
udelay(1000);
|
||||
} else
|
||||
@ -255,6 +188,10 @@ static void flush_fifo(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* i2c_probe: Use write access. Allows to identify addresses that are
|
||||
* write-only (like the config register of dual-port EEPROMs)
|
||||
*/
|
||||
int i2c_probe(uchar chip)
|
||||
{
|
||||
u16 status;
|
||||
@ -263,61 +200,81 @@ int i2c_probe(uchar chip)
|
||||
if (chip == readw(&i2c_base->oa))
|
||||
return res;
|
||||
|
||||
/* wait until bus not busy */
|
||||
/* Wait until bus is free */
|
||||
if (wait_for_bb())
|
||||
return res;
|
||||
|
||||
/* try to read one byte */
|
||||
writew(1, &i2c_base->cnt);
|
||||
/* set slave address */
|
||||
/* No data transfer, slave addr only */
|
||||
writew(0, &i2c_base->cnt);
|
||||
/* Set slave address */
|
||||
writew(chip, &i2c_base->sa);
|
||||
/* stop bit needed here */
|
||||
writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
|
||||
/* Stop bit needed here */
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
|
||||
I2C_CON_STP, &i2c_base->con);
|
||||
|
||||
while (1) {
|
||||
status = wait_for_pin();
|
||||
if (status == 0 || status & I2C_STAT_AL) {
|
||||
res = 1;
|
||||
goto probe_exit;
|
||||
}
|
||||
if (status & I2C_STAT_NACK) {
|
||||
res = 1;
|
||||
writew(0xff, &i2c_base->stat);
|
||||
writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
|
||||
status = wait_for_event();
|
||||
|
||||
if (wait_for_bb())
|
||||
res = 1;
|
||||
if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
|
||||
/*
|
||||
* With current high-level command implementation, notifying
|
||||
* the user shall flood the console with 127 messages. If
|
||||
* silent exit is desired upon unconfigured bus, remove the
|
||||
* following 'if' section:
|
||||
*/
|
||||
if (status == I2C_STAT_XRDY)
|
||||
printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n",
|
||||
current_bus, status);
|
||||
|
||||
break;
|
||||
}
|
||||
if (status & I2C_STAT_ARDY) {
|
||||
writew(I2C_STAT_ARDY, &i2c_base->stat);
|
||||
break;
|
||||
}
|
||||
if (status & I2C_STAT_RRDY) {
|
||||
res = 0;
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
|
||||
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
|
||||
defined(CONFIG_OMAP54XX)
|
||||
readb(&i2c_base->data);
|
||||
#else
|
||||
readw(&i2c_base->data);
|
||||
#endif
|
||||
writew(I2C_STAT_RRDY, &i2c_base->stat);
|
||||
}
|
||||
goto pr_exit;
|
||||
}
|
||||
|
||||
probe_exit:
|
||||
/* Check for ACK (!NAK) */
|
||||
if (!(status & I2C_STAT_NACK)) {
|
||||
res = 0; /* Device found */
|
||||
udelay(I2C_WAIT); /* Required by AM335X in SPL */
|
||||
/* Abort transfer (force idle state) */
|
||||
writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
|
||||
udelay(1000);
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
|
||||
I2C_CON_STP, &i2c_base->con); /* STP */
|
||||
}
|
||||
pr_exit:
|
||||
flush_fifo();
|
||||
/* don't allow any more data in... we don't want it. */
|
||||
writew(0, &i2c_base->cnt);
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
writew(0, &i2c_base->cnt);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* i2c_read: Function now uses a single I2C read transaction with bulk transfer
|
||||
* of the requested number of bytes (note that the 'i2c md' command
|
||||
* limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is
|
||||
* defined in the board config header, this transaction shall be with
|
||||
* Repeated Start (Sr) between the address and data phases; otherwise
|
||||
* Stop-Start (P-S) shall be used (some I2C chips do require a P-S).
|
||||
* The address (reg offset) may be 0, 1 or 2 bytes long.
|
||||
* Function now reads correctly from chips that return more than one
|
||||
* byte of data per addressed register (like TI temperature sensors),
|
||||
* or that do not need a register address at all (such as some clock
|
||||
* distributors).
|
||||
*/
|
||||
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
int i;
|
||||
int i2c_error = 0;
|
||||
u16 status;
|
||||
|
||||
if (alen < 0) {
|
||||
puts("I2C read: addr len < 0\n");
|
||||
return 1;
|
||||
}
|
||||
if (len < 0) {
|
||||
puts("I2C read: data len < 0\n");
|
||||
return 1;
|
||||
}
|
||||
if (buffer == NULL) {
|
||||
puts("I2C read: NULL pointer passed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (alen > 2) {
|
||||
printf("I2C read: addr len %d not supported\n", alen);
|
||||
@ -329,24 +286,122 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (i2c_read_byte(chip, addr + i, alen, &buffer[i])) {
|
||||
puts("I2C read: I/O error\n");
|
||||
i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
|
||||
return 1;
|
||||
/* Wait until bus not busy */
|
||||
if (wait_for_bb())
|
||||
return 1;
|
||||
|
||||
/* Zero, one or two bytes reg address (offset) */
|
||||
writew(alen, &i2c_base->cnt);
|
||||
/* Set slave address */
|
||||
writew(chip, &i2c_base->sa);
|
||||
|
||||
if (alen) {
|
||||
/* Must write reg offset first */
|
||||
#ifdef CONFIG_I2C_REPEATED_START
|
||||
/* No stop bit, use Repeated Start (Sr) */
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
|
||||
I2C_CON_TRX, &i2c_base->con);
|
||||
#else
|
||||
/* Stop - Start (P-S) */
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
|
||||
I2C_CON_TRX, &i2c_base->con);
|
||||
#endif
|
||||
/* Send register offset */
|
||||
while (1) {
|
||||
status = wait_for_event();
|
||||
/* Try to identify bus that is not padconf'd for I2C */
|
||||
if (status == I2C_STAT_XRDY) {
|
||||
i2c_error = 2;
|
||||
printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
|
||||
current_bus, status);
|
||||
goto rd_exit;
|
||||
}
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
|
||||
status);
|
||||
goto rd_exit;
|
||||
}
|
||||
if (alen) {
|
||||
if (status & I2C_STAT_XRDY) {
|
||||
alen--;
|
||||
/* Do we have to use byte access? */
|
||||
writeb((addr >> (8 * alen)) & 0xff,
|
||||
&i2c_base->data);
|
||||
writew(I2C_STAT_XRDY, &i2c_base->stat);
|
||||
}
|
||||
}
|
||||
if (status & I2C_STAT_ARDY) {
|
||||
writew(I2C_STAT_ARDY, &i2c_base->stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Set slave address */
|
||||
writew(chip, &i2c_base->sa);
|
||||
/* Read len bytes from slave */
|
||||
writew(len, &i2c_base->cnt);
|
||||
/* Need stop bit here */
|
||||
writew(I2C_CON_EN | I2C_CON_MST |
|
||||
I2C_CON_STT | I2C_CON_STP,
|
||||
&i2c_base->con);
|
||||
|
||||
/* Receive data */
|
||||
while (1) {
|
||||
status = wait_for_event();
|
||||
/*
|
||||
* Try to identify bus that is not padconf'd for I2C. This
|
||||
* state could be left over from previous transactions if
|
||||
* the address phase is skipped due to alen=0.
|
||||
*/
|
||||
if (status == I2C_STAT_XRDY) {
|
||||
i2c_error = 2;
|
||||
printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
|
||||
current_bus, status);
|
||||
goto rd_exit;
|
||||
}
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
goto rd_exit;
|
||||
}
|
||||
if (status & I2C_STAT_RRDY) {
|
||||
*buffer++ = readb(&i2c_base->data);
|
||||
writew(I2C_STAT_RRDY, &i2c_base->stat);
|
||||
}
|
||||
if (status & I2C_STAT_ARDY) {
|
||||
writew(I2C_STAT_ARDY, &i2c_base->stat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
rd_exit:
|
||||
flush_fifo();
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
writew(0, &i2c_base->cnt);
|
||||
return i2c_error;
|
||||
}
|
||||
|
||||
/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
|
||||
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
{
|
||||
int i;
|
||||
u16 status;
|
||||
int i2c_error = 0;
|
||||
u16 w;
|
||||
u8 tmpbuf[2] = {addr >> 8, addr & 0xff};
|
||||
|
||||
if (alen < 0) {
|
||||
puts("I2C write: addr len < 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
puts("I2C write: data len < 0\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (buffer == NULL) {
|
||||
puts("I2C write: NULL pointer passed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (alen > 2) {
|
||||
printf("I2C write: addr len %d not supported\n", alen);
|
||||
@ -355,92 +410,137 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
|
||||
|
||||
if (addr + len > (1 << 16)) {
|
||||
printf("I2C write: address 0x%x + 0x%x out of range\n",
|
||||
addr, len);
|
||||
addr, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* wait until bus not busy */
|
||||
/* Wait until bus not busy */
|
||||
if (wait_for_bb())
|
||||
return 1;
|
||||
|
||||
/* start address phase - will write regoffset + len bytes data */
|
||||
/* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
|
||||
/* Start address phase - will write regoffset + len bytes data */
|
||||
writew(alen + len, &i2c_base->cnt);
|
||||
/* set slave address */
|
||||
/* Set slave address */
|
||||
writew(chip, &i2c_base->sa);
|
||||
/* stop bit needed here */
|
||||
/* Stop bit needed here */
|
||||
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
|
||||
I2C_CON_STP, &i2c_base->con);
|
||||
|
||||
/* Send address and data */
|
||||
for (i = -alen; i < len; i++) {
|
||||
status = wait_for_pin();
|
||||
I2C_CON_STP, &i2c_base->con);
|
||||
|
||||
while (alen) {
|
||||
/* Must write reg offset (one or two bytes) */
|
||||
status = wait_for_event();
|
||||
/* Try to identify bus that is not padconf'd for I2C */
|
||||
if (status == I2C_STAT_XRDY) {
|
||||
i2c_error = 2;
|
||||
printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
|
||||
current_bus, status);
|
||||
goto wr_exit;
|
||||
}
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
printf("i2c error waiting for data ACK (status=0x%x)\n",
|
||||
status);
|
||||
goto write_exit;
|
||||
printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
|
||||
status);
|
||||
goto wr_exit;
|
||||
}
|
||||
|
||||
if (status & I2C_STAT_XRDY) {
|
||||
w = (i < 0) ? tmpbuf[2+i] : buffer[i];
|
||||
#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
|
||||
defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
|
||||
defined(CONFIG_OMAP54XX))
|
||||
w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;
|
||||
#endif
|
||||
writew(w, &i2c_base->data);
|
||||
alen--;
|
||||
writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data);
|
||||
writew(I2C_STAT_XRDY, &i2c_base->stat);
|
||||
} else {
|
||||
i2c_error = 1;
|
||||
printf("i2c bus not ready for Tx (i=%d)\n", i);
|
||||
goto write_exit;
|
||||
printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
|
||||
status);
|
||||
goto wr_exit;
|
||||
}
|
||||
}
|
||||
/* Address phase is over, now write data */
|
||||
for (i = 0; i < len; i++) {
|
||||
status = wait_for_event();
|
||||
if (status == 0 || status & I2C_STAT_NACK) {
|
||||
i2c_error = 1;
|
||||
printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
|
||||
status);
|
||||
goto wr_exit;
|
||||
}
|
||||
if (status & I2C_STAT_XRDY) {
|
||||
writeb(buffer[i], &i2c_base->data);
|
||||
writew(I2C_STAT_XRDY, &i2c_base->stat);
|
||||
} else {
|
||||
i2c_error = 1;
|
||||
printf("i2c_write: bus not ready for data Tx (i=%d)\n",
|
||||
i);
|
||||
goto wr_exit;
|
||||
}
|
||||
}
|
||||
|
||||
write_exit:
|
||||
wr_exit:
|
||||
flush_fifo();
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
writew(0, &i2c_base->cnt);
|
||||
return i2c_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the bus to be free by checking the Bus Busy (BB)
|
||||
* bit to become clear
|
||||
*/
|
||||
static int wait_for_bb(void)
|
||||
{
|
||||
int timeout = I2C_TIMEOUT;
|
||||
u16 stat;
|
||||
|
||||
writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
|
||||
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
|
||||
#else
|
||||
/* Read RAW status */
|
||||
while ((stat = readw(&i2c_base->irqstatus_raw) &
|
||||
I2C_STAT_BB) && timeout--) {
|
||||
#endif
|
||||
writew(stat, &i2c_base->stat);
|
||||
udelay(1000);
|
||||
udelay(I2C_WAIT);
|
||||
}
|
||||
|
||||
if (timeout <= 0) {
|
||||
printf("timed out in wait_for_bb: I2C_STAT=%x\n",
|
||||
readw(&i2c_base->stat));
|
||||
printf("Timed out in wait_for_bb: status=%04x\n",
|
||||
stat);
|
||||
return 1;
|
||||
}
|
||||
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u16 wait_for_pin(void)
|
||||
/*
|
||||
* Wait for the I2C controller to complete current action
|
||||
* and update status
|
||||
*/
|
||||
static u16 wait_for_event(void)
|
||||
{
|
||||
u16 status;
|
||||
int timeout = I2C_TIMEOUT;
|
||||
|
||||
do {
|
||||
udelay(1000);
|
||||
udelay(I2C_WAIT);
|
||||
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
|
||||
status = readw(&i2c_base->stat);
|
||||
#else
|
||||
/* Read RAW status */
|
||||
status = readw(&i2c_base->irqstatus_raw);
|
||||
#endif
|
||||
} while (!(status &
|
||||
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
|
||||
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
|
||||
I2C_STAT_AL)) && timeout--);
|
||||
|
||||
if (timeout <= 0) {
|
||||
printf("timed out in wait_for_pin: I2C_STAT=%x\n",
|
||||
readw(&i2c_base->stat));
|
||||
printf("Timed out in wait_for_event: status=%04x\n",
|
||||
status);
|
||||
/*
|
||||
* If status is still 0 here, probably the bus pads have
|
||||
* not been configured for I2C, and/or pull-ups are missing.
|
||||
*/
|
||||
printf("Check if pads/pull-ups of bus %d are properly configured\n",
|
||||
current_bus);
|
||||
writew(0xFFFF, &i2c_base->stat);
|
||||
status = 0;
|
||||
}
|
||||
@ -450,28 +550,36 @@ static u16 wait_for_pin(void)
|
||||
|
||||
int i2c_set_bus_num(unsigned int bus)
|
||||
{
|
||||
if ((bus < 0) || (bus >= I2C_BUS_MAX)) {
|
||||
printf("Bad bus: %d\n", bus);
|
||||
if (bus >= I2C_BUS_MAX) {
|
||||
printf("Bad bus: %x\n", bus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if I2C_BUS_MAX == 4
|
||||
if (bus == 3)
|
||||
i2c_base = (struct i2c *)I2C_BASE4;
|
||||
else
|
||||
if (bus == 2)
|
||||
i2c_base = (struct i2c *)I2C_BASE3;
|
||||
else
|
||||
#endif
|
||||
#if I2C_BUS_MAX == 3
|
||||
if (bus == 2)
|
||||
i2c_base = (struct i2c *)I2C_BASE3;
|
||||
else
|
||||
#endif
|
||||
if (bus == 1)
|
||||
i2c_base = (struct i2c *)I2C_BASE2;
|
||||
else
|
||||
switch (bus) {
|
||||
default:
|
||||
bus = 0; /* Fall through */
|
||||
case 0:
|
||||
i2c_base = (struct i2c *)I2C_BASE1;
|
||||
break;
|
||||
case 1:
|
||||
i2c_base = (struct i2c *)I2C_BASE2;
|
||||
break;
|
||||
#if (I2C_BUS_MAX > 2)
|
||||
case 2:
|
||||
i2c_base = (struct i2c *)I2C_BASE3;
|
||||
break;
|
||||
#if (I2C_BUS_MAX > 3)
|
||||
case 3:
|
||||
i2c_base = (struct i2c *)I2C_BASE4;
|
||||
break;
|
||||
#if (I2C_BUS_MAX > 4)
|
||||
case 4:
|
||||
i2c_base = (struct i2c *)I2C_BASE5;
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
current_bus = bus;
|
||||
|
||||
|
||||
@ -113,23 +113,21 @@ static void omap5_pbias_config(struct mmc *mmc)
|
||||
u32 value = 0;
|
||||
|
||||
value = readl((*ctrl)->control_pbias);
|
||||
value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
|
||||
value |= SDCARD_BIAS_HIZ_MODE;
|
||||
value &= ~SDCARD_PWRDNZ;
|
||||
writel(value, (*ctrl)->control_pbias);
|
||||
udelay(10); /* wait 10 us */
|
||||
value &= ~SDCARD_BIAS_PWRDNZ;
|
||||
writel(value, (*ctrl)->control_pbias);
|
||||
|
||||
palmas_mmc1_poweron_ldo();
|
||||
|
||||
value = readl((*ctrl)->control_pbias);
|
||||
value &= ~SDCARD_BIAS_HIZ_MODE;
|
||||
value |= SDCARD_PBIASLITE_VMODE | SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ;
|
||||
value |= SDCARD_BIAS_PWRDNZ;
|
||||
writel(value, (*ctrl)->control_pbias);
|
||||
|
||||
value = readl((*ctrl)->control_pbias);
|
||||
if (value & (1 << 23)) {
|
||||
value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
|
||||
value |= SDCARD_BIAS_HIZ_MODE;
|
||||
writel(value, (*ctrl)->control_pbias);
|
||||
}
|
||||
udelay(150); /* wait 150 us */
|
||||
value |= SDCARD_PWRDNZ;
|
||||
writel(value, (*ctrl)->control_pbias);
|
||||
udelay(150); /* wait 150 us */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -516,9 +516,7 @@ static int fec_open(struct eth_device *edev)
|
||||
#ifdef FEC_QUIRK_ENET_MAC
|
||||
{
|
||||
u32 ecr = readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_SPEED;
|
||||
u32 rcr = (readl(&fec->eth->r_cntrl) &
|
||||
~(FEC_RCNTRL_RMII | FEC_RCNTRL_RMII_10T)) |
|
||||
FEC_RCNTRL_RGMII | FEC_RCNTRL_MII_MODE;
|
||||
u32 rcr = readl(&fec->eth->r_cntrl) & ~FEC_RCNTRL_RMII_10T;
|
||||
if (speed == _1000BASET)
|
||||
ecr |= FEC_ECNTRL_SPEED;
|
||||
else if (speed != _100BASET)
|
||||
|
||||
@ -25,28 +25,137 @@
|
||||
|
||||
void palmas_init_settings(void)
|
||||
{
|
||||
return;
|
||||
#ifdef CONFIG_PALMAS_SMPS7_FPWM
|
||||
int err;
|
||||
/*
|
||||
* Set SMPS7 (1.8 V I/O supply on platforms with TWL6035/37) to
|
||||
* forced PWM mode. This reduces noise (but affects efficiency).
|
||||
*/
|
||||
u8 val = SMPS_MODE_SLP_FPWM | SMPS_MODE_ACT_FPWM;
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS7_CTRL, val);
|
||||
if (err)
|
||||
printf("palmas: could not force PWM for SMPS7: err = %d\n",
|
||||
err);
|
||||
#endif
|
||||
}
|
||||
|
||||
int palmas_mmc1_poweron_ldo(void)
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
/* set LDO9 TWL6035 to 3V */
|
||||
val = 0x2b; /* (3 -.9)*28 +1 */
|
||||
|
||||
if (palmas_i2c_write_u8(0x48, LDO9_VOLTAGE, val)) {
|
||||
printf("twl6035: could not set LDO9 voltage.\n");
|
||||
#if defined(CONFIG_DRA7XX)
|
||||
/*
|
||||
* Currently valid for the dra7xx_evm board:
|
||||
* Set TPS659038 LDO1 to 3.0 V
|
||||
*/
|
||||
val = LDO_VOLT_3V0;
|
||||
if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_VOLTAGE, val)) {
|
||||
printf("tps65903x: could not set LDO1 voltage.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* TURN ON LDO9 */
|
||||
val = LDO_ON | LDO_MODE_SLEEP | LDO_MODE_ACTIVE;
|
||||
|
||||
if (palmas_i2c_write_u8(0x48, LDO9_CTRL, val)) {
|
||||
printf("twl6035: could not turn on LDO9.\n");
|
||||
/* TURN ON LDO1 */
|
||||
val = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
|
||||
if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_CTRL, val)) {
|
||||
printf("tps65903x: could not turn on LDO1.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
/*
|
||||
* We assume that this is a OMAP543X + TWL603X board:
|
||||
* Set TWL6035/37 LDO9 to 3.0 V
|
||||
*/
|
||||
val = LDO_VOLT_3V0;
|
||||
return twl603x_mmc1_set_ldo9(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* On some OMAP5 + TWL603X hardware the SD card socket and LDO9_IN are
|
||||
* powered by an external 3.3 V regulator, while the output of LDO9
|
||||
* supplies VDDS_SDCARD for the OMAP5 interface only. This implies that
|
||||
* LDO9 could be set to 'bypass' mode when required (e.g. for 3.3 V cards).
|
||||
*/
|
||||
int twl603x_mmc1_set_ldo9(u8 vsel)
|
||||
{
|
||||
u8 cval = 0, vval = 0; /* Off by default */
|
||||
int err;
|
||||
|
||||
if (vsel) {
|
||||
/* Turn on */
|
||||
if (vsel > LDO_VOLT_3V3) {
|
||||
/* Put LDO9 in bypass */
|
||||
cval = LDO9_BYP_EN | RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
|
||||
vval = LDO_VOLT_3V3;
|
||||
} else {
|
||||
cval = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
|
||||
vval = vsel & 0x3f;
|
||||
}
|
||||
}
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_VOLTAGE, vval);
|
||||
if (err) {
|
||||
printf("twl603x: could not set LDO9 %s: err = %d\n",
|
||||
vsel > LDO_VOLT_3V3 ? "bypass" : "voltage", err);
|
||||
return err;
|
||||
}
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_CTRL, cval);
|
||||
if (err)
|
||||
printf("twl603x: could not turn %s LDO9: err = %d\n",
|
||||
cval ? "on" : "off", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PALMAS_AUDPWR
|
||||
/*
|
||||
* Turn audio codec power and 32 kHz clock on/off. Use for
|
||||
* testing OMAP543X + TWL603X + TWL604X boards only.
|
||||
*/
|
||||
int twl603x_audio_power(u8 on)
|
||||
{
|
||||
u8 cval = 0, vval = 0, c32k = 0;
|
||||
int err;
|
||||
|
||||
if (on) {
|
||||
vval = SMPS_VOLT_2V1;
|
||||
cval = SMPS_MODE_SLP_AUTO | SMPS_MODE_ACT_AUTO;
|
||||
c32k = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
|
||||
}
|
||||
/* Set SMPS9 to 2.1 V (for TWL604x), or to 0 (off) */
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_VOLTAGE, vval);
|
||||
if (err) {
|
||||
printf("twl603x: could not set SMPS9 voltage: err = %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
/* Turn on or off SMPS9 */
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_CTRL, cval);
|
||||
if (err) {
|
||||
printf("twl603x: could not turn SMPS9 %s: err = %d\n",
|
||||
cval ? "on" : "off", err);
|
||||
return err;
|
||||
}
|
||||
/* Output 32 kHz clock on or off */
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, CLK32KGAUDIO_CTRL, c32k);
|
||||
if (err)
|
||||
printf("twl603x: could not turn CLK32KGAUDIO %s: err = %d\n",
|
||||
c32k ? "on" : "off", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable/disable back-up battery (or super cap) charging on TWL6035/37.
|
||||
* Please use defined BB_xxx values.
|
||||
*/
|
||||
int twl603x_enable_bb_charge(u8 bb_fields)
|
||||
{
|
||||
u8 val = bb_fields & 0x0f;
|
||||
int err;
|
||||
|
||||
val |= (VRTC_EN_SLP | VRTC_EN_OFF | VRTC_PWEN);
|
||||
err = palmas_i2c_write_u8(TWL603X_CHIP_P1, BB_VRTC_CTRL, val);
|
||||
if (err)
|
||||
printf("twl603x: could not set BB_VRTC_CTRL to 0x%02x: err = %d\n",
|
||||
val, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -53,6 +53,7 @@ COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
|
||||
COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
|
||||
COBJS-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o
|
||||
COBJS-$(CONFIG_BFIN_SERIAL) += serial_bfin.o
|
||||
COBJS-$(CONFIG_FSL_LPUART) += serial_lpuart.o
|
||||
|
||||
ifndef CONFIG_SPL_BUILD
|
||||
COBJS-$(CONFIG_USB_TTY) += usbtty.o
|
||||
|
||||
@ -74,13 +74,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
|
||||
defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \
|
||||
defined(CONFIG_TI814X)
|
||||
|
||||
#if defined(CONFIG_APTIX)
|
||||
/* /13 mode so Aptix 6MHz can hit 115200 */
|
||||
serial_out(3, &com_port->mdr1);
|
||||
#else
|
||||
/* /16 is proper to hit 115200 with 48MHz */
|
||||
serial_out(0, &com_port->mdr1);
|
||||
#endif
|
||||
#endif /* CONFIG_OMAP */
|
||||
}
|
||||
|
||||
|
||||
132
drivers/serial/serial_lpuart.c
Normal file
132
drivers/serial/serial_lpuart.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2013 Freescale Semiconductor, 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; either 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <watchdog.h>
|
||||
#include <asm/io.h>
|
||||
#include <serial.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
|
||||
#define US1_TDRE (1 << 7)
|
||||
#define US1_RDRF (1 << 5)
|
||||
#define UC2_TE (1 << 3)
|
||||
#define UC2_RE (1 << 2)
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE;
|
||||
|
||||
static void lpuart_serial_setbrg(void)
|
||||
{
|
||||
u32 clk = mxc_get_clock(MXC_UART_CLK);
|
||||
u16 sbr;
|
||||
|
||||
if (!gd->baudrate)
|
||||
gd->baudrate = CONFIG_BAUDRATE;
|
||||
|
||||
sbr = (u16)(clk / (16 * gd->baudrate));
|
||||
/* place adjustment later - n/32 BRFA */
|
||||
|
||||
__raw_writeb(sbr >> 8, &base->ubdh);
|
||||
__raw_writeb(sbr & 0xff, &base->ubdl);
|
||||
}
|
||||
|
||||
static int lpuart_serial_getc(void)
|
||||
{
|
||||
u8 status;
|
||||
|
||||
while (!(__raw_readb(&base->us1) & US1_RDRF))
|
||||
WATCHDOG_RESET();
|
||||
|
||||
status = __raw_readb(&base->us1);
|
||||
status |= US1_RDRF;
|
||||
__raw_writeb(status, &base->us1);
|
||||
|
||||
return __raw_readb(&base->ud);
|
||||
}
|
||||
|
||||
static void lpuart_serial_putc(const char c)
|
||||
{
|
||||
if (c == '\n')
|
||||
serial_putc('\r');
|
||||
|
||||
while (!(__raw_readb(&base->us1) & US1_TDRE))
|
||||
WATCHDOG_RESET();
|
||||
|
||||
__raw_writeb(c, &base->ud);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test whether a character is in the RX buffer
|
||||
*/
|
||||
static int lpuart_serial_tstc(void)
|
||||
{
|
||||
if (__raw_readb(&base->urcfifo) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static int lpuart_serial_init(void)
|
||||
{
|
||||
u8 ctrl;
|
||||
|
||||
ctrl = __raw_readb(&base->uc2);
|
||||
ctrl &= ~UC2_RE;
|
||||
ctrl &= ~UC2_TE;
|
||||
__raw_writeb(ctrl, &base->uc2);
|
||||
|
||||
__raw_writeb(0, &base->umodem);
|
||||
__raw_writeb(0, &base->uc1);
|
||||
|
||||
/* provide data bits, parity, stop bit, etc */
|
||||
|
||||
serial_setbrg();
|
||||
|
||||
__raw_writeb(UC2_RE | UC2_TE, &base->uc2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct serial_device lpuart_serial_drv = {
|
||||
.name = "lpuart_serial",
|
||||
.start = lpuart_serial_init,
|
||||
.stop = NULL,
|
||||
.setbrg = lpuart_serial_setbrg,
|
||||
.putc = lpuart_serial_putc,
|
||||
.puts = default_serial_puts,
|
||||
.getc = lpuart_serial_getc,
|
||||
.tstc = lpuart_serial_tstc,
|
||||
};
|
||||
|
||||
void lpuart_serial_initialize(void)
|
||||
{
|
||||
serial_register(&lpuart_serial_drv);
|
||||
}
|
||||
|
||||
__weak struct serial_device *default_serial_console(void)
|
||||
{
|
||||
return &lpuart_serial_drv;
|
||||
}
|
||||
@ -151,12 +151,7 @@ static int calc_divisor (NS16550_t port)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_APTIX
|
||||
#define MODE_X_DIV 13
|
||||
#else
|
||||
#define MODE_X_DIV 16
|
||||
#endif
|
||||
|
||||
/* Compute divisor value. Normally, we should simply return:
|
||||
* CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate
|
||||
* but we need to round that value by adding 0.5.
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
* MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <asm/omap_common.h>
|
||||
#include <twl4030.h>
|
||||
#include <twl6030.h>
|
||||
#include "omap3.h"
|
||||
@ -135,7 +136,8 @@ int musb_platform_init(void)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP4430
|
||||
u32 *usbotghs_control = (u32 *)(CTRL_BASE + 0x33C);
|
||||
u32 *usbotghs_control =
|
||||
(u32 *)((*ctrl)->control_usbotghs_ctrl);
|
||||
*usbotghs_control = 0x15;
|
||||
#endif
|
||||
platform_needs_initialization = 0;
|
||||
|
||||
@ -39,6 +39,11 @@ static GraphicDevice panel;
|
||||
* setenv videomode
|
||||
* video=ctfb:x:800,y:480,depth:18,mode:0,pclk:30066,
|
||||
* le:0,ri:256,up:0,lo:45,hs:1,vs:1,sync:100663296,vmode:0
|
||||
*
|
||||
* Freescale mx23evk/mx28evk with a Seiko 4.3'' WVGA panel:
|
||||
* setenv videomode
|
||||
* video=ctfb:x:800,y:480,depth:24,mode:0,pclk:29851,
|
||||
* le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
|
||||
*/
|
||||
|
||||
static void mxs_lcd_init(GraphicDevice *panel,
|
||||
|
||||
@ -27,7 +27,7 @@ LIB := $(obj)libwatchdog.o
|
||||
|
||||
COBJS-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o
|
||||
COBJS-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
|
||||
ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6))
|
||||
ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6 vf610))
|
||||
COBJS-y += imx_watchdog.o
|
||||
endif
|
||||
COBJS-$(CONFIG_TNETV107X_WATCHDOG) += tnetv107x_wdt.o
|
||||
|
||||
Reference in New Issue
Block a user