1942ba996SJean-Christophe PLAGNIOL-VILLARD /* 2942ba996SJean-Christophe PLAGNIOL-VILLARD * TI DaVinci (TMS320DM644x) I2C driver. 3942ba996SJean-Christophe PLAGNIOL-VILLARD * 4942ba996SJean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> 5942ba996SJean-Christophe PLAGNIOL-VILLARD * 6942ba996SJean-Christophe PLAGNIOL-VILLARD * -------------------------------------------------------- 7942ba996SJean-Christophe PLAGNIOL-VILLARD * 8942ba996SJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 9942ba996SJean-Christophe PLAGNIOL-VILLARD * project. 10942ba996SJean-Christophe PLAGNIOL-VILLARD * 11942ba996SJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 12942ba996SJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 13942ba996SJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 14942ba996SJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 15942ba996SJean-Christophe PLAGNIOL-VILLARD * 16942ba996SJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 17942ba996SJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 18942ba996SJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19942ba996SJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 20942ba996SJean-Christophe PLAGNIOL-VILLARD * 21942ba996SJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 22942ba996SJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 23942ba996SJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 24942ba996SJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 25942ba996SJean-Christophe PLAGNIOL-VILLARD */ 26942ba996SJean-Christophe PLAGNIOL-VILLARD 27942ba996SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 28942ba996SJean-Christophe PLAGNIOL-VILLARD #include <i2c.h> 29942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/hardware.h> 30942ba996SJean-Christophe PLAGNIOL-VILLARD #include <asm/arch/i2c_defs.h> 31942ba996SJean-Christophe PLAGNIOL-VILLARD 32942ba996SJean-Christophe PLAGNIOL-VILLARD #define CHECK_NACK() \ 33942ba996SJean-Christophe PLAGNIOL-VILLARD do {\ 34942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\ 35942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0;\ 36942ba996SJean-Christophe PLAGNIOL-VILLARD return(1);\ 37942ba996SJean-Christophe PLAGNIOL-VILLARD }\ 38942ba996SJean-Christophe PLAGNIOL-VILLARD } while (0) 39942ba996SJean-Christophe PLAGNIOL-VILLARD 40942ba996SJean-Christophe PLAGNIOL-VILLARD 41942ba996SJean-Christophe PLAGNIOL-VILLARD static int wait_for_bus(void) 42942ba996SJean-Christophe PLAGNIOL-VILLARD { 43942ba996SJean-Christophe PLAGNIOL-VILLARD int stat, timeout; 44942ba996SJean-Christophe PLAGNIOL-VILLARD 45942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 46942ba996SJean-Christophe PLAGNIOL-VILLARD 47942ba996SJean-Christophe PLAGNIOL-VILLARD for (timeout = 0; timeout < 10; timeout++) { 48942ba996SJean-Christophe PLAGNIOL-VILLARD if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) { 49942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 50942ba996SJean-Christophe PLAGNIOL-VILLARD return(0); 51942ba996SJean-Christophe PLAGNIOL-VILLARD } 52942ba996SJean-Christophe PLAGNIOL-VILLARD 53942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = stat; 54942ba996SJean-Christophe PLAGNIOL-VILLARD udelay(50000); 55942ba996SJean-Christophe PLAGNIOL-VILLARD } 56942ba996SJean-Christophe PLAGNIOL-VILLARD 57942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 58942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 59942ba996SJean-Christophe PLAGNIOL-VILLARD } 60942ba996SJean-Christophe PLAGNIOL-VILLARD 61942ba996SJean-Christophe PLAGNIOL-VILLARD 62942ba996SJean-Christophe PLAGNIOL-VILLARD static int poll_i2c_irq(int mask) 63942ba996SJean-Christophe PLAGNIOL-VILLARD { 64942ba996SJean-Christophe PLAGNIOL-VILLARD int stat, timeout; 65942ba996SJean-Christophe PLAGNIOL-VILLARD 66942ba996SJean-Christophe PLAGNIOL-VILLARD for (timeout = 0; timeout < 10; timeout++) { 67942ba996SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 68942ba996SJean-Christophe PLAGNIOL-VILLARD stat = REG(I2C_STAT); 69942ba996SJean-Christophe PLAGNIOL-VILLARD if (stat & mask) { 70942ba996SJean-Christophe PLAGNIOL-VILLARD return(stat); 71942ba996SJean-Christophe PLAGNIOL-VILLARD } 72942ba996SJean-Christophe PLAGNIOL-VILLARD } 73942ba996SJean-Christophe PLAGNIOL-VILLARD 74942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 75942ba996SJean-Christophe PLAGNIOL-VILLARD return(stat | I2C_TIMEOUT); 76942ba996SJean-Christophe PLAGNIOL-VILLARD } 77942ba996SJean-Christophe PLAGNIOL-VILLARD 78942ba996SJean-Christophe PLAGNIOL-VILLARD 79942ba996SJean-Christophe PLAGNIOL-VILLARD void flush_rx(void) 80942ba996SJean-Christophe PLAGNIOL-VILLARD { 81942ba996SJean-Christophe PLAGNIOL-VILLARD int dummy; 82942ba996SJean-Christophe PLAGNIOL-VILLARD 83942ba996SJean-Christophe PLAGNIOL-VILLARD while (1) { 84942ba996SJean-Christophe PLAGNIOL-VILLARD if (!(REG(I2C_STAT) & I2C_STAT_RRDY)) 85942ba996SJean-Christophe PLAGNIOL-VILLARD break; 86942ba996SJean-Christophe PLAGNIOL-VILLARD 87942ba996SJean-Christophe PLAGNIOL-VILLARD dummy = REG(I2C_DRR); 88942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = I2C_STAT_RRDY; 89942ba996SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 90942ba996SJean-Christophe PLAGNIOL-VILLARD } 91942ba996SJean-Christophe PLAGNIOL-VILLARD } 92942ba996SJean-Christophe PLAGNIOL-VILLARD 93942ba996SJean-Christophe PLAGNIOL-VILLARD 94942ba996SJean-Christophe PLAGNIOL-VILLARD void i2c_init(int speed, int slaveadd) 95942ba996SJean-Christophe PLAGNIOL-VILLARD { 96942ba996SJean-Christophe PLAGNIOL-VILLARD u_int32_t div, psc; 97942ba996SJean-Christophe PLAGNIOL-VILLARD 98942ba996SJean-Christophe PLAGNIOL-VILLARD if (REG(I2C_CON) & I2C_CON_EN) { 99942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 100942ba996SJean-Christophe PLAGNIOL-VILLARD udelay (50000); 101942ba996SJean-Christophe PLAGNIOL-VILLARD } 102942ba996SJean-Christophe PLAGNIOL-VILLARD 103942ba996SJean-Christophe PLAGNIOL-VILLARD psc = 2; 104942ba996SJean-Christophe PLAGNIOL-VILLARD div = (CONFIG_SYS_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */ 105942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */ 106942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */ 107942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SCLH) = div - REG(I2C_SCLL); 108942ba996SJean-Christophe PLAGNIOL-VILLARD 109942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_OA) = slaveadd; 110942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = 0; 111942ba996SJean-Christophe PLAGNIOL-VILLARD 112942ba996SJean-Christophe PLAGNIOL-VILLARD /* Interrupts must be enabled or I2C module won't work */ 113942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE | 114942ba996SJean-Christophe PLAGNIOL-VILLARD I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE; 115942ba996SJean-Christophe PLAGNIOL-VILLARD 116942ba996SJean-Christophe PLAGNIOL-VILLARD /* Now enable I2C controller (get it out of reset) */ 117942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = I2C_CON_EN; 118942ba996SJean-Christophe PLAGNIOL-VILLARD 119942ba996SJean-Christophe PLAGNIOL-VILLARD udelay(1000); 120942ba996SJean-Christophe PLAGNIOL-VILLARD } 121942ba996SJean-Christophe PLAGNIOL-VILLARD 122*49d6da60SHeiko Schocher int i2c_set_bus_speed(unsigned int speed) 123*49d6da60SHeiko Schocher { 124*49d6da60SHeiko Schocher i2c_init(speed, CONFIG_SYS_I2C_SLAVE); 125*49d6da60SHeiko Schocher return 0; 126*49d6da60SHeiko Schocher } 127942ba996SJean-Christophe PLAGNIOL-VILLARD 128942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_probe(u_int8_t chip) 129942ba996SJean-Christophe PLAGNIOL-VILLARD { 130942ba996SJean-Christophe PLAGNIOL-VILLARD int rc = 1; 131942ba996SJean-Christophe PLAGNIOL-VILLARD 132942ba996SJean-Christophe PLAGNIOL-VILLARD if (chip == REG(I2C_OA)) { 133942ba996SJean-Christophe PLAGNIOL-VILLARD return(rc); 134942ba996SJean-Christophe PLAGNIOL-VILLARD } 135942ba996SJean-Christophe PLAGNIOL-VILLARD 136942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 137942ba996SJean-Christophe PLAGNIOL-VILLARD if (wait_for_bus()) {return(1);} 138942ba996SJean-Christophe PLAGNIOL-VILLARD 139942ba996SJean-Christophe PLAGNIOL-VILLARD /* try to read one byte from current (or only) address */ 140942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = 1; 141942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SA) = chip; 142942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP); 143942ba996SJean-Christophe PLAGNIOL-VILLARD udelay (50000); 144942ba996SJean-Christophe PLAGNIOL-VILLARD 145942ba996SJean-Christophe PLAGNIOL-VILLARD if (!(REG(I2C_STAT) & I2C_STAT_NACK)) { 146942ba996SJean-Christophe PLAGNIOL-VILLARD rc = 0; 147942ba996SJean-Christophe PLAGNIOL-VILLARD flush_rx(); 148942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 149942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 150942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 151942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) |= I2C_CON_STP; 152942ba996SJean-Christophe PLAGNIOL-VILLARD udelay(20000); 153942ba996SJean-Christophe PLAGNIOL-VILLARD if (wait_for_bus()) {return(1);} 154942ba996SJean-Christophe PLAGNIOL-VILLARD } 155942ba996SJean-Christophe PLAGNIOL-VILLARD 156942ba996SJean-Christophe PLAGNIOL-VILLARD flush_rx(); 157942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 158942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = 0; 159942ba996SJean-Christophe PLAGNIOL-VILLARD return(rc); 160942ba996SJean-Christophe PLAGNIOL-VILLARD } 161942ba996SJean-Christophe PLAGNIOL-VILLARD 162942ba996SJean-Christophe PLAGNIOL-VILLARD 163942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) 164942ba996SJean-Christophe PLAGNIOL-VILLARD { 165942ba996SJean-Christophe PLAGNIOL-VILLARD u_int32_t tmp; 166942ba996SJean-Christophe PLAGNIOL-VILLARD int i; 167942ba996SJean-Christophe PLAGNIOL-VILLARD 168942ba996SJean-Christophe PLAGNIOL-VILLARD if ((alen < 0) || (alen > 2)) { 169942ba996SJean-Christophe PLAGNIOL-VILLARD printf("%s(): bogus address length %x\n", __FUNCTION__, alen); 170942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 171942ba996SJean-Christophe PLAGNIOL-VILLARD } 172942ba996SJean-Christophe PLAGNIOL-VILLARD 173942ba996SJean-Christophe PLAGNIOL-VILLARD if (wait_for_bus()) {return(1);} 174942ba996SJean-Christophe PLAGNIOL-VILLARD 175942ba996SJean-Christophe PLAGNIOL-VILLARD if (alen != 0) { 176942ba996SJean-Christophe PLAGNIOL-VILLARD /* Start address phase */ 177942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX; 178942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = alen; 179942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SA) = chip; 180942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = tmp; 181942ba996SJean-Christophe PLAGNIOL-VILLARD 182942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); 183942ba996SJean-Christophe PLAGNIOL-VILLARD 184942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 185942ba996SJean-Christophe PLAGNIOL-VILLARD 186942ba996SJean-Christophe PLAGNIOL-VILLARD switch (alen) { 187942ba996SJean-Christophe PLAGNIOL-VILLARD case 2: 188942ba996SJean-Christophe PLAGNIOL-VILLARD /* Send address MSByte */ 189942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_XRDY) { 190942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_DXR) = (addr >> 8) & 0xff; 191942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 192942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 193942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 194942ba996SJean-Christophe PLAGNIOL-VILLARD } 195942ba996SJean-Christophe PLAGNIOL-VILLARD 196942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); 197942ba996SJean-Christophe PLAGNIOL-VILLARD 198942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 199942ba996SJean-Christophe PLAGNIOL-VILLARD /* No break, fall through */ 200942ba996SJean-Christophe PLAGNIOL-VILLARD case 1: 201942ba996SJean-Christophe PLAGNIOL-VILLARD /* Send address LSByte */ 202942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_XRDY) { 203942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_DXR) = addr & 0xff; 204942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 205942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 206942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 207942ba996SJean-Christophe PLAGNIOL-VILLARD } 208942ba996SJean-Christophe PLAGNIOL-VILLARD 209942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY); 210942ba996SJean-Christophe PLAGNIOL-VILLARD 211942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 212942ba996SJean-Christophe PLAGNIOL-VILLARD 213942ba996SJean-Christophe PLAGNIOL-VILLARD if (!(tmp & I2C_STAT_ARDY)) { 214942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 215942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 216942ba996SJean-Christophe PLAGNIOL-VILLARD } 217942ba996SJean-Christophe PLAGNIOL-VILLARD } 218942ba996SJean-Christophe PLAGNIOL-VILLARD } 219942ba996SJean-Christophe PLAGNIOL-VILLARD 220942ba996SJean-Christophe PLAGNIOL-VILLARD /* Address phase is over, now read 'len' bytes and stop */ 221942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP; 222942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = len & 0xffff; 223942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SA) = chip; 224942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = tmp; 225942ba996SJean-Christophe PLAGNIOL-VILLARD 226942ba996SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < len; i++) { 227942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR); 228942ba996SJean-Christophe PLAGNIOL-VILLARD 229942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 230942ba996SJean-Christophe PLAGNIOL-VILLARD 231942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_RRDY) { 232942ba996SJean-Christophe PLAGNIOL-VILLARD buf[i] = REG(I2C_DRR); 233942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 234942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 235942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 236942ba996SJean-Christophe PLAGNIOL-VILLARD } 237942ba996SJean-Christophe PLAGNIOL-VILLARD } 238942ba996SJean-Christophe PLAGNIOL-VILLARD 239942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); 240942ba996SJean-Christophe PLAGNIOL-VILLARD 241942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 242942ba996SJean-Christophe PLAGNIOL-VILLARD 243942ba996SJean-Christophe PLAGNIOL-VILLARD if (!(tmp & I2C_STAT_SCD)) { 244942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 245942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 246942ba996SJean-Christophe PLAGNIOL-VILLARD } 247942ba996SJean-Christophe PLAGNIOL-VILLARD 248942ba996SJean-Christophe PLAGNIOL-VILLARD flush_rx(); 249942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 250942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = 0; 251942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 252942ba996SJean-Christophe PLAGNIOL-VILLARD 253942ba996SJean-Christophe PLAGNIOL-VILLARD return(0); 254942ba996SJean-Christophe PLAGNIOL-VILLARD } 255942ba996SJean-Christophe PLAGNIOL-VILLARD 256942ba996SJean-Christophe PLAGNIOL-VILLARD 257942ba996SJean-Christophe PLAGNIOL-VILLARD int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) 258942ba996SJean-Christophe PLAGNIOL-VILLARD { 259942ba996SJean-Christophe PLAGNIOL-VILLARD u_int32_t tmp; 260942ba996SJean-Christophe PLAGNIOL-VILLARD int i; 261942ba996SJean-Christophe PLAGNIOL-VILLARD 262942ba996SJean-Christophe PLAGNIOL-VILLARD if ((alen < 0) || (alen > 2)) { 263942ba996SJean-Christophe PLAGNIOL-VILLARD printf("%s(): bogus address length %x\n", __FUNCTION__, alen); 264942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 265942ba996SJean-Christophe PLAGNIOL-VILLARD } 266942ba996SJean-Christophe PLAGNIOL-VILLARD if (len < 0) { 267942ba996SJean-Christophe PLAGNIOL-VILLARD printf("%s(): bogus length %x\n", __FUNCTION__, len); 268942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 269942ba996SJean-Christophe PLAGNIOL-VILLARD } 270942ba996SJean-Christophe PLAGNIOL-VILLARD 271942ba996SJean-Christophe PLAGNIOL-VILLARD if (wait_for_bus()) {return(1);} 272942ba996SJean-Christophe PLAGNIOL-VILLARD 273942ba996SJean-Christophe PLAGNIOL-VILLARD /* Start address phase */ 274942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP; 275942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen; 276942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_SA) = chip; 277942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = tmp; 278942ba996SJean-Christophe PLAGNIOL-VILLARD 279942ba996SJean-Christophe PLAGNIOL-VILLARD switch (alen) { 280942ba996SJean-Christophe PLAGNIOL-VILLARD case 2: 281942ba996SJean-Christophe PLAGNIOL-VILLARD /* Send address MSByte */ 282942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); 283942ba996SJean-Christophe PLAGNIOL-VILLARD 284942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 285942ba996SJean-Christophe PLAGNIOL-VILLARD 286942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_XRDY) { 287942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_DXR) = (addr >> 8) & 0xff; 288942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 289942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 290942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 291942ba996SJean-Christophe PLAGNIOL-VILLARD } 292942ba996SJean-Christophe PLAGNIOL-VILLARD /* No break, fall through */ 293942ba996SJean-Christophe PLAGNIOL-VILLARD case 1: 294942ba996SJean-Christophe PLAGNIOL-VILLARD /* Send address LSByte */ 295942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); 296942ba996SJean-Christophe PLAGNIOL-VILLARD 297942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 298942ba996SJean-Christophe PLAGNIOL-VILLARD 299942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_XRDY) { 300942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_DXR) = addr & 0xff; 301942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 302942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 303942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 304942ba996SJean-Christophe PLAGNIOL-VILLARD } 305942ba996SJean-Christophe PLAGNIOL-VILLARD } 306942ba996SJean-Christophe PLAGNIOL-VILLARD 307942ba996SJean-Christophe PLAGNIOL-VILLARD for (i = 0; i < len; i++) { 308942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); 309942ba996SJean-Christophe PLAGNIOL-VILLARD 310942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 311942ba996SJean-Christophe PLAGNIOL-VILLARD 312942ba996SJean-Christophe PLAGNIOL-VILLARD if (tmp & I2C_STAT_XRDY) { 313942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_DXR) = buf[i]; 314942ba996SJean-Christophe PLAGNIOL-VILLARD } else { 315942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 316942ba996SJean-Christophe PLAGNIOL-VILLARD } 317942ba996SJean-Christophe PLAGNIOL-VILLARD } 318942ba996SJean-Christophe PLAGNIOL-VILLARD 319942ba996SJean-Christophe PLAGNIOL-VILLARD tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); 320942ba996SJean-Christophe PLAGNIOL-VILLARD 321942ba996SJean-Christophe PLAGNIOL-VILLARD CHECK_NACK(); 322942ba996SJean-Christophe PLAGNIOL-VILLARD 323942ba996SJean-Christophe PLAGNIOL-VILLARD if (!(tmp & I2C_STAT_SCD)) { 324942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 325942ba996SJean-Christophe PLAGNIOL-VILLARD return(1); 326942ba996SJean-Christophe PLAGNIOL-VILLARD } 327942ba996SJean-Christophe PLAGNIOL-VILLARD 328942ba996SJean-Christophe PLAGNIOL-VILLARD flush_rx(); 329942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_STAT) = 0xffff; 330942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CNT) = 0; 331942ba996SJean-Christophe PLAGNIOL-VILLARD REG(I2C_CON) = 0; 332942ba996SJean-Christophe PLAGNIOL-VILLARD 333942ba996SJean-Christophe PLAGNIOL-VILLARD return(0); 334942ba996SJean-Christophe PLAGNIOL-VILLARD } 335