1*78b3ea9cSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause 2*78b3ea9cSJorge Ramirez-Ortiz /* 3*78b3ea9cSJorge Ramirez-Ortiz * (c) 2020 Jorge Ramirez <jorge@foundries.io>, Foundries Ltd. 4*78b3ea9cSJorge Ramirez-Ortiz */ 5*78b3ea9cSJorge Ramirez-Ortiz #include <arm.h> 6*78b3ea9cSJorge Ramirez-Ortiz #include <drivers/imx_i2c.h> 7*78b3ea9cSJorge Ramirez-Ortiz #include <initcall.h> 8*78b3ea9cSJorge Ramirez-Ortiz #include <io.h> 9*78b3ea9cSJorge Ramirez-Ortiz #include <kernel/delay.h> 10*78b3ea9cSJorge Ramirez-Ortiz #include <mm/core_memprot.h> 11*78b3ea9cSJorge Ramirez-Ortiz #include <mm/core_mmu.h> 12*78b3ea9cSJorge Ramirez-Ortiz #include <platform_config.h> 13*78b3ea9cSJorge Ramirez-Ortiz #include <stdlib.h> 14*78b3ea9cSJorge Ramirez-Ortiz #include <trace.h> 15*78b3ea9cSJorge Ramirez-Ortiz #include <util.h> 16*78b3ea9cSJorge Ramirez-Ortiz 17*78b3ea9cSJorge Ramirez-Ortiz #define I2C_CLK_RATE 24000000 /* Bits per second */ 18*78b3ea9cSJorge Ramirez-Ortiz 19*78b3ea9cSJorge Ramirez-Ortiz static struct io_pa_va i2c_bus[] = { 20*78b3ea9cSJorge Ramirez-Ortiz { .pa = I2C1_BASE, }, 21*78b3ea9cSJorge Ramirez-Ortiz { .pa = I2C2_BASE, }, 22*78b3ea9cSJorge Ramirez-Ortiz { .pa = I2C3_BASE, }, 23*78b3ea9cSJorge Ramirez-Ortiz }; 24*78b3ea9cSJorge Ramirez-Ortiz 25*78b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_clk { 26*78b3ea9cSJorge Ramirez-Ortiz struct io_pa_va base; 27*78b3ea9cSJorge Ramirez-Ortiz uint32_t i2c[ARRAY_SIZE(i2c_bus)]; 28*78b3ea9cSJorge Ramirez-Ortiz } i2c_clk = { 29*78b3ea9cSJorge Ramirez-Ortiz .base.pa = CCM_BASE, 30*78b3ea9cSJorge Ramirez-Ortiz .i2c = { I2C_CLK_CGR(1), I2C_CLK_CGR(2), I2C_CLK_CGR(3), }, 31*78b3ea9cSJorge Ramirez-Ortiz }; 32*78b3ea9cSJorge Ramirez-Ortiz 33*78b3ea9cSJorge Ramirez-Ortiz static struct imx_i2c_mux { 34*78b3ea9cSJorge Ramirez-Ortiz struct io_pa_va base; 35*78b3ea9cSJorge Ramirez-Ortiz struct imx_i2c_mux_regs { 36*78b3ea9cSJorge Ramirez-Ortiz uint32_t scl_mux; 37*78b3ea9cSJorge Ramirez-Ortiz uint32_t scl_cfg; 38*78b3ea9cSJorge Ramirez-Ortiz uint32_t sda_mux; 39*78b3ea9cSJorge Ramirez-Ortiz uint32_t sda_cfg; 40*78b3ea9cSJorge Ramirez-Ortiz } i2c[ARRAY_SIZE(i2c_bus)]; 41*78b3ea9cSJorge Ramirez-Ortiz } i2c_mux = { 42*78b3ea9cSJorge Ramirez-Ortiz .base.pa = IOMUXC_BASE, 43*78b3ea9cSJorge Ramirez-Ortiz .i2c = {{ .scl_mux = I2C_MUX_SCL(1), .scl_cfg = I2C_CFG_SCL(1), 44*78b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(1), .sda_cfg = I2C_CFG_SDA(1), }, 45*78b3ea9cSJorge Ramirez-Ortiz { .scl_mux = I2C_MUX_SCL(2), .scl_cfg = I2C_CFG_SCL(2), 46*78b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(2), .sda_cfg = I2C_CFG_SDA(2), }, 47*78b3ea9cSJorge Ramirez-Ortiz { .scl_mux = I2C_MUX_SCL(3), .scl_cfg = I2C_CFG_SCL(3), 48*78b3ea9cSJorge Ramirez-Ortiz .sda_mux = I2C_MUX_SDA(3), .sda_cfg = I2C_CFG_SDA(3), },}, 49*78b3ea9cSJorge Ramirez-Ortiz }; 50*78b3ea9cSJorge Ramirez-Ortiz 51*78b3ea9cSJorge Ramirez-Ortiz #define I2DR 0x10 52*78b3ea9cSJorge Ramirez-Ortiz #define I2SR 0x0C 53*78b3ea9cSJorge Ramirez-Ortiz #define I2CR 0x08 54*78b3ea9cSJorge Ramirez-Ortiz #define IFDR 0x04 55*78b3ea9cSJorge Ramirez-Ortiz 56*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_IEN BIT(7) 57*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_IIEN BIT(6) 58*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_MSTA BIT(5) 59*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_MTX BIT(4) 60*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_TX_NO_AK BIT(3) 61*78b3ea9cSJorge Ramirez-Ortiz #define I2CR_RSTA BIT(2) 62*78b3ea9cSJorge Ramirez-Ortiz 63*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_ICF BIT(7) 64*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IBB BIT(5) 65*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IAL BIT(4) 66*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_IIF BIT(1) 67*78b3ea9cSJorge Ramirez-Ortiz #define I2SR_RX_NO_AK BIT(0) 68*78b3ea9cSJorge Ramirez-Ortiz 69*78b3ea9cSJorge Ramirez-Ortiz static uint8_t i2c_io_read8(uint8_t bid, uint32_t address) 70*78b3ea9cSJorge Ramirez-Ortiz { 71*78b3ea9cSJorge Ramirez-Ortiz return io_read8(i2c_bus[bid].va + address); 72*78b3ea9cSJorge Ramirez-Ortiz } 73*78b3ea9cSJorge Ramirez-Ortiz 74*78b3ea9cSJorge Ramirez-Ortiz static void i2c_io_write8(uint8_t bid, uint32_t address, uint8_t data) 75*78b3ea9cSJorge Ramirez-Ortiz { 76*78b3ea9cSJorge Ramirez-Ortiz return io_write8(i2c_bus[bid].va + address, data); 77*78b3ea9cSJorge Ramirez-Ortiz } 78*78b3ea9cSJorge Ramirez-Ortiz 79*78b3ea9cSJorge Ramirez-Ortiz static bool bus_is_idle(uint32_t sr) 80*78b3ea9cSJorge Ramirez-Ortiz { 81*78b3ea9cSJorge Ramirez-Ortiz return (sr & I2SR_IBB) == 0; 82*78b3ea9cSJorge Ramirez-Ortiz } 83*78b3ea9cSJorge Ramirez-Ortiz 84*78b3ea9cSJorge Ramirez-Ortiz static bool bus_is_busy(uint32_t sr) 85*78b3ea9cSJorge Ramirez-Ortiz { 86*78b3ea9cSJorge Ramirez-Ortiz return !bus_is_idle(sr); 87*78b3ea9cSJorge Ramirez-Ortiz } 88*78b3ea9cSJorge Ramirez-Ortiz 89*78b3ea9cSJorge Ramirez-Ortiz static bool isr_active(uint32_t sr) 90*78b3ea9cSJorge Ramirez-Ortiz { 91*78b3ea9cSJorge Ramirez-Ortiz return (sr & I2SR_IIF) == I2SR_IIF; 92*78b3ea9cSJorge Ramirez-Ortiz } 93*78b3ea9cSJorge Ramirez-Ortiz 94*78b3ea9cSJorge Ramirez-Ortiz static struct ifdr_pair { 95*78b3ea9cSJorge Ramirez-Ortiz uint32_t divider; 96*78b3ea9cSJorge Ramirez-Ortiz uint8_t prescaler; 97*78b3ea9cSJorge Ramirez-Ortiz } ifdr_table[] = { 98*78b3ea9cSJorge Ramirez-Ortiz { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, 99*78b3ea9cSJorge Ramirez-Ortiz { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, 100*78b3ea9cSJorge Ramirez-Ortiz { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, 101*78b3ea9cSJorge Ramirez-Ortiz { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, 102*78b3ea9cSJorge Ramirez-Ortiz { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, 103*78b3ea9cSJorge Ramirez-Ortiz { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, 104*78b3ea9cSJorge Ramirez-Ortiz { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, 105*78b3ea9cSJorge Ramirez-Ortiz { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, 106*78b3ea9cSJorge Ramirez-Ortiz { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, 107*78b3ea9cSJorge Ramirez-Ortiz { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, 108*78b3ea9cSJorge Ramirez-Ortiz { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, 109*78b3ea9cSJorge Ramirez-Ortiz { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, 110*78b3ea9cSJorge Ramirez-Ortiz { 3072, 0x1E }, { 3840, 0x1F } 111*78b3ea9cSJorge Ramirez-Ortiz }; 112*78b3ea9cSJorge Ramirez-Ortiz 113*78b3ea9cSJorge Ramirez-Ortiz static void i2c_set_prescaler(uint8_t bid, uint32_t bps) 114*78b3ea9cSJorge Ramirez-Ortiz { 115*78b3ea9cSJorge Ramirez-Ortiz struct ifdr_pair *p = ifdr_table; 116*78b3ea9cSJorge Ramirez-Ortiz struct ifdr_pair *q = p + ARRAY_SIZE(ifdr_table) - 1; 117*78b3ea9cSJorge Ramirez-Ortiz uint32_t div = (I2C_CLK_RATE + bps - 1) / bps; 118*78b3ea9cSJorge Ramirez-Ortiz 119*78b3ea9cSJorge Ramirez-Ortiz if (div < p->divider) 120*78b3ea9cSJorge Ramirez-Ortiz q = p; 121*78b3ea9cSJorge Ramirez-Ortiz else if (div > q->divider) 122*78b3ea9cSJorge Ramirez-Ortiz p = q; 123*78b3ea9cSJorge Ramirez-Ortiz 124*78b3ea9cSJorge Ramirez-Ortiz while (p != q) { 125*78b3ea9cSJorge Ramirez-Ortiz if (div <= p->divider) 126*78b3ea9cSJorge Ramirez-Ortiz break; 127*78b3ea9cSJorge Ramirez-Ortiz p++; 128*78b3ea9cSJorge Ramirez-Ortiz } 129*78b3ea9cSJorge Ramirez-Ortiz 130*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, IFDR, p->prescaler); 131*78b3ea9cSJorge Ramirez-Ortiz } 132*78b3ea9cSJorge Ramirez-Ortiz 133*78b3ea9cSJorge Ramirez-Ortiz static void i2c_set_bus_speed(uint8_t bid, int bps) 134*78b3ea9cSJorge Ramirez-Ortiz { 135*78b3ea9cSJorge Ramirez-Ortiz /* Enable the clock */ 136*78b3ea9cSJorge Ramirez-Ortiz io_write32(i2c_clk.base.va + CCM_CCGRx_SET(i2c_clk.i2c[bid]), 137*78b3ea9cSJorge Ramirez-Ortiz CCM_CCGRx_ALWAYS_ON(0)); 138*78b3ea9cSJorge Ramirez-Ortiz 139*78b3ea9cSJorge Ramirez-Ortiz i2c_set_prescaler(bid, bps); 140*78b3ea9cSJorge Ramirez-Ortiz } 141*78b3ea9cSJorge Ramirez-Ortiz 142*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_sync_bus(uint8_t bid, bool (*match)(uint32_t), 143*78b3ea9cSJorge Ramirez-Ortiz uint32_t *status) 144*78b3ea9cSJorge Ramirez-Ortiz { 145*78b3ea9cSJorge Ramirez-Ortiz uint64_t tref = timeout_init_us(100000); 146*78b3ea9cSJorge Ramirez-Ortiz uint32_t sr = 0; 147*78b3ea9cSJorge Ramirez-Ortiz 148*78b3ea9cSJorge Ramirez-Ortiz while (!timeout_elapsed(tref)) { 149*78b3ea9cSJorge Ramirez-Ortiz sr = i2c_io_read8(bid, I2SR); 150*78b3ea9cSJorge Ramirez-Ortiz if (sr & I2SR_IAL) { 151*78b3ea9cSJorge Ramirez-Ortiz EMSG("bus arbitration lost"); 152*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, sr & ~I2SR_IAL); 153*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_COMMUNICATION; 154*78b3ea9cSJorge Ramirez-Ortiz } 155*78b3ea9cSJorge Ramirez-Ortiz if ((*match)(sr)) { 156*78b3ea9cSJorge Ramirez-Ortiz if (status) 157*78b3ea9cSJorge Ramirez-Ortiz *status = sr; 158*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 159*78b3ea9cSJorge Ramirez-Ortiz } 160*78b3ea9cSJorge Ramirez-Ortiz } 161*78b3ea9cSJorge Ramirez-Ortiz 162*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BUSY; 163*78b3ea9cSJorge Ramirez-Ortiz } 164*78b3ea9cSJorge Ramirez-Ortiz 165*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_idle_bus(uint8_t bid) 166*78b3ea9cSJorge Ramirez-Ortiz { 167*78b3ea9cSJorge Ramirez-Ortiz uint8_t tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MSTA; 168*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 169*78b3ea9cSJorge Ramirez-Ortiz 170*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 171*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &bus_is_idle, NULL); 172*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 173*78b3ea9cSJorge Ramirez-Ortiz 174*78b3ea9cSJorge Ramirez-Ortiz return ret; 175*78b3ea9cSJorge Ramirez-Ortiz } 176*78b3ea9cSJorge Ramirez-Ortiz 177*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_byte(uint8_t bid, uint8_t byte) 178*78b3ea9cSJorge Ramirez-Ortiz { 179*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 180*78b3ea9cSJorge Ramirez-Ortiz uint32_t status = 0; 181*78b3ea9cSJorge Ramirez-Ortiz 182*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2DR, byte); 183*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &isr_active, &status); 184*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 185*78b3ea9cSJorge Ramirez-Ortiz 186*78b3ea9cSJorge Ramirez-Ortiz if (ret == TEE_SUCCESS && (status & I2SR_RX_NO_AK)) 187*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_STATE; 188*78b3ea9cSJorge Ramirez-Ortiz 189*78b3ea9cSJorge Ramirez-Ortiz return ret; 190*78b3ea9cSJorge Ramirez-Ortiz } 191*78b3ea9cSJorge Ramirez-Ortiz 192*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_byte(uint8_t bid, uint8_t *p) 193*78b3ea9cSJorge Ramirez-Ortiz { 194*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 195*78b3ea9cSJorge Ramirez-Ortiz 196*78b3ea9cSJorge Ramirez-Ortiz *p = i2c_io_read8(bid, I2DR); 197*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &isr_active, NULL); 198*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2SR, 0); 199*78b3ea9cSJorge Ramirez-Ortiz 200*78b3ea9cSJorge Ramirez-Ortiz return ret; 201*78b3ea9cSJorge Ramirez-Ortiz } 202*78b3ea9cSJorge Ramirez-Ortiz 203*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_write_data(uint8_t bid, const uint8_t *buf, int len) 204*78b3ea9cSJorge Ramirez-Ortiz { 205*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 206*78b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 207*78b3ea9cSJorge Ramirez-Ortiz 208*78b3ea9cSJorge Ramirez-Ortiz if (!len) 209*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 210*78b3ea9cSJorge Ramirez-Ortiz 211*78b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_MTX | I2CR_TX_NO_AK; 212*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 213*78b3ea9cSJorge Ramirez-Ortiz 214*78b3ea9cSJorge Ramirez-Ortiz while (len--) { 215*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_write_byte(bid, *buf++); 216*78b3ea9cSJorge Ramirez-Ortiz if (ret != TEE_SUCCESS) 217*78b3ea9cSJorge Ramirez-Ortiz return ret; 218*78b3ea9cSJorge Ramirez-Ortiz } 219*78b3ea9cSJorge Ramirez-Ortiz 220*78b3ea9cSJorge Ramirez-Ortiz return ret; 221*78b3ea9cSJorge Ramirez-Ortiz } 222*78b3ea9cSJorge Ramirez-Ortiz 223*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_read_data(uint8_t bid, uint8_t *buf, int len) 224*78b3ea9cSJorge Ramirez-Ortiz { 225*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 226*78b3ea9cSJorge Ramirez-Ortiz uint8_t dummy = 0; 227*78b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 228*78b3ea9cSJorge Ramirez-Ortiz 229*78b3ea9cSJorge Ramirez-Ortiz if (!len) 230*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 231*78b3ea9cSJorge Ramirez-Ortiz 232*78b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) & ~I2CR_MTX; 233*78b3ea9cSJorge Ramirez-Ortiz tmp = (len == 1) ? tmp | I2CR_TX_NO_AK : tmp & ~I2CR_TX_NO_AK; 234*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 235*78b3ea9cSJorge Ramirez-Ortiz i2c_io_read8(bid, I2DR); 236*78b3ea9cSJorge Ramirez-Ortiz 237*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_byte(bid, &dummy); 238*78b3ea9cSJorge Ramirez-Ortiz if (ret != TEE_SUCCESS) 239*78b3ea9cSJorge Ramirez-Ortiz return ret; 240*78b3ea9cSJorge Ramirez-Ortiz 241*78b3ea9cSJorge Ramirez-Ortiz /* 242*78b3ea9cSJorge Ramirez-Ortiz * A data transfer ends when the master signals a stop; for a master 243*78b3ea9cSJorge Ramirez-Ortiz * receiver to terminate a transfer it must inform the slave transmiter 244*78b3ea9cSJorge Ramirez-Ortiz * by not acknowledging the last data byte. This is done by setting the 245*78b3ea9cSJorge Ramirez-Ortiz * transmit acknowledge bit before reading the next-to-last byte. 246*78b3ea9cSJorge Ramirez-Ortiz */ 247*78b3ea9cSJorge Ramirez-Ortiz do { 248*78b3ea9cSJorge Ramirez-Ortiz if (len == 2) { 249*78b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_TX_NO_AK; 250*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 251*78b3ea9cSJorge Ramirez-Ortiz } 252*78b3ea9cSJorge Ramirez-Ortiz 253*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_byte(bid, buf++); 254*78b3ea9cSJorge Ramirez-Ortiz if (ret != TEE_SUCCESS) 255*78b3ea9cSJorge Ramirez-Ortiz return ret; 256*78b3ea9cSJorge Ramirez-Ortiz } while (len--); 257*78b3ea9cSJorge Ramirez-Ortiz 258*78b3ea9cSJorge Ramirez-Ortiz return ret; 259*78b3ea9cSJorge Ramirez-Ortiz } 260*78b3ea9cSJorge Ramirez-Ortiz 261*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init_transfer(uint8_t bid, uint8_t chip) 262*78b3ea9cSJorge Ramirez-Ortiz { 263*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 264*78b3ea9cSJorge Ramirez-Ortiz uint32_t tmp = 0; 265*78b3ea9cSJorge Ramirez-Ortiz 266*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_idle_bus(bid); 267*78b3ea9cSJorge Ramirez-Ortiz if (ret != TEE_SUCCESS) 268*78b3ea9cSJorge Ramirez-Ortiz return ret; 269*78b3ea9cSJorge Ramirez-Ortiz 270*78b3ea9cSJorge Ramirez-Ortiz /* Enable the interface */ 271*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, I2CR_IEN); 272*78b3ea9cSJorge Ramirez-Ortiz 273*78b3ea9cSJorge Ramirez-Ortiz tmp = i2c_io_read8(bid, I2CR) | I2CR_MSTA; 274*78b3ea9cSJorge Ramirez-Ortiz i2c_io_write8(bid, I2CR, tmp); 275*78b3ea9cSJorge Ramirez-Ortiz 276*78b3ea9cSJorge Ramirez-Ortiz /* Wait until the bus is active */ 277*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_sync_bus(bid, &bus_is_busy, NULL); 278*78b3ea9cSJorge Ramirez-Ortiz if (ret != TEE_SUCCESS) 279*78b3ea9cSJorge Ramirez-Ortiz return ret; 280*78b3ea9cSJorge Ramirez-Ortiz 281*78b3ea9cSJorge Ramirez-Ortiz /* Slave address on the bus */ 282*78b3ea9cSJorge Ramirez-Ortiz return i2c_write_data(bid, &chip, 1); 283*78b3ea9cSJorge Ramirez-Ortiz } 284*78b3ea9cSJorge Ramirez-Ortiz 285*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_read(uint8_t bid, uint8_t chip, uint8_t *buf, int len) 286*78b3ea9cSJorge Ramirez-Ortiz { 287*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 288*78b3ea9cSJorge Ramirez-Ortiz 289*78b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 290*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 291*78b3ea9cSJorge Ramirez-Ortiz 292*78b3ea9cSJorge Ramirez-Ortiz if ((len && !buf) || chip > 0x7F) 293*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 294*78b3ea9cSJorge Ramirez-Ortiz 295*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_init_transfer(bid, chip << 1 | BIT(0)); 296*78b3ea9cSJorge Ramirez-Ortiz if (ret == TEE_SUCCESS) 297*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_read_data(bid, buf, len); 298*78b3ea9cSJorge Ramirez-Ortiz 299*78b3ea9cSJorge Ramirez-Ortiz if (i2c_idle_bus(bid) != TEE_SUCCESS) 300*78b3ea9cSJorge Ramirez-Ortiz IMSG("bus not idle"); 301*78b3ea9cSJorge Ramirez-Ortiz 302*78b3ea9cSJorge Ramirez-Ortiz return ret; 303*78b3ea9cSJorge Ramirez-Ortiz } 304*78b3ea9cSJorge Ramirez-Ortiz 305*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_write(uint8_t bid, uint8_t chip, const uint8_t *buf, int len) 306*78b3ea9cSJorge Ramirez-Ortiz { 307*78b3ea9cSJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 308*78b3ea9cSJorge Ramirez-Ortiz 309*78b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 310*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 311*78b3ea9cSJorge Ramirez-Ortiz 312*78b3ea9cSJorge Ramirez-Ortiz if ((len && !buf) || chip > 0x7F) 313*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 314*78b3ea9cSJorge Ramirez-Ortiz 315*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_init_transfer(bid, chip << 1); 316*78b3ea9cSJorge Ramirez-Ortiz if (ret == TEE_SUCCESS) 317*78b3ea9cSJorge Ramirez-Ortiz ret = i2c_write_data(bid, buf, len); 318*78b3ea9cSJorge Ramirez-Ortiz 319*78b3ea9cSJorge Ramirez-Ortiz if (i2c_idle_bus(bid) != TEE_SUCCESS) 320*78b3ea9cSJorge Ramirez-Ortiz IMSG("bus not idle"); 321*78b3ea9cSJorge Ramirez-Ortiz 322*78b3ea9cSJorge Ramirez-Ortiz return ret; 323*78b3ea9cSJorge Ramirez-Ortiz } 324*78b3ea9cSJorge Ramirez-Ortiz 325*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_probe(uint8_t bid, uint8_t chip) 326*78b3ea9cSJorge Ramirez-Ortiz { 327*78b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 328*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 329*78b3ea9cSJorge Ramirez-Ortiz 330*78b3ea9cSJorge Ramirez-Ortiz if (chip > 0x7F) 331*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 332*78b3ea9cSJorge Ramirez-Ortiz 333*78b3ea9cSJorge Ramirez-Ortiz return imx_i2c_write(bid, chip, NULL, 0); 334*78b3ea9cSJorge Ramirez-Ortiz } 335*78b3ea9cSJorge Ramirez-Ortiz 336*78b3ea9cSJorge Ramirez-Ortiz /* 337*78b3ea9cSJorge Ramirez-Ortiz * I2C bus initialization: configure the IOMUX and enable the clock. 338*78b3ea9cSJorge Ramirez-Ortiz * @bid: Bus ID: (0=I2C1), (1=I2C2), (2=I2C3). 339*78b3ea9cSJorge Ramirez-Ortiz * @bps: Bus baud rate, in bits per second. 340*78b3ea9cSJorge Ramirez-Ortiz */ 341*78b3ea9cSJorge Ramirez-Ortiz TEE_Result imx_i2c_init(uint8_t bid, int bps) 342*78b3ea9cSJorge Ramirez-Ortiz { 343*78b3ea9cSJorge Ramirez-Ortiz struct imx_i2c_mux *mux = &i2c_mux; 344*78b3ea9cSJorge Ramirez-Ortiz 345*78b3ea9cSJorge Ramirez-Ortiz if (bid >= ARRAY_SIZE(i2c_bus)) 346*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 347*78b3ea9cSJorge Ramirez-Ortiz 348*78b3ea9cSJorge Ramirez-Ortiz if (!bps) 349*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_BAD_PARAMETERS; 350*78b3ea9cSJorge Ramirez-Ortiz 351*78b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].scl_mux, I2C_MUX_VAL(bid)); 352*78b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].scl_cfg, I2C_CFG_VAL(bid)); 353*78b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].sda_mux, I2C_MUX_VAL(bid)); 354*78b3ea9cSJorge Ramirez-Ortiz io_write32(mux->base.va + mux->i2c[bid].sda_cfg, I2C_CFG_VAL(bid)); 355*78b3ea9cSJorge Ramirez-Ortiz 356*78b3ea9cSJorge Ramirez-Ortiz /* Baud rate in bits per second */ 357*78b3ea9cSJorge Ramirez-Ortiz i2c_set_bus_speed(bid, bps); 358*78b3ea9cSJorge Ramirez-Ortiz 359*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 360*78b3ea9cSJorge Ramirez-Ortiz } 361*78b3ea9cSJorge Ramirez-Ortiz 362*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result get_va(paddr_t pa, vaddr_t *va) 363*78b3ea9cSJorge Ramirez-Ortiz { 364*78b3ea9cSJorge Ramirez-Ortiz if (!core_mmu_add_mapping(MEM_AREA_IO_SEC, pa, 0x10000)) 365*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 366*78b3ea9cSJorge Ramirez-Ortiz 367*78b3ea9cSJorge Ramirez-Ortiz *va = (vaddr_t)phys_to_virt(pa, MEM_AREA_IO_SEC); 368*78b3ea9cSJorge Ramirez-Ortiz if (*va) 369*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 370*78b3ea9cSJorge Ramirez-Ortiz 371*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 372*78b3ea9cSJorge Ramirez-Ortiz } 373*78b3ea9cSJorge Ramirez-Ortiz 374*78b3ea9cSJorge Ramirez-Ortiz static TEE_Result i2c_init(void) 375*78b3ea9cSJorge Ramirez-Ortiz { 376*78b3ea9cSJorge Ramirez-Ortiz size_t n = 0; 377*78b3ea9cSJorge Ramirez-Ortiz 378*78b3ea9cSJorge Ramirez-Ortiz if (get_va(i2c_clk.base.pa, &i2c_clk.base.va) != TEE_SUCCESS) 379*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 380*78b3ea9cSJorge Ramirez-Ortiz 381*78b3ea9cSJorge Ramirez-Ortiz if (get_va(i2c_mux.base.pa, &i2c_mux.base.va) != TEE_SUCCESS) 382*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 383*78b3ea9cSJorge Ramirez-Ortiz 384*78b3ea9cSJorge Ramirez-Ortiz for (n = 0; n < ARRAY_SIZE(i2c_bus); n++) { 385*78b3ea9cSJorge Ramirez-Ortiz if (get_va(i2c_bus[n].pa, &i2c_bus[n].va) != TEE_SUCCESS) 386*78b3ea9cSJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 387*78b3ea9cSJorge Ramirez-Ortiz } 388*78b3ea9cSJorge Ramirez-Ortiz 389*78b3ea9cSJorge Ramirez-Ortiz return TEE_SUCCESS; 390*78b3ea9cSJorge Ramirez-Ortiz } 391*78b3ea9cSJorge Ramirez-Ortiz 392*78b3ea9cSJorge Ramirez-Ortiz driver_init(i2c_init); 393