diff --git a/qiboot/include/i2c-bitbang-s3c24xx.h b/qiboot/include/i2c-bitbang-s3c24xx.h new file mode 100644 index 0000000..6be18b9 --- /dev/null +++ b/qiboot/include/i2c-bitbang-s3c24xx.h @@ -0,0 +1,3 @@ +#include + +extern struct i2c_bitbang bb_s3c24xx; diff --git a/qiboot/include/i2c-bitbang.h b/qiboot/include/i2c-bitbang.h new file mode 100644 index 0000000..0873b3b --- /dev/null +++ b/qiboot/include/i2c-bitbang.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Generic i2c bitbang state machine + * + * 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 + * + */ + +/* controls symbol sequencing on i2c */ + +enum i2c_bitbang_control { + IBCONTROL_DO_START = -1, + IBCONTROL_DO_STOP = -2, + IBCONTROL_DO_READ = -3, + IBCONTROL_COMPLETE = -4 +}; + +/* control intra-bit and byte states */ + +enum i2c_bitbang_states { + IBS_INIT, + + IBS_START1, + IBS_START2, + + IBS_ADS_TX_S, + IBS_ADS_TX_H, + IBS_ADS_TX_L, + IBS_ADS_TX_ACK_H, + IBS_ADS_TX_ACK_L, + + IBS_DATA_RX_S, + IBS_DATA_RX_H, + IBS_DATA_RX_L, + + IBS_DATA_RX_ACK_H, + IBS_DATA_RX_ACK_L, + + IBS_STOP1, + IBS_STOP2, + IBS_STOP3 +}; + +/* context for bitbang GPIO pins and transaction */ + +struct i2c_bitbang { + + enum i2c_bitbang_states state; + int count; + unsigned int data[8]; /* read result found here */ + int index; + int index_read; + + char (*read_sda)(void); + /* data = 0 = op low, 1 == inp */ + void (*set)(char clock, char data); + /* delay > 1 half-bit time, used by i2c_complete_synchronously() */ + void (*spin)(void); + void (*close)(void); +}; + +/* synchronous read and write functions spin until completed or failed + * i2c_read_sync returns -1 for fail or byte result from device + */ + +extern int i2c_read_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg); +extern void i2c_write_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char data); + + +/* + * set up an asynchronous read or write transaction + */ +extern void i2c_read(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg); +extern void i2c_write(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char data); + +/* + * after setting up a read or write transaction above, you loop calling this + * with >= 1.25us (400kHz) or >= 5us (100kHz) delay between calls. You don't + * have to spin but can do something useful if you know it will take more than + * an i2c bit-time, hiding the time for the i2c transaction completely. + */ +extern int i2c_next_state(struct i2c_bitbang * bb); /* return !=0 = completed */ diff --git a/qiboot/src/drivers/i2c-bitbang-s3c24xx.c b/qiboot/src/drivers/i2c-bitbang-s3c24xx.c new file mode 100644 index 0000000..353dedc --- /dev/null +++ b/qiboot/src/drivers/i2c-bitbang-s3c24xx.c @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * s3c24xx-specific i2c shared by, eg, GTA02 and GTA03 + * + * 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 +#include + +static char i2c_read_sda_s3c24xx(void) +{ + return (rGPEDAT & 0x8000) != 0; +} + +static void i2c_set_s3c24xx(char clock, char data) +{ + if (clock) /* SCL <- input */ + rGPECON = (rGPECON & ~0x30000000); + else { /* SCL <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x4000); + rGPECON = (rGPECON & ~0x30000000) | 0x10000000; + } + if (data) /* SDA <- input */ + rGPECON = (rGPECON & ~0xc0000000); + else { /* SDA <- output 0 */ + rGPEDAT = (rGPEDAT & ~0x8000); + rGPECON = (rGPECON & ~0xc0000000) | 0x40000000; + } +} + +static void i2c_close_s3c24xx(void) +{ + /* set back to hardware I2C ready for Linux */ + rGPECON = (rGPECON & ~0xf0000000) | 0xa0000000; +} + +static void i2c_spin_s3c24xx(void) +{ + int n; + + for (n = 0; n < 700; n++) + rGPJDAT |= (1 << 5); +} + +struct i2c_bitbang bb_s3c24xx = { + .read_sda = i2c_read_sda_s3c24xx, + .set = i2c_set_s3c24xx, + .spin = i2c_spin_s3c24xx, + .close = i2c_close_s3c24xx, +}; diff --git a/qiboot/src/drivers/i2c-bitbang.c b/qiboot/src/drivers/i2c-bitbang.c new file mode 100644 index 0000000..9762415 --- /dev/null +++ b/qiboot/src/drivers/i2c-bitbang.c @@ -0,0 +1,230 @@ +/* + * (C) Copyright 2007 OpenMoko, Inc. + * Author: Andy Green + * + * Generic i2c bitbang state machine + * + * 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 +#include + +void i2c_read(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg) +{ + bb->data[0] = (ads7 << 1); /* write the register address */ + bb->data[1] = reg; + bb->data[2] = IBCONTROL_DO_START; + bb->data[3] = (ads7 << 1) | 1; /* then issue read cycle to device */ + bb->data[4] = IBCONTROL_DO_READ; + bb->data[5] = IBCONTROL_DO_STOP; + bb->data[6] = IBCONTROL_COMPLETE; + bb->state = IBS_INIT; +} + +void i2c_write(struct i2c_bitbang * bb, unsigned char ads7, unsigned char reg, + unsigned char b) +{ + bb->data[0] = (ads7 << 1); + bb->data[1] = reg; + bb->data[2] = b; + bb->data[3] = IBCONTROL_DO_STOP; + bb->data[4] = IBCONTROL_COMPLETE; + bb->state = IBS_INIT; +} + +int i2c_next_state(struct i2c_bitbang * bb) +{ + switch (bb->state) { + case IBS_INIT: + bb->index = 0; + bb->index_read = 0; + /* fall thru */ + case IBS_START1: + (bb->set)(1, 0); + (bb->set)(0, 0); /* start */ + bb->state = IBS_START2; + break; + + case IBS_START2: + bb->count = 8; + bb->state = IBS_ADS_TX_S; + break; + + /* transmit address or data */ + case IBS_ADS_TX_S: + (bb->set)(0, !!(bb->data[bb->index] & 0x80)); + bb->state = IBS_ADS_TX_H; + break; + case IBS_ADS_TX_H: + (bb->set)(1, !!(bb->data[bb->index] & 0x80)); + bb->state = IBS_ADS_TX_L; + break; + case IBS_ADS_TX_L: + (bb->set)(0, !!(bb->data[bb->index] & 0x80)); + bb->data[bb->index] <<= 1; + bb->count--; + if (bb->count) { + bb->state = IBS_ADS_TX_S; + break; + } + + (bb->set)(0, 1); + bb->state = IBS_ADS_TX_ACK_H; + break; + + case IBS_ADS_TX_ACK_H: + /* we finished... we expect an ack now */ + if ((bb->read_sda)()) + return -1; + + (bb->set)(1, 1); + bb->state = IBS_ADS_TX_ACK_L; + break; + + case IBS_ADS_TX_ACK_L: + (bb->set)(0, 1); + + bb->count = 8; + bb->index++; + switch (bb->data[bb->index]) { + case IBCONTROL_DO_START: + bb->state = IBS_START1; + bb->index++; + break; + case IBCONTROL_DO_STOP: + bb->state = IBS_STOP1; + bb->index++; + break; + case IBCONTROL_DO_READ: + bb->data[bb->index_read] = 0; + bb->state = IBS_DATA_RX_S; + break; + case IBCONTROL_COMPLETE: + return 1; + default: + bb->state = IBS_ADS_TX_S; /* write it out */ + break; + } + break; + + + /* receive data */ + case IBS_DATA_RX_S: + (bb->set)(0, 1); + bb->state = IBS_DATA_RX_H; + break; + + case IBS_DATA_RX_H: + (bb->set)(1, 1); + bb->state = IBS_DATA_RX_L; + break; + + case IBS_DATA_RX_L: + bb->data[bb->index_read] <<= 1; + bb->data[bb->index_read] |= !!(bb->read_sda)(); + (bb->set)(0, 1); + bb->count--; + if (bb->count) { + bb->state = IBS_DATA_RX_S; + break; + } + + /* slave has released SDA now, bang down ACK */ + (bb->set)(0, 0); + bb->state = IBS_DATA_RX_ACK_H; + break; + + case IBS_DATA_RX_ACK_H: + (bb->set)(1, 0); + bb->state = IBS_DATA_RX_ACK_L; + break; + + case IBS_DATA_RX_ACK_L: + (bb->set)(0, 1); + bb->index_read++; + bb->index++; + switch (bb->data[bb->index]) { + case IBCONTROL_DO_START: + bb->state = IBS_START1; + bb->index++; + break; + case IBCONTROL_DO_STOP: + bb->state = IBS_STOP1; + bb->index++; + break; + case IBCONTROL_DO_READ: + bb->state = IBS_DATA_RX_S; + bb->data[bb->index_read] = 0; + break; + case IBCONTROL_COMPLETE: + return 1; + default: + bb->state = IBS_ADS_TX_S; /* write it out */ + break; + } + break; + + break; + + + case IBS_STOP1: + (bb->set)(0, 0); + bb->state = IBS_STOP2; + break; + + case IBS_STOP2: + (bb->set)(1, 0); + bb->state = IBS_STOP3; + break; + + case IBS_STOP3: + (bb->set)(1, 1); + return 1; /* done */ + } + + return 0; /* keep going */ +} + +static int i2c_complete_synchronously(struct i2c_bitbang * bb) +{ + int ret = 0; + + while (!ret) { + ret = i2c_next_state(bb); + (bb->spin)(); + } + + return ret; +} + +int i2c_read_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg) +{ + i2c_read(bb, ads7, reg); + if (i2c_complete_synchronously(bb) < 0) + return -1; + + return bb->data[0]; +} + +void i2c_write_sync(struct i2c_bitbang * bb, unsigned char ads7, + unsigned char reg, unsigned char b) +{ + i2c_write(bb, ads7, reg, b); + i2c_complete_synchronously(bb); +} diff --git a/qiboot/src/gta02/gta02.c b/qiboot/src/gta02/gta02.c index b74b727..8bdcaa9 100644 --- a/qiboot/src/gta02/gta02.c +++ b/qiboot/src/gta02/gta02.c @@ -37,8 +37,10 @@ static const struct board_variant board_variants[] = { } }; + void port_init_gta02(void) { + //CAUTION:Follow the configuration order for setting the ports. // 1) setting value(GPnDAT) // 2) setting control register (GPnCON)