101ec99d9SAlbert Aribaud /* 2306563a7SAlbert Aribaud * Driver for the TWSI (i2c) controller found on the Marvell 3306563a7SAlbert Aribaud * orion5x and kirkwood SoC families. 401ec99d9SAlbert Aribaud * 557b4bce9SAlbert ARIBAUD * Author: Albert Aribaud <albert.u.boot@aribaud.net> 6306563a7SAlbert Aribaud * Copyright (c) 2010 Albert Aribaud. 701ec99d9SAlbert Aribaud * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 901ec99d9SAlbert Aribaud */ 10306563a7SAlbert Aribaud 1101ec99d9SAlbert Aribaud #include <common.h> 1201ec99d9SAlbert Aribaud #include <i2c.h> 131221ce45SMasahiro Yamada #include <linux/errno.h> 1401ec99d9SAlbert Aribaud #include <asm/io.h> 15c68c6243Smario.six@gdsys.cc #include <linux/compat.h> 1614a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C 1714a6ff2cSmario.six@gdsys.cc #include <dm.h> 1814a6ff2cSmario.six@gdsys.cc #endif 1914a6ff2cSmario.six@gdsys.cc 2014a6ff2cSmario.six@gdsys.cc DECLARE_GLOBAL_DATA_PTR; 2101ec99d9SAlbert Aribaud 22306563a7SAlbert Aribaud /* 2349c801bfSmario.six@gdsys.cc * Include a file that will provide CONFIG_I2C_MVTWSI_BASE*, and possibly other 2449c801bfSmario.six@gdsys.cc * settings 25306563a7SAlbert Aribaud */ 2601ec99d9SAlbert Aribaud 2714a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C 28306563a7SAlbert Aribaud #if defined(CONFIG_ORION5X) 29306563a7SAlbert Aribaud #include <asm/arch/orion5x.h> 3081e33f4bSStefan Roese #elif (defined(CONFIG_KIRKWOOD) || defined(CONFIG_ARCH_MVEBU)) 313dc23f78SStefan Roese #include <asm/arch/soc.h> 32aec9a0f1SJagan Teki #elif defined(CONFIG_ARCH_SUNXI) 336620377eSHans de Goede #include <asm/arch/i2c.h> 34306563a7SAlbert Aribaud #else 35306563a7SAlbert Aribaud #error Driver mvtwsi not supported by SoC or board 3601ec99d9SAlbert Aribaud #endif 3714a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */ 3801ec99d9SAlbert Aribaud 3901ec99d9SAlbert Aribaud /* 40*a8f01ccfSJernej Skrabec * On SUNXI, we get CONFIG_SYS_TCLK from this include, so we want to 41*a8f01ccfSJernej Skrabec * always have it. 42*a8f01ccfSJernej Skrabec */ 43*a8f01ccfSJernej Skrabec #if defined(CONFIG_DM_I2C) && defined(CONFIG_ARCH_SUNXI) 44*a8f01ccfSJernej Skrabec #include <asm/arch/i2c.h> 45*a8f01ccfSJernej Skrabec #endif 46*a8f01ccfSJernej Skrabec 47*a8f01ccfSJernej Skrabec /* 48306563a7SAlbert Aribaud * TWSI register structure 4901ec99d9SAlbert Aribaud */ 5001ec99d9SAlbert Aribaud 51aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI 526620377eSHans de Goede 536620377eSHans de Goede struct mvtwsi_registers { 546620377eSHans de Goede u32 slave_address; 556620377eSHans de Goede u32 xtnd_slave_addr; 566620377eSHans de Goede u32 data; 576620377eSHans de Goede u32 control; 586620377eSHans de Goede u32 status; 596620377eSHans de Goede u32 baudrate; 606620377eSHans de Goede u32 soft_reset; 616620377eSHans de Goede }; 626620377eSHans de Goede 636620377eSHans de Goede #else 646620377eSHans de Goede 65306563a7SAlbert Aribaud struct mvtwsi_registers { 66306563a7SAlbert Aribaud u32 slave_address; 67306563a7SAlbert Aribaud u32 data; 68306563a7SAlbert Aribaud u32 control; 69306563a7SAlbert Aribaud union { 7049c801bfSmario.six@gdsys.cc u32 status; /* When reading */ 7149c801bfSmario.six@gdsys.cc u32 baudrate; /* When writing */ 72306563a7SAlbert Aribaud }; 73306563a7SAlbert Aribaud u32 xtnd_slave_addr; 74306563a7SAlbert Aribaud u32 reserved[2]; 75306563a7SAlbert Aribaud u32 soft_reset; 76306563a7SAlbert Aribaud }; 77306563a7SAlbert Aribaud 786620377eSHans de Goede #endif 796620377eSHans de Goede 8014a6ff2cSmario.six@gdsys.cc #ifdef CONFIG_DM_I2C 8114a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev { 8214a6ff2cSmario.six@gdsys.cc /* TWSI Register base for the device */ 8314a6ff2cSmario.six@gdsys.cc struct mvtwsi_registers *base; 8414a6ff2cSmario.six@gdsys.cc /* Number of the device (determined from cell-index property) */ 8514a6ff2cSmario.six@gdsys.cc int index; 8614a6ff2cSmario.six@gdsys.cc /* The I2C slave address for the device */ 8714a6ff2cSmario.six@gdsys.cc u8 slaveadd; 8814a6ff2cSmario.six@gdsys.cc /* The configured I2C speed in Hz */ 8914a6ff2cSmario.six@gdsys.cc uint speed; 90c68c6243Smario.six@gdsys.cc /* The current length of a clock period (depending on speed) */ 91c68c6243Smario.six@gdsys.cc uint tick; 9214a6ff2cSmario.six@gdsys.cc }; 9314a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */ 9414a6ff2cSmario.six@gdsys.cc 95306563a7SAlbert Aribaud /* 96dfc3958cSmario.six@gdsys.cc * enum mvtwsi_ctrl_register_fields - Bit masks for flags in the control 97dfc3958cSmario.six@gdsys.cc * register 98306563a7SAlbert Aribaud */ 99dfc3958cSmario.six@gdsys.cc enum mvtwsi_ctrl_register_fields { 100dfc3958cSmario.six@gdsys.cc /* Acknowledge bit */ 101dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_ACK = 0x00000004, 102dfc3958cSmario.six@gdsys.cc /* Interrupt flag */ 103dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_IFLG = 0x00000008, 104dfc3958cSmario.six@gdsys.cc /* Stop bit */ 105dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_STOP = 0x00000010, 106dfc3958cSmario.six@gdsys.cc /* Start bit */ 107dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_START = 0x00000020, 108dfc3958cSmario.six@gdsys.cc /* I2C enable */ 109dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_TWSIEN = 0x00000040, 110dfc3958cSmario.six@gdsys.cc /* Interrupt enable */ 111dfc3958cSmario.six@gdsys.cc MVTWSI_CONTROL_INTEN = 0x00000080, 112dfc3958cSmario.six@gdsys.cc }; 113306563a7SAlbert Aribaud 114306563a7SAlbert Aribaud /* 11549c801bfSmario.six@gdsys.cc * On sun6i and newer, IFLG is a write-clear bit, which is cleared by writing 1; 11649c801bfSmario.six@gdsys.cc * on other platforms, it is a normal r/w bit, which is cleared by writing 0. 117904dfbfdSHans de Goede */ 118904dfbfdSHans de Goede 119904dfbfdSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I 120904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008 121904dfbfdSHans de Goede #else 122904dfbfdSHans de Goede #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000 123904dfbfdSHans de Goede #endif 124904dfbfdSHans de Goede 125904dfbfdSHans de Goede /* 126dfc3958cSmario.six@gdsys.cc * enum mvstwsi_status_values - Possible values of I2C controller's status 127dfc3958cSmario.six@gdsys.cc * register 128dfc3958cSmario.six@gdsys.cc * 129dfc3958cSmario.six@gdsys.cc * Only those statuses expected in normal master operation on 130dfc3958cSmario.six@gdsys.cc * non-10-bit-address devices are specified. 131dfc3958cSmario.six@gdsys.cc * 132dfc3958cSmario.six@gdsys.cc * Every status that's unexpected during normal operation (bus errors, 133dfc3958cSmario.six@gdsys.cc * arbitration losses, missing ACKs...) is passed back to the caller as an error 134306563a7SAlbert Aribaud * code. 135306563a7SAlbert Aribaud */ 136dfc3958cSmario.six@gdsys.cc enum mvstwsi_status_values { 137dfc3958cSmario.six@gdsys.cc /* START condition transmitted */ 138dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_START = 0x08, 139dfc3958cSmario.six@gdsys.cc /* Repeated START condition transmitted */ 140dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_REPEATED_START = 0x10, 141dfc3958cSmario.six@gdsys.cc /* Address + write bit transmitted, ACK received */ 142dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_W_ACK = 0x18, 143dfc3958cSmario.six@gdsys.cc /* Data transmitted, ACK received */ 144dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK = 0x28, 145dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK received */ 146dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_ACK = 0x40, 147dfc3958cSmario.six@gdsys.cc /* Address + read bit transmitted, ACK not received */ 148dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_ADDR_R_NAK = 0x48, 149dfc3958cSmario.six@gdsys.cc /* Data received, ACK transmitted */ 150dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_ACK = 0x50, 151dfc3958cSmario.six@gdsys.cc /* Data received, ACK not transmitted */ 152dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK = 0x58, 153dfc3958cSmario.six@gdsys.cc /* No relevant status */ 154dfc3958cSmario.six@gdsys.cc MVTWSI_STATUS_IDLE = 0xF8, 155dfc3958cSmario.six@gdsys.cc }; 156306563a7SAlbert Aribaud 157306563a7SAlbert Aribaud /* 158670514f5Smario.six@gdsys.cc * enum mvstwsi_ack_flags - Determine whether a read byte should be 159670514f5Smario.six@gdsys.cc * acknowledged or not. 160670514f5Smario.six@gdsys.cc */ 161670514f5Smario.six@gdsys.cc enum mvtwsi_ack_flags { 162670514f5Smario.six@gdsys.cc /* Send NAK after received byte */ 163670514f5Smario.six@gdsys.cc MVTWSI_READ_NAK = 0, 164670514f5Smario.six@gdsys.cc /* Send ACK after received byte */ 165670514f5Smario.six@gdsys.cc MVTWSI_READ_ACK = 1, 166670514f5Smario.six@gdsys.cc }; 167670514f5Smario.six@gdsys.cc 1686e677cafSmario.six@gdsys.cc /* 1696e677cafSmario.six@gdsys.cc * calc_tick() - Calculate the duration of a clock cycle from the I2C speed 1706e677cafSmario.six@gdsys.cc * 1716e677cafSmario.six@gdsys.cc * @speed: The speed in Hz to calculate the clock cycle duration for. 1726e677cafSmario.six@gdsys.cc * @return The duration of a clock cycle in ns. 1736e677cafSmario.six@gdsys.cc */ 174c68c6243Smario.six@gdsys.cc inline uint calc_tick(uint speed) 175c68c6243Smario.six@gdsys.cc { 176c68c6243Smario.six@gdsys.cc /* One tick = the duration of a period at the specified speed in ns (we 177c68c6243Smario.six@gdsys.cc * add 100 ns to be on the safe side) */ 178c68c6243Smario.six@gdsys.cc return (1000000000u / speed) + 100; 179c68c6243Smario.six@gdsys.cc } 180c68c6243Smario.six@gdsys.cc 18114a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C 182c68c6243Smario.six@gdsys.cc 183670514f5Smario.six@gdsys.cc /* 1846e677cafSmario.six@gdsys.cc * twsi_get_base() - Get controller register base for specified adapter 1856e677cafSmario.six@gdsys.cc * 1866e677cafSmario.six@gdsys.cc * @adap: Adapter to get the register base for. 1876e677cafSmario.six@gdsys.cc * @return Register base for the specified adapter. 188306563a7SAlbert Aribaud */ 189dd82242bSPaul Kocialkowski static struct mvtwsi_registers *twsi_get_base(struct i2c_adapter *adap) 190dd82242bSPaul Kocialkowski { 191dd82242bSPaul Kocialkowski switch (adap->hwadapnr) { 192dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0 193dd82242bSPaul Kocialkowski case 0: 194dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE0; 195dd82242bSPaul Kocialkowski #endif 196dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1 197dd82242bSPaul Kocialkowski case 1: 198dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE1; 199dd82242bSPaul Kocialkowski #endif 200dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2 201dd82242bSPaul Kocialkowski case 2: 202dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE2; 203dd82242bSPaul Kocialkowski #endif 204dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3 205dd82242bSPaul Kocialkowski case 3: 206dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE3; 207dd82242bSPaul Kocialkowski #endif 208dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4 209dd82242bSPaul Kocialkowski case 4: 210dd82242bSPaul Kocialkowski return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE4; 211dd82242bSPaul Kocialkowski #endif 2129d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5 2139d082687SJelle van der Waa case 5: 2149d082687SJelle van der Waa return (struct mvtwsi_registers *)CONFIG_I2C_MVTWSI_BASE5; 2159d082687SJelle van der Waa #endif 216dd82242bSPaul Kocialkowski default: 217dd82242bSPaul Kocialkowski printf("Missing mvtwsi controller %d base\n", adap->hwadapnr); 218dd82242bSPaul Kocialkowski break; 219dd82242bSPaul Kocialkowski } 220dd82242bSPaul Kocialkowski 221dd82242bSPaul Kocialkowski return NULL; 222dd82242bSPaul Kocialkowski } 22314a6ff2cSmario.six@gdsys.cc #endif 224306563a7SAlbert Aribaud 225306563a7SAlbert Aribaud /* 226dfc3958cSmario.six@gdsys.cc * enum mvtwsi_error_class - types of I2C errors 227306563a7SAlbert Aribaud */ 228dfc3958cSmario.six@gdsys.cc enum mvtwsi_error_class { 229dfc3958cSmario.six@gdsys.cc /* The controller returned a different status than expected */ 230dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_WRONG_STATUS = 0x01, 231dfc3958cSmario.six@gdsys.cc /* The controller timed out */ 232dfc3958cSmario.six@gdsys.cc MVTWSI_ERROR_TIMEOUT = 0x02, 233dfc3958cSmario.six@gdsys.cc }; 234306563a7SAlbert Aribaud 235dfc3958cSmario.six@gdsys.cc /* 236dfc3958cSmario.six@gdsys.cc * mvtwsi_error() - Build I2C return code from error information 237dfc3958cSmario.six@gdsys.cc * 238dfc3958cSmario.six@gdsys.cc * For debugging purposes, this function packs some information of an occurred 239dfc3958cSmario.six@gdsys.cc * error into a return code. These error codes are returned from I2C API 240dfc3958cSmario.six@gdsys.cc * functions (i2c_{read,write}, dm_i2c_{read,write}, etc.). 241dfc3958cSmario.six@gdsys.cc * 242dfc3958cSmario.six@gdsys.cc * @ec: The error class of the error (enum mvtwsi_error_class). 243dfc3958cSmario.six@gdsys.cc * @lc: The last value of the control register. 244dfc3958cSmario.six@gdsys.cc * @ls: The last value of the status register. 245dfc3958cSmario.six@gdsys.cc * @es: The expected value of the status register. 246dfc3958cSmario.six@gdsys.cc * @return The generated error code. 247dfc3958cSmario.six@gdsys.cc */ 248dfc3958cSmario.six@gdsys.cc inline uint mvtwsi_error(uint ec, uint lc, uint ls, uint es) 249dfc3958cSmario.six@gdsys.cc { 250dfc3958cSmario.six@gdsys.cc return ((ec << 24) & 0xFF000000) 251dfc3958cSmario.six@gdsys.cc | ((lc << 16) & 0x00FF0000) 252dfc3958cSmario.six@gdsys.cc | ((ls << 8) & 0x0000FF00) 253dfc3958cSmario.six@gdsys.cc | (es & 0xFF); 254dfc3958cSmario.six@gdsys.cc } 255306563a7SAlbert Aribaud 256306563a7SAlbert Aribaud /* 2576e677cafSmario.six@gdsys.cc * twsi_wait() - Wait for I2C bus interrupt flag and check status, or time out. 2586e677cafSmario.six@gdsys.cc * 2596e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time 2606e677cafSmario.six@gdsys.cc * out occurred, or the status was not the expected one. 261306563a7SAlbert Aribaud */ 262c68c6243Smario.six@gdsys.cc static int twsi_wait(struct mvtwsi_registers *twsi, int expected_status, 263c68c6243Smario.six@gdsys.cc uint tick) 26401ec99d9SAlbert Aribaud { 265306563a7SAlbert Aribaud int control, status; 266306563a7SAlbert Aribaud int timeout = 1000; 267306563a7SAlbert Aribaud 268306563a7SAlbert Aribaud do { 269306563a7SAlbert Aribaud control = readl(&twsi->control); 270306563a7SAlbert Aribaud if (control & MVTWSI_CONTROL_IFLG) { 271306563a7SAlbert Aribaud status = readl(&twsi->status); 272306563a7SAlbert Aribaud if (status == expected_status) 273306563a7SAlbert Aribaud return 0; 27401ec99d9SAlbert Aribaud else 275dfc3958cSmario.six@gdsys.cc return mvtwsi_error( 276306563a7SAlbert Aribaud MVTWSI_ERROR_WRONG_STATUS, 277306563a7SAlbert Aribaud control, status, expected_status); 278306563a7SAlbert Aribaud } 279c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */ 280306563a7SAlbert Aribaud } while (timeout--); 281306563a7SAlbert Aribaud status = readl(&twsi->status); 282dfc3958cSmario.six@gdsys.cc return mvtwsi_error(MVTWSI_ERROR_TIMEOUT, control, status, 283dfc3958cSmario.six@gdsys.cc expected_status); 28401ec99d9SAlbert Aribaud } 28501ec99d9SAlbert Aribaud 286306563a7SAlbert Aribaud /* 2876e677cafSmario.six@gdsys.cc * twsi_start() - Assert a START condition on the bus. 2886e677cafSmario.six@gdsys.cc * 2896e677cafSmario.six@gdsys.cc * This function is used in both single I2C transactions and inside 2906e677cafSmario.six@gdsys.cc * back-to-back transactions (repeated starts). 2916e677cafSmario.six@gdsys.cc * 2926e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 2936e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the 2946e677cafSmario.six@gdsys.cc * operation completion. 2956e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 2966e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time 2976e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one. 298306563a7SAlbert Aribaud */ 299c68c6243Smario.six@gdsys.cc static int twsi_start(struct mvtwsi_registers *twsi, int expected_status, 300c68c6243Smario.six@gdsys.cc uint tick) 301306563a7SAlbert Aribaud { 30249c801bfSmario.six@gdsys.cc /* Assert START */ 303670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_START | 3042ca02995SHans de Goede MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control); 30549c801bfSmario.six@gdsys.cc /* Wait for controller to process START */ 306c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick); 307306563a7SAlbert Aribaud } 308306563a7SAlbert Aribaud 309306563a7SAlbert Aribaud /* 3106e677cafSmario.six@gdsys.cc * twsi_send() - Send a byte on the I2C bus. 3116e677cafSmario.six@gdsys.cc * 3126e677cafSmario.six@gdsys.cc * The byte may be part of an address byte or data. 3136e677cafSmario.six@gdsys.cc * 3146e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 3156e677cafSmario.six@gdsys.cc * @byte: The byte to send. 3166e677cafSmario.six@gdsys.cc * @expected_status: The I2C bus status expected to be asserted after the 3176e677cafSmario.six@gdsys.cc * operation completion. 3186e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 3196e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time 3206e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one. 321306563a7SAlbert Aribaud */ 3223c4db636Smario.six@gdsys.cc static int twsi_send(struct mvtwsi_registers *twsi, u8 byte, 323c68c6243Smario.six@gdsys.cc int expected_status, uint tick) 324306563a7SAlbert Aribaud { 32549c801bfSmario.six@gdsys.cc /* Write byte to data register for sending */ 326306563a7SAlbert Aribaud writel(byte, &twsi->data); 32749c801bfSmario.six@gdsys.cc /* Clear any pending interrupt -- that will cause sending */ 328670514f5Smario.six@gdsys.cc writel(MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_CLEAR_IFLG, 329670514f5Smario.six@gdsys.cc &twsi->control); 33049c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and check ACK */ 331c68c6243Smario.six@gdsys.cc return twsi_wait(twsi, expected_status, tick); 332306563a7SAlbert Aribaud } 333306563a7SAlbert Aribaud 334306563a7SAlbert Aribaud /* 3356e677cafSmario.six@gdsys.cc * twsi_recv() - Receive a byte on the I2C bus. 3366e677cafSmario.six@gdsys.cc * 3376e677cafSmario.six@gdsys.cc * The static variable mvtwsi_control_flags controls whether we ack or nak. 3386e677cafSmario.six@gdsys.cc * 3396e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 3406e677cafSmario.six@gdsys.cc * @byte: The byte to send. 3416e677cafSmario.six@gdsys.cc * @ack_flag: Flag that determines whether the received byte should 3426e677cafSmario.six@gdsys.cc * be acknowledged by the controller or not (sent ACK/NAK). 3436e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 3446e677cafSmario.six@gdsys.cc * @return Zero if status is as expected, or a non-zero code if either a time 3456e677cafSmario.six@gdsys.cc * out occurred or the status was not the expected one. 346306563a7SAlbert Aribaud */ 347c68c6243Smario.six@gdsys.cc static int twsi_recv(struct mvtwsi_registers *twsi, u8 *byte, int ack_flag, 348c68c6243Smario.six@gdsys.cc uint tick) 349306563a7SAlbert Aribaud { 350670514f5Smario.six@gdsys.cc int expected_status, status, control; 351306563a7SAlbert Aribaud 352670514f5Smario.six@gdsys.cc /* Compute expected status based on passed ACK flag */ 353670514f5Smario.six@gdsys.cc expected_status = ack_flag ? MVTWSI_STATUS_DATA_R_ACK : 354670514f5Smario.six@gdsys.cc MVTWSI_STATUS_DATA_R_NAK; 35549c801bfSmario.six@gdsys.cc /* Acknowledge *previous state*, and launch receive */ 356670514f5Smario.six@gdsys.cc control = MVTWSI_CONTROL_TWSIEN; 357670514f5Smario.six@gdsys.cc control |= ack_flag == MVTWSI_READ_ACK ? MVTWSI_CONTROL_ACK : 0; 358670514f5Smario.six@gdsys.cc writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control); 35949c801bfSmario.six@gdsys.cc /* Wait for controller to receive byte, and assert ACK or NAK */ 360c68c6243Smario.six@gdsys.cc status = twsi_wait(twsi, expected_status, tick); 36149c801bfSmario.six@gdsys.cc /* If we did receive the expected byte, store it */ 362306563a7SAlbert Aribaud if (status == 0) 363306563a7SAlbert Aribaud *byte = readl(&twsi->data); 364306563a7SAlbert Aribaud return status; 365306563a7SAlbert Aribaud } 366306563a7SAlbert Aribaud 367306563a7SAlbert Aribaud /* 3686e677cafSmario.six@gdsys.cc * twsi_stop() - Assert a STOP condition on the bus. 3696e677cafSmario.six@gdsys.cc * 3706e677cafSmario.six@gdsys.cc * This function is also used to force the bus back to idle state (SDA = 3716e677cafSmario.six@gdsys.cc * SCL = 1). 3726e677cafSmario.six@gdsys.cc * 3736e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 3746e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 3756e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out 3766e677cafSmario.six@gdsys.cc * occurred. 377306563a7SAlbert Aribaud */ 378c68c6243Smario.six@gdsys.cc static int twsi_stop(struct mvtwsi_registers *twsi, uint tick) 379306563a7SAlbert Aribaud { 380306563a7SAlbert Aribaud int control, stop_status; 381059fce9fSmario.six@gdsys.cc int status = 0; 382306563a7SAlbert Aribaud int timeout = 1000; 383306563a7SAlbert Aribaud 38449c801bfSmario.six@gdsys.cc /* Assert STOP */ 385306563a7SAlbert Aribaud control = MVTWSI_CONTROL_TWSIEN | MVTWSI_CONTROL_STOP; 386904dfbfdSHans de Goede writel(control | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control); 38749c801bfSmario.six@gdsys.cc /* Wait for IDLE; IFLG won't rise, so we can't use twsi_wait() */ 388306563a7SAlbert Aribaud do { 389306563a7SAlbert Aribaud stop_status = readl(&twsi->status); 390306563a7SAlbert Aribaud if (stop_status == MVTWSI_STATUS_IDLE) 391306563a7SAlbert Aribaud break; 392c68c6243Smario.six@gdsys.cc ndelay(tick); /* One clock cycle */ 393306563a7SAlbert Aribaud } while (timeout--); 394306563a7SAlbert Aribaud control = readl(&twsi->control); 395306563a7SAlbert Aribaud if (stop_status != MVTWSI_STATUS_IDLE) 396059fce9fSmario.six@gdsys.cc status = mvtwsi_error(MVTWSI_ERROR_TIMEOUT, 397306563a7SAlbert Aribaud control, status, MVTWSI_STATUS_IDLE); 398306563a7SAlbert Aribaud return status; 399306563a7SAlbert Aribaud } 400306563a7SAlbert Aribaud 4016e677cafSmario.six@gdsys.cc /* 4026e677cafSmario.six@gdsys.cc * twsi_calc_freq() - Compute I2C frequency depending on m and n parameters. 4036e677cafSmario.six@gdsys.cc * 4046e677cafSmario.six@gdsys.cc * @n: Parameter 'n' for the frequency calculation algorithm. 4056e677cafSmario.six@gdsys.cc * @m: Parameter 'm' for the frequency calculation algorithm. 4066e677cafSmario.six@gdsys.cc * @return The I2C frequency corresponding to the passed m and n parameters. 4076e677cafSmario.six@gdsys.cc */ 408e0758281Smario.six@gdsys.cc static uint twsi_calc_freq(const int n, const int m) 409f582a158SStefan Roese { 410aec9a0f1SJagan Teki #ifdef CONFIG_ARCH_SUNXI 411f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (1 << n)); 412f582a158SStefan Roese #else 413f582a158SStefan Roese return CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n)); 414f582a158SStefan Roese #endif 415f582a158SStefan Roese } 416306563a7SAlbert Aribaud 417306563a7SAlbert Aribaud /* 4186e677cafSmario.six@gdsys.cc * twsi_reset() - Reset the I2C controller. 4196e677cafSmario.six@gdsys.cc * 4206e677cafSmario.six@gdsys.cc * Resetting the controller also resets the baud rate and slave address, hence 4216e677cafSmario.six@gdsys.cc * they must be re-established after the reset. 4226e677cafSmario.six@gdsys.cc * 4236e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 424306563a7SAlbert Aribaud */ 4253c4db636Smario.six@gdsys.cc static void twsi_reset(struct mvtwsi_registers *twsi) 426306563a7SAlbert Aribaud { 42749c801bfSmario.six@gdsys.cc /* Reset controller */ 428306563a7SAlbert Aribaud writel(0, &twsi->soft_reset); 42949c801bfSmario.six@gdsys.cc /* Wait 2 ms -- this is what the Marvell LSP does */ 430306563a7SAlbert Aribaud udelay(20000); 431306563a7SAlbert Aribaud } 432306563a7SAlbert Aribaud 433306563a7SAlbert Aribaud /* 4346e677cafSmario.six@gdsys.cc * __twsi_i2c_set_bus_speed() - Set the speed of the I2C controller. 4356e677cafSmario.six@gdsys.cc * 4366e677cafSmario.six@gdsys.cc * This function sets baud rate to the highest possible value that does not 4376e677cafSmario.six@gdsys.cc * exceed the requested rate. 4386e677cafSmario.six@gdsys.cc * 4396e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 4406e677cafSmario.six@gdsys.cc * @requested_speed: The desired frequency the controller should run at 4416e677cafSmario.six@gdsys.cc * in Hz. 4426e677cafSmario.six@gdsys.cc * @return The actual frequency the controller was configured to. 443306563a7SAlbert Aribaud */ 4443c4db636Smario.six@gdsys.cc static uint __twsi_i2c_set_bus_speed(struct mvtwsi_registers *twsi, 445e0758281Smario.six@gdsys.cc uint requested_speed) 446306563a7SAlbert Aribaud { 447e0758281Smario.six@gdsys.cc uint tmp_speed, highest_speed, n, m; 448e0758281Smario.six@gdsys.cc uint baud = 0x44; /* Baud rate after controller reset */ 449306563a7SAlbert Aribaud 450306563a7SAlbert Aribaud highest_speed = 0; 45149c801bfSmario.six@gdsys.cc /* Successively try m, n combinations, and use the combination 45249c801bfSmario.six@gdsys.cc * resulting in the largest speed that's not above the requested 45349c801bfSmario.six@gdsys.cc * speed */ 45401ec99d9SAlbert Aribaud for (n = 0; n < 8; n++) { 45501ec99d9SAlbert Aribaud for (m = 0; m < 16; m++) { 456f582a158SStefan Roese tmp_speed = twsi_calc_freq(n, m); 4579ec43b0cSmario.six@gdsys.cc if ((tmp_speed <= requested_speed) && 4589ec43b0cSmario.six@gdsys.cc (tmp_speed > highest_speed)) { 459306563a7SAlbert Aribaud highest_speed = tmp_speed; 460306563a7SAlbert Aribaud baud = (m << 3) | n; 46101ec99d9SAlbert Aribaud } 46201ec99d9SAlbert Aribaud } 46301ec99d9SAlbert Aribaud } 4640db2bbdcSHans de Goede writel(baud, &twsi->baudrate); 465c68c6243Smario.six@gdsys.cc 466c68c6243Smario.six@gdsys.cc /* Wait for controller for one tick */ 467c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C 468c68c6243Smario.six@gdsys.cc ndelay(calc_tick(highest_speed)); 469c68c6243Smario.six@gdsys.cc #else 470c68c6243Smario.six@gdsys.cc ndelay(10000); 471c68c6243Smario.six@gdsys.cc #endif 472c68c6243Smario.six@gdsys.cc return highest_speed; 4730db2bbdcSHans de Goede } 4740db2bbdcSHans de Goede 4756e677cafSmario.six@gdsys.cc /* 4766e677cafSmario.six@gdsys.cc * __twsi_i2c_init() - Initialize the I2C controller. 4776e677cafSmario.six@gdsys.cc * 4786e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 4796e677cafSmario.six@gdsys.cc * @speed: The initial frequency the controller should run at 4806e677cafSmario.six@gdsys.cc * in Hz. 4816e677cafSmario.six@gdsys.cc * @slaveadd: The I2C address to be set for the I2C master. 4826e677cafSmario.six@gdsys.cc * @actual_speed: A output parameter that receives the actual frequency 4836e677cafSmario.six@gdsys.cc * in Hz the controller was set to by the function. 4846e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out 4856e677cafSmario.six@gdsys.cc * occurred. 4866e677cafSmario.six@gdsys.cc */ 4873c4db636Smario.six@gdsys.cc static void __twsi_i2c_init(struct mvtwsi_registers *twsi, int speed, 488c68c6243Smario.six@gdsys.cc int slaveadd, uint *actual_speed) 4890db2bbdcSHans de Goede { 49049c801bfSmario.six@gdsys.cc /* Reset controller */ 4913c4db636Smario.six@gdsys.cc twsi_reset(twsi); 49249c801bfSmario.six@gdsys.cc /* Set speed */ 493c68c6243Smario.six@gdsys.cc *actual_speed = __twsi_i2c_set_bus_speed(twsi, speed); 49449c801bfSmario.six@gdsys.cc /* Set slave address; even though we don't use it */ 4950db2bbdcSHans de Goede writel(slaveadd, &twsi->slave_address); 4960db2bbdcSHans de Goede writel(0, &twsi->xtnd_slave_addr); 49749c801bfSmario.six@gdsys.cc /* Assert STOP, but don't care for the result */ 498c68c6243Smario.six@gdsys.cc #ifdef CONFIG_DM_I2C 499c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, calc_tick(*actual_speed)); 500c68c6243Smario.six@gdsys.cc #else 501c68c6243Smario.six@gdsys.cc (void) twsi_stop(twsi, 10000); 502c68c6243Smario.six@gdsys.cc #endif 50301ec99d9SAlbert Aribaud } 50401ec99d9SAlbert Aribaud 50501ec99d9SAlbert Aribaud /* 5066e677cafSmario.six@gdsys.cc * i2c_begin() - Start a I2C transaction. 5076e677cafSmario.six@gdsys.cc * 5086e677cafSmario.six@gdsys.cc * Begin a I2C transaction with a given expected start status and chip address. 5096e677cafSmario.six@gdsys.cc * A START is asserted, and the address byte is sent to the I2C controller. The 5106e677cafSmario.six@gdsys.cc * expected address status will be derived from the direction bit (bit 0) of 5116e677cafSmario.six@gdsys.cc * the address byte. 5126e677cafSmario.six@gdsys.cc * 5136e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 5146e677cafSmario.six@gdsys.cc * @expected_start_status: The I2C status the controller is expected to 5156e677cafSmario.six@gdsys.cc * assert after the address byte was sent. 5166e677cafSmario.six@gdsys.cc * @addr: The address byte to be sent. 5176e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current 5186e677cafSmario.six@gdsys.cc * I2C speed. 5196e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or 5206e677cafSmario.six@gdsys.cc * unexpected I2C status occurred. 52101ec99d9SAlbert Aribaud */ 5223c4db636Smario.six@gdsys.cc static int i2c_begin(struct mvtwsi_registers *twsi, int expected_start_status, 523c68c6243Smario.six@gdsys.cc u8 addr, uint tick) 52401ec99d9SAlbert Aribaud { 525306563a7SAlbert Aribaud int status, expected_addr_status; 52601ec99d9SAlbert Aribaud 52749c801bfSmario.six@gdsys.cc /* Compute the expected address status from the direction bit in 52849c801bfSmario.six@gdsys.cc * the address byte */ 52949c801bfSmario.six@gdsys.cc if (addr & 1) /* Reading */ 530306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_R_ACK; 53149c801bfSmario.six@gdsys.cc else /* Writing */ 532306563a7SAlbert Aribaud expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK; 53349c801bfSmario.six@gdsys.cc /* Assert START */ 534c68c6243Smario.six@gdsys.cc status = twsi_start(twsi, expected_start_status, tick); 53549c801bfSmario.six@gdsys.cc /* Send out the address if the start went well */ 536306563a7SAlbert Aribaud if (status == 0) 537c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, addr, expected_addr_status, tick); 53849c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */ 539306563a7SAlbert Aribaud return status; 54001ec99d9SAlbert Aribaud } 54101ec99d9SAlbert Aribaud 542306563a7SAlbert Aribaud /* 5436e677cafSmario.six@gdsys.cc * __twsi_i2c_probe_chip() - Probe the given I2C chip address. 5446e677cafSmario.six@gdsys.cc * 5456e677cafSmario.six@gdsys.cc * This function begins a I2C read transaction, does a dummy read and NAKs; if 5466e677cafSmario.six@gdsys.cc * the procedure succeeds, the chip is considered to be present. 5476e677cafSmario.six@gdsys.cc * 5486e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 5496e677cafSmario.six@gdsys.cc * @chip: The chip address to probe. 5506e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 5516e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or 5526e677cafSmario.six@gdsys.cc * unexpected I2C status occurred. 553306563a7SAlbert Aribaud */ 554c68c6243Smario.six@gdsys.cc static int __twsi_i2c_probe_chip(struct mvtwsi_registers *twsi, uchar chip, 555c68c6243Smario.six@gdsys.cc uint tick) 55601ec99d9SAlbert Aribaud { 557306563a7SAlbert Aribaud u8 dummy_byte; 558306563a7SAlbert Aribaud int status; 55901ec99d9SAlbert Aribaud 56049c801bfSmario.six@gdsys.cc /* Begin i2c read */ 561c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1) | 1, tick); 56249c801bfSmario.six@gdsys.cc /* Dummy read was accepted: receive byte, but NAK it. */ 563306563a7SAlbert Aribaud if (status == 0) 564c68c6243Smario.six@gdsys.cc status = twsi_recv(twsi, &dummy_byte, MVTWSI_READ_NAK, tick); 565306563a7SAlbert Aribaud /* Stop transaction */ 566c68c6243Smario.six@gdsys.cc twsi_stop(twsi, tick); 56749c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */ 568306563a7SAlbert Aribaud return status; 56901ec99d9SAlbert Aribaud } 57001ec99d9SAlbert Aribaud 571306563a7SAlbert Aribaud /* 5726e677cafSmario.six@gdsys.cc * __twsi_i2c_read() - Read data from a I2C chip. 5736e677cafSmario.six@gdsys.cc * 5746e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address 5756e677cafSmario.six@gdsys.cc * bytes; then begins a I2C read transaction, and receives the data bytes. 576306563a7SAlbert Aribaud * 57749c801bfSmario.six@gdsys.cc * NOTE: Some devices want a stop right before the second start, while some 57849c801bfSmario.six@gdsys.cc * will choke if it is there. Since deciding this is not yet supported in 57949c801bfSmario.six@gdsys.cc * higher level APIs, we need to make a decision here, and for the moment that 58049c801bfSmario.six@gdsys.cc * will be a repeated start without a preceding stop. 5816e677cafSmario.six@gdsys.cc * 5826e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 5836e677cafSmario.six@gdsys.cc * @chip: The chip address to read from. 5846e677cafSmario.six@gdsys.cc * @addr: The address bytes to send. 5856e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes. 5866e677cafSmario.six@gdsys.cc * @data: The buffer to receive the data read from the chip (has to have 5876e677cafSmario.six@gdsys.cc * a size of at least 'length' bytes). 5886e677cafSmario.six@gdsys.cc * @length: The amount of data to be read from the chip in bytes. 5896e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 5906e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or 5916e677cafSmario.six@gdsys.cc * unexpected I2C status occurred. 592306563a7SAlbert Aribaud */ 5933c4db636Smario.six@gdsys.cc static int __twsi_i2c_read(struct mvtwsi_registers *twsi, uchar chip, 594c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length, 595c68c6243Smario.six@gdsys.cc uint tick) 59601ec99d9SAlbert Aribaud { 597059fce9fSmario.six@gdsys.cc int status = 0; 598059fce9fSmario.six@gdsys.cc int stop_status; 59924f9c6bbSmario.six@gdsys.cc int expected_start = MVTWSI_STATUS_START; 60001ec99d9SAlbert Aribaud 60124f9c6bbSmario.six@gdsys.cc if (alen > 0) { 60249c801bfSmario.six@gdsys.cc /* Begin i2c write to send the address bytes */ 603c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1), tick); 60449c801bfSmario.six@gdsys.cc /* Send address bytes */ 605306563a7SAlbert Aribaud while ((status == 0) && alen--) 60603d6cd97SStefan Roese status = twsi_send(twsi, addr[alen], 607c68c6243Smario.six@gdsys.cc MVTWSI_STATUS_DATA_W_ACK, tick); 60824f9c6bbSmario.six@gdsys.cc /* Send repeated STARTs after the initial START */ 60924f9c6bbSmario.six@gdsys.cc expected_start = MVTWSI_STATUS_REPEATED_START; 61024f9c6bbSmario.six@gdsys.cc } 61149c801bfSmario.six@gdsys.cc /* Begin i2c read to receive data bytes */ 612306563a7SAlbert Aribaud if (status == 0) 613c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, expected_start, (chip << 1) | 1, tick); 614670514f5Smario.six@gdsys.cc /* Receive actual data bytes; set NAK if we if we have nothing more to 615670514f5Smario.six@gdsys.cc * read */ 616670514f5Smario.six@gdsys.cc while ((status == 0) && length--) 6173c4db636Smario.six@gdsys.cc status = twsi_recv(twsi, data++, 618670514f5Smario.six@gdsys.cc length > 0 ? 619c68c6243Smario.six@gdsys.cc MVTWSI_READ_ACK : MVTWSI_READ_NAK, tick); 620306563a7SAlbert Aribaud /* Stop transaction */ 621c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick); 62249c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */ 623059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status; 62401ec99d9SAlbert Aribaud } 62501ec99d9SAlbert Aribaud 626306563a7SAlbert Aribaud /* 6276e677cafSmario.six@gdsys.cc * __twsi_i2c_write() - Send data to a I2C chip. 6286e677cafSmario.six@gdsys.cc * 6296e677cafSmario.six@gdsys.cc * This function begins a I2C write transaction, and transmits the address 6306e677cafSmario.six@gdsys.cc * bytes; then begins a new I2C write transaction, and sends the data bytes. 6316e677cafSmario.six@gdsys.cc * 6326e677cafSmario.six@gdsys.cc * @twsi: The MVTWSI register structure to use. 6336e677cafSmario.six@gdsys.cc * @chip: The chip address to read from. 6346e677cafSmario.six@gdsys.cc * @addr: The address bytes to send. 6356e677cafSmario.six@gdsys.cc * @alen: The length of the address bytes in bytes. 6366e677cafSmario.six@gdsys.cc * @data: The buffer containing the data to be sent to the chip. 6376e677cafSmario.six@gdsys.cc * @length: The length of data to be sent to the chip in bytes. 6386e677cafSmario.six@gdsys.cc * @tick: The duration of a clock cycle at the current I2C speed. 6396e677cafSmario.six@gdsys.cc * @return Zero if the operation succeeded, or a non-zero code if a time out or 6406e677cafSmario.six@gdsys.cc * unexpected I2C status occurred. 641306563a7SAlbert Aribaud */ 6423c4db636Smario.six@gdsys.cc static int __twsi_i2c_write(struct mvtwsi_registers *twsi, uchar chip, 643c68c6243Smario.six@gdsys.cc u8 *addr, int alen, uchar *data, int length, 644c68c6243Smario.six@gdsys.cc uint tick) 64501ec99d9SAlbert Aribaud { 646059fce9fSmario.six@gdsys.cc int status, stop_status; 64701ec99d9SAlbert Aribaud 64849c801bfSmario.six@gdsys.cc /* Begin i2c write to send first the address bytes, then the 64949c801bfSmario.six@gdsys.cc * data bytes */ 650c68c6243Smario.six@gdsys.cc status = i2c_begin(twsi, MVTWSI_STATUS_START, (chip << 1), tick); 65149c801bfSmario.six@gdsys.cc /* Send address bytes */ 652f8a10ed1Smario.six@gdsys.cc while ((status == 0) && (alen-- > 0)) 65303d6cd97SStefan Roese status = twsi_send(twsi, addr[alen], MVTWSI_STATUS_DATA_W_ACK, 654c68c6243Smario.six@gdsys.cc tick); 65549c801bfSmario.six@gdsys.cc /* Send data bytes */ 656306563a7SAlbert Aribaud while ((status == 0) && (length-- > 0)) 657c68c6243Smario.six@gdsys.cc status = twsi_send(twsi, *(data++), MVTWSI_STATUS_DATA_W_ACK, 658c68c6243Smario.six@gdsys.cc tick); 659306563a7SAlbert Aribaud /* Stop transaction */ 660c68c6243Smario.six@gdsys.cc stop_status = twsi_stop(twsi, tick); 66149c801bfSmario.six@gdsys.cc /* Return 0, or the status of the first failure */ 662059fce9fSmario.six@gdsys.cc return status != 0 ? status : stop_status; 66301ec99d9SAlbert Aribaud } 66401ec99d9SAlbert Aribaud 66514a6ff2cSmario.six@gdsys.cc #ifndef CONFIG_DM_I2C 66661bc02b2Smario.six@gdsys.cc static void twsi_i2c_init(struct i2c_adapter *adap, int speed, 66761bc02b2Smario.six@gdsys.cc int slaveadd) 66861bc02b2Smario.six@gdsys.cc { 6693c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap); 670c68c6243Smario.six@gdsys.cc __twsi_i2c_init(twsi, speed, slaveadd, NULL); 67161bc02b2Smario.six@gdsys.cc } 67261bc02b2Smario.six@gdsys.cc 67361bc02b2Smario.six@gdsys.cc static uint twsi_i2c_set_bus_speed(struct i2c_adapter *adap, 67461bc02b2Smario.six@gdsys.cc uint requested_speed) 67561bc02b2Smario.six@gdsys.cc { 6763c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap); 677c68c6243Smario.six@gdsys.cc __twsi_i2c_set_bus_speed(twsi, requested_speed); 678c68c6243Smario.six@gdsys.cc return 0; 67961bc02b2Smario.six@gdsys.cc } 68061bc02b2Smario.six@gdsys.cc 68161bc02b2Smario.six@gdsys.cc static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip) 68261bc02b2Smario.six@gdsys.cc { 6833c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap); 684c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(twsi, chip, 10000); 68561bc02b2Smario.six@gdsys.cc } 68661bc02b2Smario.six@gdsys.cc 68761bc02b2Smario.six@gdsys.cc static int twsi_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, 68861bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length) 68961bc02b2Smario.six@gdsys.cc { 6903c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap); 691f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4]; 692f8a10ed1Smario.six@gdsys.cc 693f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF; 694f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF; 695f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF; 696f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF; 697f8a10ed1Smario.six@gdsys.cc 698c68c6243Smario.six@gdsys.cc return __twsi_i2c_read(twsi, chip, addr_bytes, alen, data, length, 699c68c6243Smario.six@gdsys.cc 10000); 70061bc02b2Smario.six@gdsys.cc } 70161bc02b2Smario.six@gdsys.cc 70261bc02b2Smario.six@gdsys.cc static int twsi_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, 70361bc02b2Smario.six@gdsys.cc int alen, uchar *data, int length) 70461bc02b2Smario.six@gdsys.cc { 7053c4db636Smario.six@gdsys.cc struct mvtwsi_registers *twsi = twsi_get_base(adap); 706f8a10ed1Smario.six@gdsys.cc u8 addr_bytes[4]; 707f8a10ed1Smario.six@gdsys.cc 708f8a10ed1Smario.six@gdsys.cc addr_bytes[0] = (addr >> 0) & 0xFF; 709f8a10ed1Smario.six@gdsys.cc addr_bytes[1] = (addr >> 8) & 0xFF; 710f8a10ed1Smario.six@gdsys.cc addr_bytes[2] = (addr >> 16) & 0xFF; 711f8a10ed1Smario.six@gdsys.cc addr_bytes[3] = (addr >> 24) & 0xFF; 712f8a10ed1Smario.six@gdsys.cc 713c68c6243Smario.six@gdsys.cc return __twsi_i2c_write(twsi, chip, addr_bytes, alen, data, length, 714c68c6243Smario.six@gdsys.cc 10000); 71561bc02b2Smario.six@gdsys.cc } 71661bc02b2Smario.six@gdsys.cc 717dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE0 7180db2bbdcSHans de Goede U_BOOT_I2C_ADAP_COMPLETE(twsi0, twsi_i2c_init, twsi_i2c_probe, 7190db2bbdcSHans de Goede twsi_i2c_read, twsi_i2c_write, 7200db2bbdcSHans de Goede twsi_i2c_set_bus_speed, 7210db2bbdcSHans de Goede CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 0) 722dd82242bSPaul Kocialkowski #endif 723dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE1 724dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi1, twsi_i2c_init, twsi_i2c_probe, 725dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write, 726dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed, 727dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 1) 728dd82242bSPaul Kocialkowski 729dd82242bSPaul Kocialkowski #endif 730dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE2 731dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi2, twsi_i2c_init, twsi_i2c_probe, 732dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write, 733dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed, 734dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 2) 735dd82242bSPaul Kocialkowski 736dd82242bSPaul Kocialkowski #endif 737dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE3 738dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi3, twsi_i2c_init, twsi_i2c_probe, 739dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write, 740dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed, 741dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 3) 742dd82242bSPaul Kocialkowski 743dd82242bSPaul Kocialkowski #endif 744dd82242bSPaul Kocialkowski #ifdef CONFIG_I2C_MVTWSI_BASE4 745dd82242bSPaul Kocialkowski U_BOOT_I2C_ADAP_COMPLETE(twsi4, twsi_i2c_init, twsi_i2c_probe, 746dd82242bSPaul Kocialkowski twsi_i2c_read, twsi_i2c_write, 747dd82242bSPaul Kocialkowski twsi_i2c_set_bus_speed, 748dd82242bSPaul Kocialkowski CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 4) 749dd82242bSPaul Kocialkowski 750dd82242bSPaul Kocialkowski #endif 7519d082687SJelle van der Waa #ifdef CONFIG_I2C_MVTWSI_BASE5 7529d082687SJelle van der Waa U_BOOT_I2C_ADAP_COMPLETE(twsi5, twsi_i2c_init, twsi_i2c_probe, 7539d082687SJelle van der Waa twsi_i2c_read, twsi_i2c_write, 7549d082687SJelle van der Waa twsi_i2c_set_bus_speed, 7559d082687SJelle van der Waa CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE, 5) 7569d082687SJelle van der Waa 7579d082687SJelle van der Waa #endif 75814a6ff2cSmario.six@gdsys.cc #else /* CONFIG_DM_I2C */ 75914a6ff2cSmario.six@gdsys.cc 76014a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe_chip(struct udevice *bus, u32 chip_addr, 76114a6ff2cSmario.six@gdsys.cc u32 chip_flags) 76214a6ff2cSmario.six@gdsys.cc { 76314a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); 764c68c6243Smario.six@gdsys.cc return __twsi_i2c_probe_chip(dev->base, chip_addr, dev->tick); 76514a6ff2cSmario.six@gdsys.cc } 76614a6ff2cSmario.six@gdsys.cc 76714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_set_bus_speed(struct udevice *bus, uint speed) 76814a6ff2cSmario.six@gdsys.cc { 76914a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); 770c68c6243Smario.six@gdsys.cc 771c68c6243Smario.six@gdsys.cc dev->speed = __twsi_i2c_set_bus_speed(dev->base, speed); 772c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed); 773c68c6243Smario.six@gdsys.cc 774c68c6243Smario.six@gdsys.cc return 0; 77514a6ff2cSmario.six@gdsys.cc } 77614a6ff2cSmario.six@gdsys.cc 77714a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_ofdata_to_platdata(struct udevice *bus) 77814a6ff2cSmario.six@gdsys.cc { 77914a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); 78014a6ff2cSmario.six@gdsys.cc 78114a6ff2cSmario.six@gdsys.cc dev->base = dev_get_addr_ptr(bus); 78214a6ff2cSmario.six@gdsys.cc 78314a6ff2cSmario.six@gdsys.cc if (!dev->base) 78414a6ff2cSmario.six@gdsys.cc return -ENOMEM; 78514a6ff2cSmario.six@gdsys.cc 786e160f7d4SSimon Glass dev->index = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), 78714a6ff2cSmario.six@gdsys.cc "cell-index", -1); 788e160f7d4SSimon Glass dev->slaveadd = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), 78914a6ff2cSmario.six@gdsys.cc "u-boot,i2c-slave-addr", 0x0); 790e160f7d4SSimon Glass dev->speed = fdtdec_get_int(gd->fdt_blob, dev_of_offset(bus), 79114a6ff2cSmario.six@gdsys.cc "clock-frequency", 100000); 79214a6ff2cSmario.six@gdsys.cc return 0; 79314a6ff2cSmario.six@gdsys.cc } 79414a6ff2cSmario.six@gdsys.cc 79514a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_probe(struct udevice *bus) 79614a6ff2cSmario.six@gdsys.cc { 79714a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); 798c68c6243Smario.six@gdsys.cc uint actual_speed; 799c68c6243Smario.six@gdsys.cc 800c68c6243Smario.six@gdsys.cc __twsi_i2c_init(dev->base, dev->speed, dev->slaveadd, &actual_speed); 801c68c6243Smario.six@gdsys.cc dev->speed = actual_speed; 802c68c6243Smario.six@gdsys.cc dev->tick = calc_tick(dev->speed); 80314a6ff2cSmario.six@gdsys.cc return 0; 80414a6ff2cSmario.six@gdsys.cc } 80514a6ff2cSmario.six@gdsys.cc 80614a6ff2cSmario.six@gdsys.cc static int mvtwsi_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) 80714a6ff2cSmario.six@gdsys.cc { 80814a6ff2cSmario.six@gdsys.cc struct mvtwsi_i2c_dev *dev = dev_get_priv(bus); 80914a6ff2cSmario.six@gdsys.cc struct i2c_msg *dmsg, *omsg, dummy; 81014a6ff2cSmario.six@gdsys.cc 81114a6ff2cSmario.six@gdsys.cc memset(&dummy, 0, sizeof(struct i2c_msg)); 81214a6ff2cSmario.six@gdsys.cc 81314a6ff2cSmario.six@gdsys.cc /* We expect either two messages (one with an offset and one with the 81414a6ff2cSmario.six@gdsys.cc * actual data) or one message (just data or offset/data combined) */ 81514a6ff2cSmario.six@gdsys.cc if (nmsgs > 2 || nmsgs == 0) { 81614a6ff2cSmario.six@gdsys.cc debug("%s: Only one or two messages are supported.", __func__); 81714a6ff2cSmario.six@gdsys.cc return -1; 81814a6ff2cSmario.six@gdsys.cc } 81914a6ff2cSmario.six@gdsys.cc 82014a6ff2cSmario.six@gdsys.cc omsg = nmsgs == 1 ? &dummy : msg; 82114a6ff2cSmario.six@gdsys.cc dmsg = nmsgs == 1 ? msg : msg + 1; 82214a6ff2cSmario.six@gdsys.cc 82314a6ff2cSmario.six@gdsys.cc if (dmsg->flags & I2C_M_RD) 82414a6ff2cSmario.six@gdsys.cc return __twsi_i2c_read(dev->base, dmsg->addr, omsg->buf, 825c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len, 826c68c6243Smario.six@gdsys.cc dev->tick); 82714a6ff2cSmario.six@gdsys.cc else 82814a6ff2cSmario.six@gdsys.cc return __twsi_i2c_write(dev->base, dmsg->addr, omsg->buf, 829c68c6243Smario.six@gdsys.cc omsg->len, dmsg->buf, dmsg->len, 830c68c6243Smario.six@gdsys.cc dev->tick); 83114a6ff2cSmario.six@gdsys.cc } 83214a6ff2cSmario.six@gdsys.cc 83314a6ff2cSmario.six@gdsys.cc static const struct dm_i2c_ops mvtwsi_i2c_ops = { 83414a6ff2cSmario.six@gdsys.cc .xfer = mvtwsi_i2c_xfer, 83514a6ff2cSmario.six@gdsys.cc .probe_chip = mvtwsi_i2c_probe_chip, 83614a6ff2cSmario.six@gdsys.cc .set_bus_speed = mvtwsi_i2c_set_bus_speed, 83714a6ff2cSmario.six@gdsys.cc }; 83814a6ff2cSmario.six@gdsys.cc 83914a6ff2cSmario.six@gdsys.cc static const struct udevice_id mvtwsi_i2c_ids[] = { 84014a6ff2cSmario.six@gdsys.cc { .compatible = "marvell,mv64xxx-i2c", }, 84187de0eb3SStefan Roese { .compatible = "marvell,mv78230-i2c", }, 842*a8f01ccfSJernej Skrabec { .compatible = "allwinner,sun6i-a31-i2c", }, 84314a6ff2cSmario.six@gdsys.cc { /* sentinel */ } 84414a6ff2cSmario.six@gdsys.cc }; 84514a6ff2cSmario.six@gdsys.cc 84614a6ff2cSmario.six@gdsys.cc U_BOOT_DRIVER(i2c_mvtwsi) = { 84714a6ff2cSmario.six@gdsys.cc .name = "i2c_mvtwsi", 84814a6ff2cSmario.six@gdsys.cc .id = UCLASS_I2C, 84914a6ff2cSmario.six@gdsys.cc .of_match = mvtwsi_i2c_ids, 85014a6ff2cSmario.six@gdsys.cc .probe = mvtwsi_i2c_probe, 85114a6ff2cSmario.six@gdsys.cc .ofdata_to_platdata = mvtwsi_i2c_ofdata_to_platdata, 85214a6ff2cSmario.six@gdsys.cc .priv_auto_alloc_size = sizeof(struct mvtwsi_i2c_dev), 85314a6ff2cSmario.six@gdsys.cc .ops = &mvtwsi_i2c_ops, 85414a6ff2cSmario.six@gdsys.cc }; 85514a6ff2cSmario.six@gdsys.cc #endif /* CONFIG_DM_I2C */ 856