X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=drivers%2Fi2c%2Fmxc_i2c.c;h=36edf03b28868c22bc44b2cd879f9d8d7531c8b2;hb=581b4ae49d0089c38195cbb9ac6e85eedc5c7f41;hp=a73b10b9c49f662c167276f3d97abcc7517e75dd;hpb=caddc17f3019a437b972cd04a8c9a9cbea344def;p=karo-tx-uboot.git diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index a73b10b9c4..36edf03b28 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -11,23 +11,7 @@ * Copyright (C) 2008 Darius Augulis * * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 + * SPDX-License-Identifier: GPL-2.0+ */ #include @@ -38,6 +22,17 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + +#ifdef I2C_QUIRK_REG +struct mxc_i2c_regs { + uint8_t iadr; + uint8_t ifdr; + uint8_t i2cr; + uint8_t i2sr; + uint8_t i2dr; +}; +#else struct mxc_i2c_regs { uint32_t iadr; uint32_t ifdr; @@ -45,8 +40,8 @@ struct mxc_i2c_regs { uint32_t i2sr; uint32_t i2dr; }; +#endif -#define I2CR_IEN (1 << 7) #define I2CR_IIEN (1 << 6) #define I2CR_MSTA (1 << 5) #define I2CR_MTX (1 << 4) @@ -59,10 +54,39 @@ struct mxc_i2c_regs { #define I2SR_IIF (1 << 1) #define I2SR_RX_NO_AK (1 << 0) +#ifdef I2C_QUIRK_REG +#define I2CR_IEN (0 << 7) +#define I2CR_IDIS (1 << 7) +#define I2SR_IIF_CLEAR (1 << 1) +#else +#define I2CR_IEN (1 << 7) +#define I2CR_IDIS (0 << 7) +#define I2SR_IIF_CLEAR (0 << 1) +#endif + #if defined(CONFIG_HARD_I2C) && !defined(CONFIG_SYS_I2C_BASE) #error "define CONFIG_SYS_I2C_BASE to use the mxc_i2c driver" #endif +#ifdef I2C_QUIRK_REG +static u16 i2c_clk_div[60][2] = { + { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 }, + { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 }, + { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D }, + { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 }, + { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 }, + { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 }, + { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 }, + { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 }, + { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 }, + { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, + { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 }, + { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 }, + { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B }, + { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A }, + { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, +}; +#else static u16 i2c_clk_div[50][2] = { { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, @@ -78,6 +102,35 @@ static u16 i2c_clk_div[50][2] = { { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, { 3072, 0x1E }, { 3840, 0x1F } }; +#endif + + +#ifndef CONFIG_SYS_MXC_I2C1_SPEED +#define CONFIG_SYS_MXC_I2C1_SPEED 100000 +#endif +#ifndef CONFIG_SYS_MXC_I2C2_SPEED +#define CONFIG_SYS_MXC_I2C2_SPEED 100000 +#endif +#ifndef CONFIG_SYS_MXC_I2C3_SPEED +#define CONFIG_SYS_MXC_I2C3_SPEED 100000 +#endif +#ifndef CONFIG_SYS_MXC_I2C4_SPEED +#define CONFIG_SYS_MXC_I2C4_SPEED 100000 +#endif + +#ifndef CONFIG_SYS_MXC_I2C1_SLAVE +#define CONFIG_SYS_MXC_I2C1_SLAVE 0 +#endif +#ifndef CONFIG_SYS_MXC_I2C2_SLAVE +#define CONFIG_SYS_MXC_I2C2_SLAVE 0 +#endif +#ifndef CONFIG_SYS_MXC_I2C3_SLAVE +#define CONFIG_SYS_MXC_I2C3_SLAVE 0 +#endif +#ifndef CONFIG_SYS_MXC_I2C4_SLAVE +#define CONFIG_SYS_MXC_I2C4_SLAVE 0 +#endif + /* * Calculate and set proper clock divider @@ -88,7 +141,7 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) unsigned int div; u8 clk_div; -#if defined(CONFIG_MX31) +#if defined(CONFIG_SOC_MX31) struct clock_control_regs *sc_regs = (struct clock_control_regs *)CCM_BASE; @@ -121,30 +174,18 @@ static int bus_i2c_set_bus_speed(void *base, int speed) u8 clk_idx = i2c_imx_get_clk(speed); u8 idx = i2c_clk_div[clk_idx][1]; + if (!base) + return -ENODEV; + /* Store divider value */ writeb(idx, &i2c_regs->ifdr); /* Reset module */ - writeb(0, &i2c_regs->i2cr); + writeb(I2CR_IDIS, &i2c_regs->i2cr); writeb(0, &i2c_regs->i2sr); return 0; } -/* - * Get I2C Speed - */ -static unsigned int bus_i2c_get_bus_speed(void *base) -{ - struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; - u8 clk_idx = readb(&i2c_regs->ifdr); - u8 clk_div; - - for (clk_div = 0; i2c_clk_div[clk_div][1] != clk_idx; clk_div++) - ; - - return mxc_get_clock(MXC_I2C_CLK) / i2c_clk_div[clk_div][0]; -} - #define ST_BUS_IDLE (0 | (I2SR_IBB << 8)) #define ST_BUS_BUSY (I2SR_IBB | (I2SR_IBB << 8)) #define ST_IIF (I2SR_IIF | (I2SR_IIF << 8)) @@ -157,7 +198,11 @@ static int wait_for_sr_state(struct mxc_i2c_regs *i2c_regs, unsigned state) for (;;) { sr = readb(&i2c_regs->i2sr); if (sr & I2SR_IAL) { +#ifdef I2C_QUIRK_REG + writeb(sr | I2SR_IAL, &i2c_regs->i2sr); +#else writeb(sr & ~I2SR_IAL, &i2c_regs->i2sr); +#endif printf("%s: Arbitration lost sr=%x cr=%x state=%x\n", __func__, sr, readb(&i2c_regs->i2cr), state); return -ERESTART; @@ -178,7 +223,7 @@ static int tx_byte(struct mxc_i2c_regs *i2c_regs, u8 byte) { int ret; - writeb(0, &i2c_regs->i2sr); + writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr); writeb(byte, &i2c_regs->i2dr); ret = wait_for_sr_state(i2c_regs, ST_IIF); if (ret < 0) @@ -214,14 +259,18 @@ static int i2c_init_transfer_(struct mxc_i2c_regs *i2c_regs, int ret; /* Enable I2C controller */ +#ifdef I2C_QUIRK_REG + if (readb(&i2c_regs->i2cr) & I2CR_IDIS) { +#else if (!(readb(&i2c_regs->i2cr) & I2CR_IEN)) { +#endif writeb(I2CR_IEN, &i2c_regs->i2cr); /* Wait for controller to be stable */ udelay(50); } if (readb(&i2c_regs->iadr) == (chip << 1)) writeb((chip << 1) ^ 2, &i2c_regs->iadr); - writeb(0, &i2c_regs->i2sr); + writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr); ret = wait_for_sr_state(i2c_regs, ST_BUS_IDLE); if (ret < 0) return ret; @@ -269,7 +318,8 @@ static int i2c_init_transfer(struct mxc_i2c_regs *i2c_regs, printf("%s: failed for chip 0x%x retry=%d\n", __func__, chip, retry); if (ret != -ERESTART) - writeb(0, &i2c_regs->i2cr); /* Disable controller */ + /* Disable controller */ + writeb(I2CR_IDIS, &i2c_regs->i2cr); udelay(100); if (i2c_idle_bus(i2c_regs) < 0) break; @@ -289,6 +339,9 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, int i; struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; + if (!base) + return -ENODEV; + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) return ret; @@ -309,7 +362,7 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, if (len == 1) temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); - writeb(0, &i2c_regs->i2sr); + writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr); readb(&i2c_regs->i2dr); /* dummy read to clear ICF */ /* read data */ @@ -331,7 +384,7 @@ int bus_i2c_read(void *base, uchar chip, uint addr, int alen, uchar *buf, temp |= I2CR_TX_NO_AK; writeb(temp, &i2c_regs->i2cr); } - writeb(0, &i2c_regs->i2sr); + writeb(I2SR_IIF_CLEAR, &i2c_regs->i2sr); buf[i] = readb(&i2c_regs->i2dr); } i2c_imx_stop(i2c_regs); @@ -348,6 +401,9 @@ int bus_i2c_write(void *base, uchar chip, uint addr, int alen, int i; struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; + if (!base) + return -ENODEV; + ret = i2c_init_transfer(i2c_regs, chip, addr, alen); if (ret < 0) return ret; @@ -361,6 +417,32 @@ int bus_i2c_write(void *base, uchar chip, uint addr, int alen, return ret; } +static void * const i2c_bases[] = { +#if defined(CONFIG_SOC_MX25) + (void *)IMX_I2C_BASE, + (void *)IMX_I2C2_BASE, + (void *)IMX_I2C3_BASE +#elif defined(CONFIG_SOC_MX27) + (void *)IMX_I2C1_BASE, + (void *)IMX_I2C2_BASE +#elif defined(CONFIG_SOC_MX31) || defined(CONFIG_SOC_MX35) || \ + defined(CONFIG_SOC_MX51) || defined(CONFIG_SOC_MX53) || \ + defined(CONFIG_SOC_MX6) || defined(CONFIG_LS102XA) + (void *)I2C1_BASE_ADDR, + (void *)I2C2_BASE_ADDR, + (void *)I2C3_BASE_ADDR +#elif defined(CONFIG_SOC_VF610) + (void *)I2C0_BASE_ADDR +#elif defined(CONFIG_FSL_LSCH3) + (void *)I2C1_BASE_ADDR, + (void *)I2C2_BASE_ADDR, + (void *)I2C3_BASE_ADDR, + (void *)I2C4_BASE_ADDR +#else +#error "architecture not supported" +#endif +}; + struct i2c_parms { void *base; void *idle_bus_data; @@ -369,36 +451,20 @@ struct i2c_parms { struct sram_data { unsigned curr_i2c_bus; - struct i2c_parms i2c_data[3]; + struct i2c_parms i2c_data[ARRAY_SIZE(i2c_bases)]; }; -/* - * For SPL boot some boards need i2c before SDRAM is initialized so force - * variables to live in SRAM - */ -static struct sram_data __attribute__((section(".data"))) srdata; - -void *get_base(void) +void *i2c_get_base(struct i2c_adapter *adap) { -#ifdef CONFIG_SYS_I2C_BASE -#ifdef CONFIG_I2C_MULTI_BUS - void *ret = srdata.i2c_data[srdata.curr_i2c_bus].base; - if (ret) - return ret; -#endif - return (void *)CONFIG_SYS_I2C_BASE; -#elif defined(CONFIG_I2C_MULTI_BUS) - return srdata.i2c_data[srdata.curr_i2c_bus].base; -#else - return srdata.i2c_data[0].base; -#endif + return i2c_bases[adap->hwadapnr]; } static struct i2c_parms *i2c_get_parms(void *base) { + struct sram_data *srdata = (void *)gd->srdata; int i = 0; - struct i2c_parms *p = srdata.i2c_data; - while (i < ARRAY_SIZE(srdata.i2c_data)) { + struct i2c_parms *p = srdata->i2c_data; + while (i < ARRAY_SIZE(srdata->i2c_data)) { if (p->base == base) return p; p++; @@ -416,46 +482,34 @@ static int i2c_idle_bus(void *base) return 0; } -#ifdef CONFIG_I2C_MULTI_BUS -unsigned int i2c_get_bus_num(void) +static int mxc_i2c_read(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, + int len) { - return srdata.curr_i2c_bus; + return bus_i2c_read(i2c_get_base(adap), chip, addr, alen, buffer, len); } -int i2c_set_bus_num(unsigned bus_idx) +static int mxc_i2c_write(struct i2c_adapter *adap, uint8_t chip, + uint addr, int alen, uint8_t *buffer, + int len) { - if (bus_idx >= ARRAY_SIZE(srdata.i2c_data)) - return -1; - if (!srdata.i2c_data[bus_idx].base) - return -1; - srdata.curr_i2c_bus = bus_idx; - return 0; -} -#endif - -int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) -{ - return bus_i2c_read(get_base(), chip, addr, alen, buf, len); -} - -int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) -{ - return bus_i2c_write(get_base(), chip, addr, alen, buf, len); + return bus_i2c_write(i2c_get_base(adap), chip, addr, alen, buffer, len); } /* * Test if a chip at a given address responds (probe the chip) */ -int i2c_probe(uchar chip) +static int mxc_i2c_probe(struct i2c_adapter *adap, uint8_t chip) { - return bus_i2c_write(get_base(), chip, 0, 0, NULL, 0); + return bus_i2c_write(i2c_get_base(adap), chip, 0, 0, NULL, 0); } void bus_i2c_init(void *base, int speed, int unused, int (*idle_bus_fn)(void *p), void *idle_bus_data) { + struct sram_data *srdata = (void *)gd->srdata; int i = 0; - struct i2c_parms *p = srdata.i2c_data; + struct i2c_parms *p = srdata->i2c_data; if (!base) return; for (;;) { @@ -469,7 +523,7 @@ void bus_i2c_init(void *base, int speed, int unused, } p++; i++; - if (i >= ARRAY_SIZE(srdata.i2c_data)) + if (i >= ARRAY_SIZE(srdata->i2c_data)) return; } bus_i2c_set_bus_speed(base, speed); @@ -478,23 +532,43 @@ void bus_i2c_init(void *base, int speed, int unused, /* * Init I2C Bus */ -void i2c_init(int speed, int unused) +static void mxc_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) { - bus_i2c_init(get_base(), speed, unused, NULL, NULL); + bus_i2c_init(i2c_get_base(adap), speed, slaveaddr, NULL, NULL); } /* * Set I2C Speed */ -int i2c_set_bus_speed(unsigned int speed) +static uint mxc_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed) { - return bus_i2c_set_bus_speed(get_base(), speed); + return bus_i2c_set_bus_speed(i2c_get_base(adap), speed); } /* - * Get I2C Speed + * Register mxc i2c adapters */ -unsigned int i2c_get_bus_speed(void) -{ - return bus_i2c_get_bus_speed(get_base()); -} +U_BOOT_I2C_ADAP_COMPLETE(mxc0, mxc_i2c_init, mxc_i2c_probe, + mxc_i2c_read, mxc_i2c_write, + mxc_i2c_set_bus_speed, + CONFIG_SYS_MXC_I2C1_SPEED, + CONFIG_SYS_MXC_I2C1_SLAVE, 0) +U_BOOT_I2C_ADAP_COMPLETE(mxc1, mxc_i2c_init, mxc_i2c_probe, + mxc_i2c_read, mxc_i2c_write, + mxc_i2c_set_bus_speed, + CONFIG_SYS_MXC_I2C2_SPEED, + CONFIG_SYS_MXC_I2C2_SLAVE, 1) +#ifdef CONFIG_SYS_I2C_MXC_I2C3 +U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe, + mxc_i2c_read, mxc_i2c_write, + mxc_i2c_set_bus_speed, + CONFIG_SYS_MXC_I2C3_SPEED, + CONFIG_SYS_MXC_I2C3_SLAVE, 2) +#endif +#ifdef CONFIG_SYS_I2C_MXC_I2C4 +U_BOOT_I2C_ADAP_COMPLETE(mxc3, mxc_i2c_init, mxc_i2c_probe, + mxc_i2c_read, mxc_i2c_write, + mxc_i2c_set_bus_speed, + CONFIG_SYS_MXC_I2C4_SPEED, + CONFIG_SYS_MXC_I2C4_SLAVE, 3) +#endif