diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/Makefile | 4 | ||||
-rw-r--r-- | drivers/i2c/designware_i2c.c | 293 | ||||
-rw-r--r-- | drivers/i2c/mxs_i2c.c | 187 | ||||
-rw-r--r-- | drivers/spi/altera_spi.c | 132 | ||||
-rw-r--r-- | drivers/spi/mxc_spi.c | 40 |
5 files changed, 328 insertions, 328 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 416ea4f2c8..d067897244 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -6,21 +6,21 @@ # obj-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o -obj-$(CONFIG_DW_I2C) += designware_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o -obj-$(CONFIG_I2C_MXS) += mxs_i2c.o obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o +obj-$(CONFIG_SYS_I2C_DW) += designware_i2c.o obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o +obj-$(CONFIG_SYS_I2C_MXS) += mxs_i2c.o obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_OMAP34XX) += omap24xx_i2c.o obj-$(CONFIG_SYS_I2C_PPC4XX) += ppc4xx_i2c.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index e085a7095e..e768cdedb0 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -6,17 +6,33 @@ */ #include <common.h> +#include <i2c.h> #include <asm/io.h> #include "designware_i2c.h" -#include <i2c.h> -#ifdef CONFIG_I2C_MULTI_BUS -static unsigned int bus_initialized[CONFIG_SYS_I2C_BUS_MAX]; -static unsigned int current_bus = 0; +static struct i2c_regs *i2c_get_base(struct i2c_adapter *adap) +{ + switch (adap->hwadapnr) { +#if CONFIG_SYS_I2C_BUS_MAX >= 4 + case 3: + return (struct i2c_regs *)CONFIG_SYS_I2C_BASE3; +#endif +#if CONFIG_SYS_I2C_BUS_MAX >= 3 + case 2: + return (struct i2c_regs *)CONFIG_SYS_I2C_BASE2; +#endif +#if CONFIG_SYS_I2C_BUS_MAX >= 2 + case 1: + return (struct i2c_regs *)CONFIG_SYS_I2C_BASE1; #endif + case 0: + return (struct i2c_regs *)CONFIG_SYS_I2C_BASE; + default: + printf("Wrong I2C-adapter number %d\n", adap->hwadapnr); + } -static struct i2c_regs *i2c_regs_p = - (struct i2c_regs *)CONFIG_SYS_I2C_BASE; + return NULL; +} /* * set_speed - Set the i2c speed mode (standard, high, fast) @@ -24,51 +40,52 @@ static struct i2c_regs *i2c_regs_p = * * Set the i2c speed mode (standard, high, fast) */ -static void set_speed(int i2c_spd) +static void set_speed(struct i2c_adapter *adap, int i2c_spd) { + struct i2c_regs *i2c_base = i2c_get_base(adap); unsigned int cntl; unsigned int hcnt, lcnt; unsigned int enbl; /* to set speed cltr must be disabled */ - enbl = readl(&i2c_regs_p->ic_enable); + enbl = readl(&i2c_base->ic_enable); enbl &= ~IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); + writel(enbl, &i2c_base->ic_enable); - cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); + cntl = (readl(&i2c_base->ic_con) & (~IC_CON_SPD_MSK)); switch (i2c_spd) { case IC_SPEED_MODE_MAX: cntl |= IC_CON_SPD_HS; hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; - writel(hcnt, &i2c_regs_p->ic_hs_scl_hcnt); + writel(hcnt, &i2c_base->ic_hs_scl_hcnt); lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; - writel(lcnt, &i2c_regs_p->ic_hs_scl_lcnt); + writel(lcnt, &i2c_base->ic_hs_scl_lcnt); break; case IC_SPEED_MODE_STANDARD: cntl |= IC_CON_SPD_SS; hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; - writel(hcnt, &i2c_regs_p->ic_ss_scl_hcnt); + writel(hcnt, &i2c_base->ic_ss_scl_hcnt); lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; - writel(lcnt, &i2c_regs_p->ic_ss_scl_lcnt); + writel(lcnt, &i2c_base->ic_ss_scl_lcnt); break; case IC_SPEED_MODE_FAST: default: cntl |= IC_CON_SPD_FS; hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; - writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); + writel(hcnt, &i2c_base->ic_fs_scl_hcnt); lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; - writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); + writel(lcnt, &i2c_base->ic_fs_scl_lcnt); break; } - writel(cntl, &i2c_regs_p->ic_con); + writel(cntl, &i2c_base->ic_con); /* Enable back i2c now speed set */ enbl |= IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); + writel(enbl, &i2c_base->ic_enable); } /* @@ -77,7 +94,8 @@ static void set_speed(int i2c_spd) * * Set the i2c speed. */ -int i2c_set_bus_speed(unsigned int speed) +static unsigned int dw_i2c_set_bus_speed(struct i2c_adapter *adap, + unsigned int speed) { int i2c_spd; @@ -88,28 +106,8 @@ int i2c_set_bus_speed(unsigned int speed) else i2c_spd = IC_SPEED_MODE_STANDARD; - set_speed(i2c_spd); - - return i2c_spd; -} - -/* - * i2c_get_bus_speed - Gets the i2c speed - * - * Gets the i2c speed. - */ -unsigned int i2c_get_bus_speed(void) -{ - u32 cntl; - - cntl = (readl(&i2c_regs_p->ic_con) & IC_CON_SPD_MSK); - - if (cntl == IC_CON_SPD_HS) - return I2C_MAX_SPEED; - else if (cntl == IC_CON_SPD_FS) - return I2C_FAST_SPEED; - else if (cntl == IC_CON_SPD_SS) - return I2C_STANDARD_SPEED; + set_speed(adap, i2c_spd); + adap->speed = speed; return 0; } @@ -117,34 +115,32 @@ unsigned int i2c_get_bus_speed(void) /* * i2c_init - Init function * @speed: required i2c speed - * @slaveadd: slave address for the device + * @slaveaddr: slave address for the device * * Initialization function. */ -void i2c_init(int speed, int slaveadd) +static void dw_i2c_init(struct i2c_adapter *adap, int speed, + int slaveaddr) { + struct i2c_regs *i2c_base = i2c_get_base(adap); unsigned int enbl; /* Disable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); + enbl = readl(&i2c_base->ic_enable); enbl &= ~IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); + writel(enbl, &i2c_base->ic_enable); - writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_regs_p->ic_con); - writel(IC_RX_TL, &i2c_regs_p->ic_rx_tl); - writel(IC_TX_TL, &i2c_regs_p->ic_tx_tl); - i2c_set_bus_speed(speed); - writel(IC_STOP_DET, &i2c_regs_p->ic_intr_mask); - writel(slaveadd, &i2c_regs_p->ic_sar); + writel((IC_CON_SD | IC_CON_SPD_FS | IC_CON_MM), &i2c_base->ic_con); + writel(IC_RX_TL, &i2c_base->ic_rx_tl); + writel(IC_TX_TL, &i2c_base->ic_tx_tl); + dw_i2c_set_bus_speed(adap, speed); + writel(IC_STOP_DET, &i2c_base->ic_intr_mask); + writel(slaveaddr, &i2c_base->ic_sar); /* Enable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); + enbl = readl(&i2c_base->ic_enable); enbl |= IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); - -#ifdef CONFIG_I2C_MULTI_BUS - bus_initialized[current_bus] = 1; -#endif + writel(enbl, &i2c_base->ic_enable); } /* @@ -153,21 +149,22 @@ void i2c_init(int speed, int slaveadd) * * Sets the target slave address. */ -static void i2c_setaddress(unsigned int i2c_addr) +static void i2c_setaddress(struct i2c_adapter *adap, unsigned int i2c_addr) { + struct i2c_regs *i2c_base = i2c_get_base(adap); unsigned int enbl; /* Disable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); + enbl = readl(&i2c_base->ic_enable); enbl &= ~IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); + writel(enbl, &i2c_base->ic_enable); - writel(i2c_addr, &i2c_regs_p->ic_tar); + writel(i2c_addr, &i2c_base->ic_tar); /* Enable i2c */ - enbl = readl(&i2c_regs_p->ic_enable); + enbl = readl(&i2c_base->ic_enable); enbl |= IC_ENABLE_0B; - writel(enbl, &i2c_regs_p->ic_enable); + writel(enbl, &i2c_base->ic_enable); } /* @@ -175,10 +172,12 @@ static void i2c_setaddress(unsigned int i2c_addr) * * Flushes the i2c RX FIFO */ -static void i2c_flush_rxfifo(void) +static void i2c_flush_rxfifo(struct i2c_adapter *adap) { - while (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) - readl(&i2c_regs_p->ic_cmd_data); + struct i2c_regs *i2c_base = i2c_get_base(adap); + + while (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) + readl(&i2c_base->ic_cmd_data); } /* @@ -186,12 +185,13 @@ static void i2c_flush_rxfifo(void) * * Waits for bus busy */ -static int i2c_wait_for_bb(void) +static int i2c_wait_for_bb(struct i2c_adapter *adap) { + struct i2c_regs *i2c_base = i2c_get_base(adap); unsigned long start_time_bb = get_timer(0); - while ((readl(&i2c_regs_p->ic_status) & IC_STATUS_MA) || - !(readl(&i2c_regs_p->ic_status) & IC_STATUS_TFE)) { + while ((readl(&i2c_base->ic_status) & IC_STATUS_MA) || + !(readl(&i2c_base->ic_status) & IC_STATUS_TFE)) { /* Evaluate timeout */ if (get_timer(start_time_bb) > (unsigned long)(I2C_BYTE_TO_BB)) @@ -201,40 +201,44 @@ static int i2c_wait_for_bb(void) return 0; } -static int i2c_xfer_init(uchar chip, uint addr, int alen) +static int i2c_xfer_init(struct i2c_adapter *adap, uchar chip, uint addr, + int alen) { - if (i2c_wait_for_bb()) + struct i2c_regs *i2c_base = i2c_get_base(adap); + + if (i2c_wait_for_bb(adap)) return 1; - i2c_setaddress(chip); + i2c_setaddress(adap, chip); while (alen) { alen--; /* high byte address going out first */ writel((addr >> (alen * 8)) & 0xff, - &i2c_regs_p->ic_cmd_data); + &i2c_base->ic_cmd_data); } return 0; } -static int i2c_xfer_finish(void) +static int i2c_xfer_finish(struct i2c_adapter *adap) { + struct i2c_regs *i2c_base = i2c_get_base(adap); ulong start_stop_det = get_timer(0); while (1) { - if ((readl(&i2c_regs_p->ic_raw_intr_stat) & IC_STOP_DET)) { - readl(&i2c_regs_p->ic_clr_stop_det); + if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) { + readl(&i2c_base->ic_clr_stop_det); break; } else if (get_timer(start_stop_det) > I2C_STOPDET_TO) { break; } } - if (i2c_wait_for_bb()) { + if (i2c_wait_for_bb(adap)) { printf("Timed out waiting for bus\n"); return 1; } - i2c_flush_rxfifo(); + i2c_flush_rxfifo(adap); return 0; } @@ -249,8 +253,10 @@ static int i2c_xfer_finish(void) * * Read from i2c memory. */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int dw_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, + int alen, u8 *buffer, int len) { + struct i2c_regs *i2c_base = i2c_get_base(adap); unsigned long start_time_rx; #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW @@ -265,25 +271,25 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) * still be one byte because the extra address bits are * hidden in the chip address. */ - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); + dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8)); - debug("%s: fix addr_overflow: chip %02x addr %02x\n", __func__, chip, + debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev, addr); #endif - if (i2c_xfer_init(chip, addr, alen)) + if (i2c_xfer_init(adap, dev, addr, alen)) return 1; start_time_rx = get_timer(0); while (len) { if (len == 1) - writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data); + writel(IC_CMD | IC_STOP, &i2c_base->ic_cmd_data); else - writel(IC_CMD, &i2c_regs_p->ic_cmd_data); + writel(IC_CMD, &i2c_base->ic_cmd_data); - if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) { - *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); + if (readl(&i2c_base->ic_status) & IC_STATUS_RFNE) { + *buffer++ = (uchar)readl(&i2c_base->ic_cmd_data); len--; start_time_rx = get_timer(0); @@ -292,7 +298,7 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) } } - return i2c_xfer_finish(); + return i2c_xfer_finish(adap); } /* @@ -305,8 +311,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) * * Write to i2c memory. */ -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int dw_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, + int alen, u8 *buffer, int len) { + struct i2c_regs *i2c_base = i2c_get_base(adap); int nb = len; unsigned long start_time_tx; @@ -322,23 +330,25 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) * still be one byte because the extra address bits are * hidden in the chip address. */ - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); + dev |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); addr &= ~(CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW << (alen * 8)); - debug("%s: fix addr_overflow: chip %02x addr %02x\n", __func__, chip, + debug("%s: fix addr_overflow: dev %02x addr %02x\n", __func__, dev, addr); #endif - if (i2c_xfer_init(chip, addr, alen)) + if (i2c_xfer_init(adap, dev, addr, alen)) return 1; start_time_tx = get_timer(0); while (len) { - if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { - if (--len == 0) - writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data); - else - writel(*buffer, &i2c_regs_p->ic_cmd_data); + if (readl(&i2c_base->ic_status) & IC_STATUS_TFNF) { + if (--len == 0) { + writel(*buffer | IC_STOP, + &i2c_base->ic_cmd_data); + } else { + writel(*buffer, &i2c_base->ic_cmd_data); + } buffer++; start_time_tx = get_timer(0); @@ -348,13 +358,13 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) } } - return i2c_xfer_finish(); + return i2c_xfer_finish(adap); } /* * i2c_probe - Probe the i2c chip */ -int i2c_probe(uchar chip) +static int dw_i2c_probe(struct i2c_adapter *adap, u8 dev) { u32 tmp; int ret; @@ -362,80 +372,31 @@ int i2c_probe(uchar chip) /* * Try to read the first location of the chip. */ - ret = i2c_read(chip, 0, 1, (uchar *)&tmp, 1); + ret = dw_i2c_read(adap, dev, 0, 1, (uchar *)&tmp, 1); if (ret) - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + dw_i2c_init(adap, adap->speed, adap->slaveaddr); return ret; } -#ifdef CONFIG_I2C_MULTI_BUS -int i2c_set_bus_num(unsigned int bus) -{ - switch (bus) { - case 0: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE; - break; -#ifdef CONFIG_SYS_I2C_BASE1 - case 1: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE1; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE2 - case 2: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE2; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE3 - case 3: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE3; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE4 - case 4: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE4; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE5 - case 5: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE5; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE6 - case 6: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE6; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE7 - case 7: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE7; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE8 - case 8: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE8; - break; -#endif -#ifdef CONFIG_SYS_I2C_BASE9 - case 9: - i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE9; - break; -#endif - default: - printf("Bad bus: %d\n", bus); - return -1; - } - - current_bus = bus; +U_BOOT_I2C_ADAP_COMPLETE(dw_0, dw_i2c_init, dw_i2c_probe, dw_i2c_read, + dw_i2c_write, dw_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0) - if (!bus_initialized[current_bus]) - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); +#if CONFIG_SYS_I2C_BUS_MAX >= 2 +U_BOOT_I2C_ADAP_COMPLETE(dw_1, dw_i2c_init, dw_i2c_probe, dw_i2c_read, + dw_i2c_write, dw_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED1, CONFIG_SYS_I2C_SLAVE1, 1) +#endif - return 0; -} +#if CONFIG_SYS_I2C_BUS_MAX >= 3 +U_BOOT_I2C_ADAP_COMPLETE(dw_2, dw_i2c_init, dw_i2c_probe, dw_i2c_read, + dw_i2c_write, dw_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED2, CONFIG_SYS_I2C_SLAVE2, 2) +#endif -unsigned int i2c_get_bus_num(void) -{ - return current_bus; -} +#if CONFIG_SYS_I2C_BUS_MAX >= 4 +U_BOOT_I2C_ADAP_COMPLETE(dw_3, dw_i2c_init, dw_i2c_probe, dw_i2c_read, + dw_i2c_write, dw_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED3, CONFIG_SYS_I2C_SLAVE3, 3) #endif diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index de3b19402b..87e05c7125 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -24,11 +24,74 @@ #define MXS_I2C_MAX_TIMEOUT 1000000 -static void mxs_i2c_reset(void) +static struct mxs_i2c_regs *mxs_i2c_get_base(struct i2c_adapter *adap) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + if (adap->hwadapnr == 0) + return (struct mxs_i2c_regs *)MXS_I2C0_BASE; + else + return (struct mxs_i2c_regs *)MXS_I2C1_BASE; +} + +static unsigned int mxs_i2c_get_bus_speed(struct i2c_adapter *adap) +{ + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); + uint32_t timing0; + + timing0 = readl(&i2c_regs->hw_i2c_timing0); + /* + * This is a reverse version of the algorithm presented in + * i2c_set_bus_speed(). Please refer there for details. + */ + return clk / ((((timing0 >> 16) - 3) * 2) + 38); +} + +static uint mxs_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed) +{ + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); + /* + * The timing derivation algorithm. There is no documentation for this + * algorithm available, it was derived by using the scope and fiddling + * with constants until the result observed on the scope was good enough + * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be + * possible to assume the algorithm works for other frequencies as well. + * + * Note it was necessary to cap the frequency on both ends as it's not + * possible to configure completely arbitrary frequency for the I2C bus + * clock. + */ + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); + uint32_t base = ((clk / speed) - 38) / 2; + uint16_t high_count = base + 3; + uint16_t low_count = base - 3; + uint16_t rcv_count = (high_count * 3) / 4; + uint16_t xmit_count = low_count / 4; + + if (speed > 540000) { + printf("MXS I2C: Speed too high (%d Hz)\n", speed); + return -EINVAL; + } + + if (speed < 12000) { + printf("MXS I2C: Speed too low (%d Hz)\n", speed); + return -EINVAL; + } + + writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0); + writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1); + + writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) | + (0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET), + &i2c_regs->hw_i2c_timing2); + + return 0; +} + +static void mxs_i2c_reset(struct i2c_adapter *adap) +{ + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); int ret; - int speed = i2c_get_bus_speed(); + int speed = mxs_i2c_get_bus_speed(adap); ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg); if (ret) { @@ -43,12 +106,12 @@ static void mxs_i2c_reset(void) writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set); - i2c_set_bus_speed(speed); + mxs_i2c_set_bus_speed(adap, speed); } -static void mxs_i2c_setup_read(uint8_t chip, int len) +static void mxs_i2c_setup_read(struct i2c_adapter *adap, uint8_t chip, int len) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); writel(I2C_QUEUECMD_RETAIN_CLOCK | I2C_QUEUECMD_PRE_SEND_START | I2C_QUEUECMD_MASTER_MODE | I2C_QUEUECMD_DIRECTION | @@ -64,10 +127,10 @@ static void mxs_i2c_setup_read(uint8_t chip, int len) writel(I2C_QUEUECTRL_QUEUE_RUN, &i2c_regs->hw_i2c_queuectrl_set); } -static int mxs_i2c_write(uchar chip, uint addr, int alen, - uchar *buf, int blen, int stop) +static int mxs_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, + int alen, uchar *buf, int blen, int stop) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); uint32_t data, tmp; int i, remain, off; int timeout = MXS_I2C_MAX_TIMEOUT; @@ -122,9 +185,9 @@ static int mxs_i2c_write(uchar chip, uint addr, int alen, return 0; } -static int mxs_i2c_wait_for_ack(void) +static int mxs_i2c_wait_for_ack(struct i2c_adapter *adap) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); uint32_t tmp; int timeout = MXS_I2C_MAX_TIMEOUT; @@ -156,32 +219,34 @@ static int mxs_i2c_wait_for_ack(void) return 0; err: - mxs_i2c_reset(); + mxs_i2c_reset(adap); return 1; } -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int mxs_i2c_if_read(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, + int len) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + struct mxs_i2c_regs *i2c_regs = mxs_i2c_get_base(adap); uint32_t tmp = 0; int timeout = MXS_I2C_MAX_TIMEOUT; int ret; int i; - ret = mxs_i2c_write(chip, addr, alen, NULL, 0, 0); + ret = mxs_i2c_write(adap, chip, addr, alen, NULL, 0, 0); if (ret) { debug("MXS I2C: Failed writing address\n"); return ret; } - ret = mxs_i2c_wait_for_ack(); + ret = mxs_i2c_wait_for_ack(adap); if (ret) { debug("MXS I2C: Failed writing address\n"); return ret; } - mxs_i2c_setup_read(chip, len); - ret = mxs_i2c_wait_for_ack(); + mxs_i2c_setup_read(adap, chip, len); + ret = mxs_i2c_wait_for_ack(adap); if (ret) { debug("MXS I2C: Failed reading address\n"); return ret; @@ -209,91 +274,47 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) return 0; } -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) +static int mxs_i2c_if_write(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, + int len) { int ret; - ret = mxs_i2c_write(chip, addr, alen, buffer, len, 1); + ret = mxs_i2c_write(adap, chip, addr, alen, buffer, len, 1); if (ret) { debug("MXS I2C: Failed writing address\n"); return ret; } - ret = mxs_i2c_wait_for_ack(); + ret = mxs_i2c_wait_for_ack(adap); if (ret) debug("MXS I2C: Failed writing address\n"); return ret; } -int i2c_probe(uchar chip) +static int mxs_i2c_probe(struct i2c_adapter *adap, uint8_t chip) { int ret; - ret = mxs_i2c_write(chip, 0, 1, NULL, 0, 1); + ret = mxs_i2c_write(adap, chip, 0, 1, NULL, 0, 1); if (!ret) - ret = mxs_i2c_wait_for_ack(); - mxs_i2c_reset(); + ret = mxs_i2c_wait_for_ack(adap); + mxs_i2c_reset(adap); return ret; } -int i2c_set_bus_speed(unsigned int speed) +static void mxs_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) { - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; - /* - * The timing derivation algorithm. There is no documentation for this - * algorithm available, it was derived by using the scope and fiddling - * with constants until the result observed on the scope was good enough - * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be - * possible to assume the algorithm works for other frequencies as well. - * - * Note it was necessary to cap the frequency on both ends as it's not - * possible to configure completely arbitrary frequency for the I2C bus - * clock. - */ - uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); - uint32_t base = ((clk / speed) - 38) / 2; - uint16_t high_count = base + 3; - uint16_t low_count = base - 3; - uint16_t rcv_count = (high_count * 3) / 4; - uint16_t xmit_count = low_count / 4; - - if (speed > 540000) { - printf("MXS I2C: Speed too high (%d Hz)\n", speed); - return -EINVAL; - } - - if (speed < 12000) { - printf("MXS I2C: Speed too low (%d Hz)\n", speed); - return -EINVAL; - } - - writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0); - writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1); - - writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) | - (0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET), - &i2c_regs->hw_i2c_timing2); - - return 0; -} - -unsigned int i2c_get_bus_speed(void) -{ - struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; - uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); - uint32_t timing0; - - timing0 = readl(&i2c_regs->hw_i2c_timing0); - /* - * This is a reverse version of the algorithm presented in - * i2c_set_bus_speed(). Please refer there for details. - */ - return clk / ((((timing0 >> 16) - 3) * 2) + 38); -} - -void i2c_init(int speed, int slaveadd) -{ - mxs_i2c_reset(); - i2c_set_bus_speed(speed); + mxs_i2c_reset(adap); + mxs_i2c_set_bus_speed(adap, speed); return; } + +U_BOOT_I2C_ADAP_COMPLETE(mxs0, mxs_i2c_init, mxs_i2c_probe, + mxs_i2c_if_read, mxs_i2c_if_write, + mxs_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED, 0, 0) +U_BOOT_I2C_ADAP_COMPLETE(mxs1, mxs_i2c_init, mxs_i2c_probe, + mxs_i2c_if_read, mxs_i2c_if_write, + mxs_i2c_set_bus_speed, + CONFIG_SYS_I2C_SPEED, 0, 1) diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c index 5accbb5c22..a4d03d97cf 100644 --- a/drivers/spi/altera_spi.c +++ b/drivers/spi/altera_spi.c @@ -12,58 +12,62 @@ #include <malloc.h> #include <spi.h> -#define ALTERA_SPI_RXDATA 0 -#define ALTERA_SPI_TXDATA 4 -#define ALTERA_SPI_STATUS 8 -#define ALTERA_SPI_CONTROL 12 -#define ALTERA_SPI_SLAVE_SEL 20 - -#define ALTERA_SPI_STATUS_ROE_MSK (0x8) -#define ALTERA_SPI_STATUS_TOE_MSK (0x10) -#define ALTERA_SPI_STATUS_TMT_MSK (0x20) -#define ALTERA_SPI_STATUS_TRDY_MSK (0x40) -#define ALTERA_SPI_STATUS_RRDY_MSK (0x80) -#define ALTERA_SPI_STATUS_E_MSK (0x100) - -#define ALTERA_SPI_CONTROL_IROE_MSK (0x8) -#define ALTERA_SPI_CONTROL_ITOE_MSK (0x10) -#define ALTERA_SPI_CONTROL_ITRDY_MSK (0x40) -#define ALTERA_SPI_CONTROL_IRRDY_MSK (0x80) -#define ALTERA_SPI_CONTROL_IE_MSK (0x100) -#define ALTERA_SPI_CONTROL_SSO_MSK (0x400) +#ifndef CONFIG_ALTERA_SPI_IDLE_VAL +#define CONFIG_ALTERA_SPI_IDLE_VAL 0xff +#endif #ifndef CONFIG_SYS_ALTERA_SPI_LIST #define CONFIG_SYS_ALTERA_SPI_LIST { CONFIG_SYS_SPI_BASE } #endif +struct altera_spi_regs { + u32 rxdata; + u32 txdata; + u32 status; + u32 control; + u32 _reserved; + u32 slave_sel; +}; + +#define ALTERA_SPI_STATUS_ROE_MSK (1 << 3) +#define ALTERA_SPI_STATUS_TOE_MSK (1 << 4) +#define ALTERA_SPI_STATUS_TMT_MSK (1 << 5) +#define ALTERA_SPI_STATUS_TRDY_MSK (1 << 6) +#define ALTERA_SPI_STATUS_RRDY_MSK (1 << 7) +#define ALTERA_SPI_STATUS_E_MSK (1 << 8) + +#define ALTERA_SPI_CONTROL_IROE_MSK (1 << 3) +#define ALTERA_SPI_CONTROL_ITOE_MSK (1 << 4) +#define ALTERA_SPI_CONTROL_ITRDY_MSK (1 << 6) +#define ALTERA_SPI_CONTROL_IRRDY_MSK (1 << 7) +#define ALTERA_SPI_CONTROL_IE_MSK (1 << 8) +#define ALTERA_SPI_CONTROL_SSO_MSK (1 << 10) + static ulong altera_spi_base_list[] = CONFIG_SYS_ALTERA_SPI_LIST; struct altera_spi_slave { - struct spi_slave slave; - ulong base; + struct spi_slave slave; + struct altera_spi_regs *regs; }; #define to_altera_spi_slave(s) container_of(s, struct altera_spi_slave, slave) -__attribute__((weak)) -int spi_cs_is_valid(unsigned int bus, unsigned int cs) +__weak int spi_cs_is_valid(unsigned int bus, unsigned int cs) { return bus < ARRAY_SIZE(altera_spi_base_list) && cs < 32; } -__attribute__((weak)) -void spi_cs_activate(struct spi_slave *slave) +__weak void spi_cs_activate(struct spi_slave *slave) { struct altera_spi_slave *altspi = to_altera_spi_slave(slave); - writel(1 << slave->cs, altspi->base + ALTERA_SPI_SLAVE_SEL); - writel(ALTERA_SPI_CONTROL_SSO_MSK, altspi->base + ALTERA_SPI_CONTROL); + writel(1 << slave->cs, &altspi->regs->slave_sel); + writel(ALTERA_SPI_CONTROL_SSO_MSK, &altspi->regs->control); } -__attribute__((weak)) -void spi_cs_deactivate(struct spi_slave *slave) +__weak void spi_cs_deactivate(struct spi_slave *slave) { struct altera_spi_slave *altspi = to_altera_spi_slave(slave); - writel(0, altspi->base + ALTERA_SPI_CONTROL); - writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); + writel(0, &altspi->regs->control); + writel(0, &altspi->regs->slave_sel); } void spi_init(void) @@ -87,9 +91,8 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (!altspi) return NULL; - altspi->base = altera_spi_base_list[bus]; - debug("%s: bus:%i cs:%i base:%lx\n", __func__, - bus, cs, altspi->base); + altspi->regs = (struct altera_spi_regs *)altera_spi_base_list[bus]; + debug("%s: bus:%i cs:%i base:%p\n", __func__, bus, cs, altspi->regs); return &altspi->slave; } @@ -105,8 +108,8 @@ int spi_claim_bus(struct spi_slave *slave) struct altera_spi_slave *altspi = to_altera_spi_slave(slave); debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); - writel(0, altspi->base + ALTERA_SPI_CONTROL); - writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); + writel(0, &altspi->regs->control); + writel(0, &altspi->regs->slave_sel); return 0; } @@ -115,24 +118,22 @@ void spi_release_bus(struct spi_slave *slave) struct altera_spi_slave *altspi = to_altera_spi_slave(slave); debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); - writel(0, altspi->base + ALTERA_SPI_SLAVE_SEL); + writel(0, &altspi->regs->slave_sel); } -#ifndef CONFIG_ALTERA_SPI_IDLE_VAL -# define CONFIG_ALTERA_SPI_IDLE_VAL 0xff -#endif - int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct altera_spi_slave *altspi = to_altera_spi_slave(slave); /* assume spi core configured to do 8 bit transfers */ - uint bytes = bitlen / 8; - const uchar *txp = dout; - uchar *rxp = din; + unsigned int bytes = bitlen / 8; + const unsigned char *txp = dout; + unsigned char *rxp = din; + uint32_t reg, data, start; debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__, - slave->bus, slave->cs, bitlen, bytes, flags); + slave->bus, slave->cs, bitlen, bytes, flags); + if (bitlen == 0) goto done; @@ -142,25 +143,40 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, } /* empty read buffer */ - if (readl(altspi->base + ALTERA_SPI_STATUS) & - ALTERA_SPI_STATUS_RRDY_MSK) - readl(altspi->base + ALTERA_SPI_RXDATA); + if (readl(&altspi->regs->status) & ALTERA_SPI_STATUS_RRDY_MSK) + readl(&altspi->regs->rxdata); + if (flags & SPI_XFER_BEGIN) spi_cs_activate(slave); while (bytes--) { - uchar d = txp ? *txp++ : CONFIG_ALTERA_SPI_IDLE_VAL; - debug("%s: tx:%x ", __func__, d); - writel(d, altspi->base + ALTERA_SPI_TXDATA); - while (!(readl(altspi->base + ALTERA_SPI_STATUS) & - ALTERA_SPI_STATUS_RRDY_MSK)) - ; - d = readl(altspi->base + ALTERA_SPI_RXDATA); + if (txp) + data = *txp++; + else + data = CONFIG_ALTERA_SPI_IDLE_VAL; + + debug("%s: tx:%x ", __func__, data); + writel(data, &altspi->regs->txdata); + + start = get_timer(0); + while (1) { + reg = readl(&altspi->regs->status); + if (reg & ALTERA_SPI_STATUS_RRDY_MSK) + break; + if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { + printf("%s: Transmission timed out!\n", __func__); + goto done; + } + } + + data = readl(&altspi->regs->rxdata); if (rxp) - *rxp++ = d; - debug("rx:%x\n", d); + *rxp++ = data & 0xff; + + debug("rx:%x\n", data); } - done: + +done: if (flags & SPI_XFER_END) spi_cs_deactivate(slave); diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index be102692d4..23f2ba6223 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -49,6 +49,8 @@ struct mxc_spi_slave { #endif int gpio; int ss_pol; + unsigned int max_hz; + unsigned int mode; }; static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave) @@ -83,12 +85,13 @@ u32 get_cspi_div(u32 div) } #ifdef MXC_CSPI -static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, - unsigned int max_hz, unsigned int mode) +static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs) { unsigned int ctrl_reg; u32 clk_src; u32 div; + unsigned int max_hz = mxcs->max_hz; + unsigned int mode = mxcs->mode; clk_src = mxc_get_clock(MXC_CSPI_CLK); @@ -120,19 +123,15 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, #endif #ifdef MXC_ECSPI -static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, - unsigned int max_hz, unsigned int mode) +static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs) { u32 clk_src = mxc_get_clock(MXC_CSPI_CLK); s32 reg_ctrl, reg_config; u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, sclkctl = 0; u32 pre_div = 0, post_div = 0; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; - - if (max_hz == 0) { - printf("Error: desired clock is 0\n"); - return -1; - } + unsigned int max_hz = mxcs->max_hz; + unsigned int mode = mxcs->mode; /* * Reset SPI and set all CSs to master mode, if toggling @@ -169,9 +168,6 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) | MXC_CSPICTRL_POSTDIV(post_div); - /* We need to disable SPI before changing registers */ - reg_ctrl &= ~MXC_CSPICTRL_EN; - if (mode & SPI_CS_HIGH) ss_pol = 1; @@ -412,6 +408,11 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (bus >= ARRAY_SIZE(spi_bases)) return NULL; + if (max_hz == 0) { + printf("Error: desired clock is 0\n"); + return NULL; + } + mxcs = spi_alloc_slave(struct mxc_spi_slave, bus, cs); if (!mxcs) { puts("mxc_spi: SPI Slave not allocated !\n"); @@ -427,13 +428,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, } mxcs->base = spi_bases[bus]; + mxcs->max_hz = max_hz; + mxcs->mode = mode; - ret = spi_cfg_mxc(mxcs, cs, max_hz, mode); - if (ret) { - printf("mxc_spi: cannot setup SPI controller\n"); - free(mxcs); - return NULL; - } return &mxcs->slave; } @@ -446,12 +443,17 @@ void spi_free_slave(struct spi_slave *slave) int spi_claim_bus(struct spi_slave *slave) { + int ret; struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; reg_write(®s->rxdata, 1); udelay(1); - reg_write(®s->ctrl, mxcs->ctrl_reg); + ret = spi_cfg_mxc(mxcs, slave->cs); + if (ret) { + printf("mxc_spi: cannot setup SPI controller\n"); + return ret; + } reg_write(®s->period, MXC_CSPIPERIOD_32KHZ); reg_write(®s->intr, 0); |