1*3cff842bSKuo-Jung Su /* 2*3cff842bSKuo-Jung Su * Faraday I2C Controller 3*3cff842bSKuo-Jung Su * 4*3cff842bSKuo-Jung Su * (C) Copyright 2010 Faraday Technology 5*3cff842bSKuo-Jung Su * Dante Su <dantesu@faraday-tech.com> 6*3cff842bSKuo-Jung Su * 7*3cff842bSKuo-Jung Su * This file is released under the terms of GPL v2 and any later version. 8*3cff842bSKuo-Jung Su * See the file COPYING in the root directory of the source tree for details. 9*3cff842bSKuo-Jung Su */ 10*3cff842bSKuo-Jung Su 11*3cff842bSKuo-Jung Su #include <common.h> 12*3cff842bSKuo-Jung Su #include <asm/io.h> 13*3cff842bSKuo-Jung Su #include <i2c.h> 14*3cff842bSKuo-Jung Su 15*3cff842bSKuo-Jung Su #include "fti2c010.h" 16*3cff842bSKuo-Jung Su 17*3cff842bSKuo-Jung Su #ifndef CONFIG_HARD_I2C 18*3cff842bSKuo-Jung Su #error "fti2c010: CONFIG_HARD_I2C is not defined" 19*3cff842bSKuo-Jung Su #endif 20*3cff842bSKuo-Jung Su 21*3cff842bSKuo-Jung Su #ifndef CONFIG_SYS_I2C_SPEED 22*3cff842bSKuo-Jung Su #define CONFIG_SYS_I2C_SPEED 50000 23*3cff842bSKuo-Jung Su #endif 24*3cff842bSKuo-Jung Su 25*3cff842bSKuo-Jung Su #ifndef CONFIG_FTI2C010_FREQ 26*3cff842bSKuo-Jung Su #define CONFIG_FTI2C010_FREQ clk_get_rate("I2C") 27*3cff842bSKuo-Jung Su #endif 28*3cff842bSKuo-Jung Su 29*3cff842bSKuo-Jung Su /* command timeout */ 30*3cff842bSKuo-Jung Su #define CFG_CMD_TIMEOUT 10 /* ms */ 31*3cff842bSKuo-Jung Su 32*3cff842bSKuo-Jung Su /* 7-bit chip address + 1-bit read/write */ 33*3cff842bSKuo-Jung Su #define I2C_RD(chip) ((((chip) << 1) & 0xff) | 1) 34*3cff842bSKuo-Jung Su #define I2C_WR(chip) (((chip) << 1) & 0xff) 35*3cff842bSKuo-Jung Su 36*3cff842bSKuo-Jung Su struct fti2c010_chip { 37*3cff842bSKuo-Jung Su void __iomem *regs; 38*3cff842bSKuo-Jung Su uint bus; 39*3cff842bSKuo-Jung Su uint speed; 40*3cff842bSKuo-Jung Su }; 41*3cff842bSKuo-Jung Su 42*3cff842bSKuo-Jung Su static struct fti2c010_chip chip_list[] = { 43*3cff842bSKuo-Jung Su { 44*3cff842bSKuo-Jung Su .bus = 0, 45*3cff842bSKuo-Jung Su .regs = (void __iomem *)CONFIG_FTI2C010_BASE, 46*3cff842bSKuo-Jung Su }, 47*3cff842bSKuo-Jung Su #ifdef CONFIG_I2C_MULTI_BUS 48*3cff842bSKuo-Jung Su # ifdef CONFIG_FTI2C010_BASE1 49*3cff842bSKuo-Jung Su { 50*3cff842bSKuo-Jung Su .bus = 1, 51*3cff842bSKuo-Jung Su .regs = (void __iomem *)CONFIG_FTI2C010_BASE1, 52*3cff842bSKuo-Jung Su }, 53*3cff842bSKuo-Jung Su # endif 54*3cff842bSKuo-Jung Su # ifdef CONFIG_FTI2C010_BASE2 55*3cff842bSKuo-Jung Su { 56*3cff842bSKuo-Jung Su .bus = 2, 57*3cff842bSKuo-Jung Su .regs = (void __iomem *)CONFIG_FTI2C010_BASE2, 58*3cff842bSKuo-Jung Su }, 59*3cff842bSKuo-Jung Su # endif 60*3cff842bSKuo-Jung Su # ifdef CONFIG_FTI2C010_BASE3 61*3cff842bSKuo-Jung Su { 62*3cff842bSKuo-Jung Su .bus = 3, 63*3cff842bSKuo-Jung Su .regs = (void __iomem *)CONFIG_FTI2C010_BASE3, 64*3cff842bSKuo-Jung Su }, 65*3cff842bSKuo-Jung Su # endif 66*3cff842bSKuo-Jung Su #endif /* #ifdef CONFIG_I2C_MULTI_BUS */ 67*3cff842bSKuo-Jung Su }; 68*3cff842bSKuo-Jung Su 69*3cff842bSKuo-Jung Su static struct fti2c010_chip *curr = chip_list; 70*3cff842bSKuo-Jung Su 71*3cff842bSKuo-Jung Su static int fti2c010_wait(uint32_t mask) 72*3cff842bSKuo-Jung Su { 73*3cff842bSKuo-Jung Su int ret = -1; 74*3cff842bSKuo-Jung Su uint32_t stat, ts; 75*3cff842bSKuo-Jung Su struct fti2c010_regs *regs = curr->regs; 76*3cff842bSKuo-Jung Su 77*3cff842bSKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 78*3cff842bSKuo-Jung Su stat = readl(®s->sr); 79*3cff842bSKuo-Jung Su if ((stat & mask) == mask) { 80*3cff842bSKuo-Jung Su ret = 0; 81*3cff842bSKuo-Jung Su break; 82*3cff842bSKuo-Jung Su } 83*3cff842bSKuo-Jung Su } 84*3cff842bSKuo-Jung Su 85*3cff842bSKuo-Jung Su return ret; 86*3cff842bSKuo-Jung Su } 87*3cff842bSKuo-Jung Su 88*3cff842bSKuo-Jung Su /* 89*3cff842bSKuo-Jung Su * u-boot I2C API 90*3cff842bSKuo-Jung Su */ 91*3cff842bSKuo-Jung Su 92*3cff842bSKuo-Jung Su /* 93*3cff842bSKuo-Jung Su * Initialization, must be called once on start up, may be called 94*3cff842bSKuo-Jung Su * repeatedly to change the speed and slave addresses. 95*3cff842bSKuo-Jung Su */ 96*3cff842bSKuo-Jung Su void i2c_init(int speed, int slaveaddr) 97*3cff842bSKuo-Jung Su { 98*3cff842bSKuo-Jung Su if (speed || !curr->speed) 99*3cff842bSKuo-Jung Su i2c_set_bus_speed(speed); 100*3cff842bSKuo-Jung Su 101*3cff842bSKuo-Jung Su /* if slave mode disabled */ 102*3cff842bSKuo-Jung Su if (!slaveaddr) 103*3cff842bSKuo-Jung Su return; 104*3cff842bSKuo-Jung Su 105*3cff842bSKuo-Jung Su /* 106*3cff842bSKuo-Jung Su * TODO: 107*3cff842bSKuo-Jung Su * Implement slave mode, but is it really necessary? 108*3cff842bSKuo-Jung Su */ 109*3cff842bSKuo-Jung Su } 110*3cff842bSKuo-Jung Su 111*3cff842bSKuo-Jung Su /* 112*3cff842bSKuo-Jung Su * Probe the given I2C chip address. Returns 0 if a chip responded, 113*3cff842bSKuo-Jung Su * not 0 on failure. 114*3cff842bSKuo-Jung Su */ 115*3cff842bSKuo-Jung Su int i2c_probe(uchar chip) 116*3cff842bSKuo-Jung Su { 117*3cff842bSKuo-Jung Su int ret; 118*3cff842bSKuo-Jung Su struct fti2c010_regs *regs = curr->regs; 119*3cff842bSKuo-Jung Su 120*3cff842bSKuo-Jung Su i2c_init(0, 0); 121*3cff842bSKuo-Jung Su 122*3cff842bSKuo-Jung Su /* 1. Select slave device (7bits Address + 1bit R/W) */ 123*3cff842bSKuo-Jung Su writel(I2C_WR(chip), ®s->dr); 124*3cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 125*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 126*3cff842bSKuo-Jung Su if (ret) 127*3cff842bSKuo-Jung Su return ret; 128*3cff842bSKuo-Jung Su 129*3cff842bSKuo-Jung Su /* 2. Select device register */ 130*3cff842bSKuo-Jung Su writel(0, ®s->dr); 131*3cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN, ®s->cr); 132*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 133*3cff842bSKuo-Jung Su 134*3cff842bSKuo-Jung Su return ret; 135*3cff842bSKuo-Jung Su } 136*3cff842bSKuo-Jung Su 137*3cff842bSKuo-Jung Su /* 138*3cff842bSKuo-Jung Su * Read/Write interface: 139*3cff842bSKuo-Jung Su * chip: I2C chip address, range 0..127 140*3cff842bSKuo-Jung Su * addr: Memory (register) address within the chip 141*3cff842bSKuo-Jung Su * alen: Number of bytes to use for addr (typically 1, 2 for larger 142*3cff842bSKuo-Jung Su * memories, 0 for register type devices with only one 143*3cff842bSKuo-Jung Su * register) 144*3cff842bSKuo-Jung Su * buffer: Where to read/write the data 145*3cff842bSKuo-Jung Su * len: How many bytes to read/write 146*3cff842bSKuo-Jung Su * 147*3cff842bSKuo-Jung Su * Returns: 0 on success, not 0 on failure 148*3cff842bSKuo-Jung Su */ 149*3cff842bSKuo-Jung Su int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) 150*3cff842bSKuo-Jung Su { 151*3cff842bSKuo-Jung Su int ret, pos; 152*3cff842bSKuo-Jung Su uchar paddr[4]; 153*3cff842bSKuo-Jung Su struct fti2c010_regs *regs = curr->regs; 154*3cff842bSKuo-Jung Su 155*3cff842bSKuo-Jung Su i2c_init(0, 0); 156*3cff842bSKuo-Jung Su 157*3cff842bSKuo-Jung Su paddr[0] = (addr >> 0) & 0xFF; 158*3cff842bSKuo-Jung Su paddr[1] = (addr >> 8) & 0xFF; 159*3cff842bSKuo-Jung Su paddr[2] = (addr >> 16) & 0xFF; 160*3cff842bSKuo-Jung Su paddr[3] = (addr >> 24) & 0xFF; 161*3cff842bSKuo-Jung Su 162*3cff842bSKuo-Jung Su /* 163*3cff842bSKuo-Jung Su * Phase A. Set register address 164*3cff842bSKuo-Jung Su */ 165*3cff842bSKuo-Jung Su 166*3cff842bSKuo-Jung Su /* A.1 Select slave device (7bits Address + 1bit R/W) */ 167*3cff842bSKuo-Jung Su writel(I2C_WR(chip), ®s->dr); 168*3cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 169*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 170*3cff842bSKuo-Jung Su if (ret) 171*3cff842bSKuo-Jung Su return ret; 172*3cff842bSKuo-Jung Su 173*3cff842bSKuo-Jung Su /* A.2 Select device register */ 174*3cff842bSKuo-Jung Su for (pos = 0; pos < alen; ++pos) { 175*3cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 176*3cff842bSKuo-Jung Su 177*3cff842bSKuo-Jung Su writel(paddr[pos], ®s->dr); 178*3cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 179*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 180*3cff842bSKuo-Jung Su if (ret) 181*3cff842bSKuo-Jung Su return ret; 182*3cff842bSKuo-Jung Su } 183*3cff842bSKuo-Jung Su 184*3cff842bSKuo-Jung Su /* 185*3cff842bSKuo-Jung Su * Phase B. Get register data 186*3cff842bSKuo-Jung Su */ 187*3cff842bSKuo-Jung Su 188*3cff842bSKuo-Jung Su /* B.1 Select slave device (7bits Address + 1bit R/W) */ 189*3cff842bSKuo-Jung Su writel(I2C_RD(chip), ®s->dr); 190*3cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 191*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 192*3cff842bSKuo-Jung Su if (ret) 193*3cff842bSKuo-Jung Su return ret; 194*3cff842bSKuo-Jung Su 195*3cff842bSKuo-Jung Su /* B.2 Get register data */ 196*3cff842bSKuo-Jung Su for (pos = 0; pos < len; ++pos) { 197*3cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 198*3cff842bSKuo-Jung Su uint32_t stat = SR_DR; 199*3cff842bSKuo-Jung Su 200*3cff842bSKuo-Jung Su if (pos == len - 1) { 201*3cff842bSKuo-Jung Su ctrl |= CR_NAK | CR_STOP; 202*3cff842bSKuo-Jung Su stat |= SR_ACK; 203*3cff842bSKuo-Jung Su } 204*3cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 205*3cff842bSKuo-Jung Su ret = fti2c010_wait(stat); 206*3cff842bSKuo-Jung Su if (ret) 207*3cff842bSKuo-Jung Su break; 208*3cff842bSKuo-Jung Su buf[pos] = (uchar)(readl(®s->dr) & 0xFF); 209*3cff842bSKuo-Jung Su } 210*3cff842bSKuo-Jung Su 211*3cff842bSKuo-Jung Su return ret; 212*3cff842bSKuo-Jung Su } 213*3cff842bSKuo-Jung Su 214*3cff842bSKuo-Jung Su /* 215*3cff842bSKuo-Jung Su * Read/Write interface: 216*3cff842bSKuo-Jung Su * chip: I2C chip address, range 0..127 217*3cff842bSKuo-Jung Su * addr: Memory (register) address within the chip 218*3cff842bSKuo-Jung Su * alen: Number of bytes to use for addr (typically 1, 2 for larger 219*3cff842bSKuo-Jung Su * memories, 0 for register type devices with only one 220*3cff842bSKuo-Jung Su * register) 221*3cff842bSKuo-Jung Su * buffer: Where to read/write the data 222*3cff842bSKuo-Jung Su * len: How many bytes to read/write 223*3cff842bSKuo-Jung Su * 224*3cff842bSKuo-Jung Su * Returns: 0 on success, not 0 on failure 225*3cff842bSKuo-Jung Su */ 226*3cff842bSKuo-Jung Su int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) 227*3cff842bSKuo-Jung Su { 228*3cff842bSKuo-Jung Su int ret, pos; 229*3cff842bSKuo-Jung Su uchar paddr[4]; 230*3cff842bSKuo-Jung Su struct fti2c010_regs *regs = curr->regs; 231*3cff842bSKuo-Jung Su 232*3cff842bSKuo-Jung Su i2c_init(0, 0); 233*3cff842bSKuo-Jung Su 234*3cff842bSKuo-Jung Su paddr[0] = (addr >> 0) & 0xFF; 235*3cff842bSKuo-Jung Su paddr[1] = (addr >> 8) & 0xFF; 236*3cff842bSKuo-Jung Su paddr[2] = (addr >> 16) & 0xFF; 237*3cff842bSKuo-Jung Su paddr[3] = (addr >> 24) & 0xFF; 238*3cff842bSKuo-Jung Su 239*3cff842bSKuo-Jung Su /* 240*3cff842bSKuo-Jung Su * Phase A. Set register address 241*3cff842bSKuo-Jung Su * 242*3cff842bSKuo-Jung Su * A.1 Select slave device (7bits Address + 1bit R/W) 243*3cff842bSKuo-Jung Su */ 244*3cff842bSKuo-Jung Su writel(I2C_WR(chip), ®s->dr); 245*3cff842bSKuo-Jung Su writel(CR_ENABLE | CR_TBEN | CR_START, ®s->cr); 246*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 247*3cff842bSKuo-Jung Su if (ret) 248*3cff842bSKuo-Jung Su return ret; 249*3cff842bSKuo-Jung Su 250*3cff842bSKuo-Jung Su /* A.2 Select device register */ 251*3cff842bSKuo-Jung Su for (pos = 0; pos < alen; ++pos) { 252*3cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 253*3cff842bSKuo-Jung Su 254*3cff842bSKuo-Jung Su writel(paddr[pos], ®s->dr); 255*3cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 256*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 257*3cff842bSKuo-Jung Su if (ret) 258*3cff842bSKuo-Jung Su return ret; 259*3cff842bSKuo-Jung Su } 260*3cff842bSKuo-Jung Su 261*3cff842bSKuo-Jung Su /* 262*3cff842bSKuo-Jung Su * Phase B. Set register data 263*3cff842bSKuo-Jung Su */ 264*3cff842bSKuo-Jung Su for (pos = 0; pos < len; ++pos) { 265*3cff842bSKuo-Jung Su uint32_t ctrl = CR_ENABLE | CR_TBEN; 266*3cff842bSKuo-Jung Su 267*3cff842bSKuo-Jung Su if (pos == len - 1) 268*3cff842bSKuo-Jung Su ctrl |= CR_STOP; 269*3cff842bSKuo-Jung Su writel(buf[pos], ®s->dr); 270*3cff842bSKuo-Jung Su writel(ctrl, ®s->cr); 271*3cff842bSKuo-Jung Su ret = fti2c010_wait(SR_DT); 272*3cff842bSKuo-Jung Su if (ret) 273*3cff842bSKuo-Jung Su break; 274*3cff842bSKuo-Jung Su } 275*3cff842bSKuo-Jung Su 276*3cff842bSKuo-Jung Su return ret; 277*3cff842bSKuo-Jung Su } 278*3cff842bSKuo-Jung Su 279*3cff842bSKuo-Jung Su /* 280*3cff842bSKuo-Jung Su * Functions for setting the current I2C bus and its speed 281*3cff842bSKuo-Jung Su */ 282*3cff842bSKuo-Jung Su #ifdef CONFIG_I2C_MULTI_BUS 283*3cff842bSKuo-Jung Su 284*3cff842bSKuo-Jung Su /* 285*3cff842bSKuo-Jung Su * i2c_set_bus_num: 286*3cff842bSKuo-Jung Su * 287*3cff842bSKuo-Jung Su * Change the active I2C bus. Subsequent read/write calls will 288*3cff842bSKuo-Jung Su * go to this one. 289*3cff842bSKuo-Jung Su * 290*3cff842bSKuo-Jung Su * bus - bus index, zero based 291*3cff842bSKuo-Jung Su * 292*3cff842bSKuo-Jung Su * Returns: 0 on success, not 0 on failure 293*3cff842bSKuo-Jung Su */ 294*3cff842bSKuo-Jung Su int i2c_set_bus_num(uint bus) 295*3cff842bSKuo-Jung Su { 296*3cff842bSKuo-Jung Su if (bus >= ARRAY_SIZE(chip_list)) 297*3cff842bSKuo-Jung Su return -1; 298*3cff842bSKuo-Jung Su curr = chip_list + bus; 299*3cff842bSKuo-Jung Su i2c_init(0, 0); 300*3cff842bSKuo-Jung Su return 0; 301*3cff842bSKuo-Jung Su } 302*3cff842bSKuo-Jung Su 303*3cff842bSKuo-Jung Su /* 304*3cff842bSKuo-Jung Su * i2c_get_bus_num: 305*3cff842bSKuo-Jung Su * 306*3cff842bSKuo-Jung Su * Returns index of currently active I2C bus. Zero-based. 307*3cff842bSKuo-Jung Su */ 308*3cff842bSKuo-Jung Su 309*3cff842bSKuo-Jung Su uint i2c_get_bus_num(void) 310*3cff842bSKuo-Jung Su { 311*3cff842bSKuo-Jung Su return curr->bus; 312*3cff842bSKuo-Jung Su } 313*3cff842bSKuo-Jung Su 314*3cff842bSKuo-Jung Su #endif /* #ifdef CONFIG_I2C_MULTI_BUS */ 315*3cff842bSKuo-Jung Su 316*3cff842bSKuo-Jung Su /* 317*3cff842bSKuo-Jung Su * i2c_set_bus_speed: 318*3cff842bSKuo-Jung Su * 319*3cff842bSKuo-Jung Su * Change the speed of the active I2C bus 320*3cff842bSKuo-Jung Su * 321*3cff842bSKuo-Jung Su * speed - bus speed in Hz 322*3cff842bSKuo-Jung Su * 323*3cff842bSKuo-Jung Su * Returns: 0 on success, not 0 on failure 324*3cff842bSKuo-Jung Su */ 325*3cff842bSKuo-Jung Su int i2c_set_bus_speed(uint speed) 326*3cff842bSKuo-Jung Su { 327*3cff842bSKuo-Jung Su struct fti2c010_regs *regs = curr->regs; 328*3cff842bSKuo-Jung Su uint clk = CONFIG_FTI2C010_FREQ; 329*3cff842bSKuo-Jung Su uint gsr = 0, tsr = 32; 330*3cff842bSKuo-Jung Su uint spd, div; 331*3cff842bSKuo-Jung Su 332*3cff842bSKuo-Jung Su if (!speed) 333*3cff842bSKuo-Jung Su speed = CONFIG_SYS_I2C_SPEED; 334*3cff842bSKuo-Jung Su 335*3cff842bSKuo-Jung Su for (div = 0; div < 0x3ffff; ++div) { 336*3cff842bSKuo-Jung Su /* SCLout = PCLK/(2*(COUNT + 2) + GSR) */ 337*3cff842bSKuo-Jung Su spd = clk / (2 * (div + 2) + gsr); 338*3cff842bSKuo-Jung Su if (spd <= speed) 339*3cff842bSKuo-Jung Su break; 340*3cff842bSKuo-Jung Su } 341*3cff842bSKuo-Jung Su 342*3cff842bSKuo-Jung Su if (curr->speed == spd) 343*3cff842bSKuo-Jung Su return 0; 344*3cff842bSKuo-Jung Su 345*3cff842bSKuo-Jung Su writel(CR_I2CRST, ®s->cr); 346*3cff842bSKuo-Jung Su mdelay(100); 347*3cff842bSKuo-Jung Su if (readl(®s->cr) & CR_I2CRST) { 348*3cff842bSKuo-Jung Su printf("fti2c010: reset timeout\n"); 349*3cff842bSKuo-Jung Su return -1; 350*3cff842bSKuo-Jung Su } 351*3cff842bSKuo-Jung Su 352*3cff842bSKuo-Jung Su curr->speed = spd; 353*3cff842bSKuo-Jung Su 354*3cff842bSKuo-Jung Su writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), ®s->tgsr); 355*3cff842bSKuo-Jung Su writel(CDR_DIV(div), ®s->cdr); 356*3cff842bSKuo-Jung Su 357*3cff842bSKuo-Jung Su return 0; 358*3cff842bSKuo-Jung Su } 359*3cff842bSKuo-Jung Su 360*3cff842bSKuo-Jung Su /* 361*3cff842bSKuo-Jung Su * i2c_get_bus_speed: 362*3cff842bSKuo-Jung Su * 363*3cff842bSKuo-Jung Su * Returns speed of currently active I2C bus in Hz 364*3cff842bSKuo-Jung Su */ 365*3cff842bSKuo-Jung Su 366*3cff842bSKuo-Jung Su uint i2c_get_bus_speed(void) 367*3cff842bSKuo-Jung Su { 368*3cff842bSKuo-Jung Su return curr->speed; 369*3cff842bSKuo-Jung Su } 370