1ef2ee5d0SMichal Meloun /*- 2ef2ee5d0SMichal Meloun * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3ef2ee5d0SMichal Meloun * All rights reserved. 4ef2ee5d0SMichal Meloun * 5ef2ee5d0SMichal Meloun * Redistribution and use in source and binary forms, with or without 6ef2ee5d0SMichal Meloun * modification, are permitted provided that the following conditions 7ef2ee5d0SMichal Meloun * are met: 8ef2ee5d0SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer. 10ef2ee5d0SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11ef2ee5d0SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12ef2ee5d0SMichal Meloun * documentation and/or other materials provided with the distribution. 13ef2ee5d0SMichal Meloun * 14ef2ee5d0SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ef2ee5d0SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ef2ee5d0SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ef2ee5d0SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ef2ee5d0SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ef2ee5d0SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ef2ee5d0SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ef2ee5d0SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ef2ee5d0SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ef2ee5d0SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ef2ee5d0SMichal Meloun * SUCH DAMAGE. 25ef2ee5d0SMichal Meloun */ 26ef2ee5d0SMichal Meloun 27ef2ee5d0SMichal Meloun #include <sys/cdefs.h> 28ef2ee5d0SMichal Meloun /* 29ef2ee5d0SMichal Meloun * I2C driver for Tegra SoCs. 30ef2ee5d0SMichal Meloun */ 31ef2ee5d0SMichal Meloun #include <sys/param.h> 32ef2ee5d0SMichal Meloun #include <sys/systm.h> 33ef2ee5d0SMichal Meloun #include <sys/bus.h> 34ef2ee5d0SMichal Meloun #include <sys/kernel.h> 35ef2ee5d0SMichal Meloun #include <sys/limits.h> 36ef2ee5d0SMichal Meloun #include <sys/module.h> 37ef2ee5d0SMichal Meloun #include <sys/resource.h> 38ef2ee5d0SMichal Meloun 39ef2ee5d0SMichal Meloun #include <machine/bus.h> 40ef2ee5d0SMichal Meloun #include <machine/resource.h> 41ef2ee5d0SMichal Meloun #include <sys/rman.h> 42ef2ee5d0SMichal Meloun 43ef2ee5d0SMichal Meloun #include <sys/lock.h> 44ef2ee5d0SMichal Meloun #include <sys/mutex.h> 45ef2ee5d0SMichal Meloun 46be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 471f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h> 48ef2ee5d0SMichal Meloun #include <dev/iicbus/iiconf.h> 49ef2ee5d0SMichal Meloun #include <dev/iicbus/iicbus.h> 50ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h> 51ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 52ef2ee5d0SMichal Meloun 53ef2ee5d0SMichal Meloun #include "iicbus_if.h" 54ef2ee5d0SMichal Meloun 55ef2ee5d0SMichal Meloun #define I2C_CNFG 0x000 56ef2ee5d0SMichal Meloun #define I2C_CNFG_MSTR_CLR_BUS_ON_TIMEOUT (1 << 15) 57ef2ee5d0SMichal Meloun #define I2C_CNFG_DEBOUNCE_CNT(x) (((x) & 0x07) << 12) 58ef2ee5d0SMichal Meloun #define I2C_CNFG_NEW_MASTER_FSM (1 << 11) 59ef2ee5d0SMichal Meloun #define I2C_CNFG_PACKET_MODE_EN (1 << 10) 60ef2ee5d0SMichal Meloun #define I2C_CNFG_SEND (1 << 9) 61ef2ee5d0SMichal Meloun #define I2C_CNFG_NOACK (1 << 8) 62ef2ee5d0SMichal Meloun #define I2C_CNFG_CMD2 (1 << 7) 63ef2ee5d0SMichal Meloun #define I2C_CNFG_CMD1 (1 << 6) 64ef2ee5d0SMichal Meloun #define I2C_CNFG_START (1 << 5) 65ef2ee5d0SMichal Meloun #define I2C_CNFG_SLV2 (1 << 4) 66ef2ee5d0SMichal Meloun #define I2C_CNFG_LENGTH_SHIFT 1 67ef2ee5d0SMichal Meloun #define I2C_CNFG_LENGTH_MASK 0x7 68ef2ee5d0SMichal Meloun #define I2C_CNFG_A_MOD (1 << 0) 69ef2ee5d0SMichal Meloun 70ef2ee5d0SMichal Meloun #define I2C_CMD_ADDR0 0x004 71ef2ee5d0SMichal Meloun #define I2C_CMD_ADDR1 0x008 72ef2ee5d0SMichal Meloun #define I2C_CMD_DATA1 0x00c 73ef2ee5d0SMichal Meloun #define I2C_CMD_DATA2 0x010 74ef2ee5d0SMichal Meloun #define I2C_STATUS 0x01c 75ef2ee5d0SMichal Meloun #define I2C_SL_CNFG 0x020 76ef2ee5d0SMichal Meloun #define I2C_SL_RCVD 0x024 77ef2ee5d0SMichal Meloun #define I2C_SL_STATUS 0x028 78ef2ee5d0SMichal Meloun #define I2C_SL_ADDR1 0x02c 79ef2ee5d0SMichal Meloun #define I2C_SL_ADDR2 0x030 80ef2ee5d0SMichal Meloun #define I2C_TLOW_SEXT 0x034 81ef2ee5d0SMichal Meloun #define I2C_SL_DELAY_COUNT 0x03c 82ef2ee5d0SMichal Meloun #define I2C_SL_INT_MASK 0x040 83ef2ee5d0SMichal Meloun #define I2C_SL_INT_SOURCE 0x044 84ef2ee5d0SMichal Meloun #define I2C_SL_INT_SET 0x048 85ef2ee5d0SMichal Meloun #define I2C_TX_PACKET_FIFO 0x050 86ef2ee5d0SMichal Meloun #define I2C_RX_FIFO 0x054 87ef2ee5d0SMichal Meloun #define I2C_PACKET_TRANSFER_STATUS 0x058 88ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL 0x05c 89ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_SLV_TX_FIFO_TRIG(x) (((x) & 0x07) << 13) 90ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_SLV_RX_FIFO_TRIG(x) (((x) & 0x07) << 10) 91ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_SLV_TX_FIFO_FLUSH (1 << 9) 92ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_SLV_RX_FIFO_FLUSH (1 << 8) 93ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_TX_FIFO_TRIG(x) (((x) & 0x07) << 5) 94ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_RX_FIFO_TRIG(x) (((x) & 0x07) << 2) 95ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_TX_FIFO_FLUSH (1 << 1) 96ef2ee5d0SMichal Meloun #define I2C_FIFO_CONTROL_RX_FIFO_FLUSH (1 << 0) 97ef2ee5d0SMichal Meloun 98ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS 0x060 99ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS_SLV_XFER_ERR_REASON (1 << 25) 100ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS_TX_FIFO_SLV_EMPTY_CNT(x) (((x) >> 20) & 0xF) 101ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS_RX_FIFO_SLV_FULL_CNT(x) (((x) >> 16) & 0xF) 102ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT(x) (((x) >> 4) & 0xF) 103ef2ee5d0SMichal Meloun #define I2C_FIFO_STATUS_RX_FIFO_FULL_CNT(x) (((x) >> 0) & 0xF) 104ef2ee5d0SMichal Meloun 105ef2ee5d0SMichal Meloun #define I2C_INTERRUPT_MASK_REGISTER 0x064 106ef2ee5d0SMichal Meloun #define I2C_INTERRUPT_STATUS_REGISTER 0x068 107ef2ee5d0SMichal Meloun #define I2C_INT_SLV_ACK_WITHHELD (1 << 28) 108ef2ee5d0SMichal Meloun #define I2C_INT_SLV_RD2WR (1 << 27) 109ef2ee5d0SMichal Meloun #define I2C_INT_SLV_WR2RD (1 << 26) 110ef2ee5d0SMichal Meloun #define I2C_INT_SLV_PKT_XFER_ERR (1 << 25) 111ef2ee5d0SMichal Meloun #define I2C_INT_SLV_TX_BUFFER_REQ (1 << 24) 112ef2ee5d0SMichal Meloun #define I2C_INT_SLV_RX_BUFFER_FILLED (1 << 23) 113ef2ee5d0SMichal Meloun #define I2C_INT_SLV_PACKET_XFER_COMPLETE (1 << 22) 114ef2ee5d0SMichal Meloun #define I2C_INT_SLV_TFIFO_OVF (1 << 21) 115ef2ee5d0SMichal Meloun #define I2C_INT_SLV_RFIFO_UNF (1 << 20) 116ef2ee5d0SMichal Meloun #define I2C_INT_SLV_TFIFO_DATA_REQ (1 << 17) 117ef2ee5d0SMichal Meloun #define I2C_INT_SLV_RFIFO_DATA_REQ (1 << 16) 118ef2ee5d0SMichal Meloun #define I2C_INT_BUS_CLEAR_DONE (1 << 11) 119ef2ee5d0SMichal Meloun #define I2C_INT_TLOW_MEXT_TIMEOUT (1 << 10) 120ef2ee5d0SMichal Meloun #define I2C_INT_TLOW_SEXT_TIMEOUT (1 << 9) 121ef2ee5d0SMichal Meloun #define I2C_INT_TIMEOUT (1 << 8) 122ef2ee5d0SMichal Meloun #define I2C_INT_PACKET_XFER_COMPLETE (1 << 7) 123ef2ee5d0SMichal Meloun #define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1 << 6) 124ef2ee5d0SMichal Meloun #define I2C_INT_TFIFO_OVR (1 << 5) 125ef2ee5d0SMichal Meloun #define I2C_INT_RFIFO_UNF (1 << 4) 126ef2ee5d0SMichal Meloun #define I2C_INT_NOACK (1 << 3) 127ef2ee5d0SMichal Meloun #define I2C_INT_ARB_LOST (1 << 2) 128ef2ee5d0SMichal Meloun #define I2C_INT_TFIFO_DATA_REQ (1 << 1) 129ef2ee5d0SMichal Meloun #define I2C_INT_RFIFO_DATA_REQ (1 << 0) 130ef2ee5d0SMichal Meloun #define I2C_ERROR_MASK (I2C_INT_ARB_LOST | I2C_INT_NOACK | \ 131ef2ee5d0SMichal Meloun I2C_INT_RFIFO_UNF | I2C_INT_TFIFO_OVR) 132ef2ee5d0SMichal Meloun 133ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR 0x06c 134ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16 135ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR_STD_FAST_MODE_MASK 0xffff 136ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR_HSMODE_SHIFT 0 137ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR_HSMODE_MASK 0xffff 138ef2ee5d0SMichal Meloun #define I2C_INTERRUPT_SOURCE_REGISTER 0x070 139ef2ee5d0SMichal Meloun #define I2C_INTERRUPT_SET_REGISTER 0x074 140ef2ee5d0SMichal Meloun #define I2C_SLV_TX_PACKET_FIFO 0x07c 141ef2ee5d0SMichal Meloun #define I2C_SLV_PACKET_STATUS 0x080 142ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_CONFIG 0x084 143ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD(x) (((x) & 0xFF) << 16) 144ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_CONFIG_BC_STOP_COND (1 << 2) 145ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_CONFIG_BC_TERMINATE (1 << 1) 146ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_CONFIG_BC_ENABLE (1 << 0) 147ef2ee5d0SMichal Meloun 148ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_STATUS 0x088 149ef2ee5d0SMichal Meloun #define I2C_BUS_CLEAR_STATUS_BC_STATUS (1 << 0) 150ef2ee5d0SMichal Meloun 151ef2ee5d0SMichal Meloun #define I2C_CONFIG_LOAD 0x08c 152ef2ee5d0SMichal Meloun #define I2C_CONFIG_LOAD_TIMEOUT_CONFIG_LOAD (1 << 2) 153ef2ee5d0SMichal Meloun #define I2C_CONFIG_LOAD_SLV_CONFIG_LOAD (1 << 1) 154ef2ee5d0SMichal Meloun #define I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD (1 << 0) 155ef2ee5d0SMichal Meloun 156ef2ee5d0SMichal Meloun #define I2C_INTERFACE_TIMING_0 0x094 157ef2ee5d0SMichal Meloun #define I2C_INTERFACE_TIMING_1 0x098 158ef2ee5d0SMichal Meloun #define I2C_HS_INTERFACE_TIMING_0 0x09c 159ef2ee5d0SMichal Meloun #define I2C_HS_INTERFACE_TIMING_1 0x0a0 160ef2ee5d0SMichal Meloun 161ef2ee5d0SMichal Meloun /* Protocol header 0 */ 162ef2ee5d0SMichal Meloun #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 163ef2ee5d0SMichal Meloun #define PACKET_HEADER0_HEADER_SIZE_MASK 0x3 164ef2ee5d0SMichal Meloun #define PACKET_HEADER0_PACKET_ID_SHIFT 16 165ef2ee5d0SMichal Meloun #define PACKET_HEADER0_PACKET_ID_MASK 0xff 166ef2ee5d0SMichal Meloun #define PACKET_HEADER0_CONT_ID_SHIFT 12 167ef2ee5d0SMichal Meloun #define PACKET_HEADER0_CONT_ID_MASK 0xf 168ef2ee5d0SMichal Meloun #define PACKET_HEADER0_PROTOCOL_I2C (1 << 4) 169ef2ee5d0SMichal Meloun #define PACKET_HEADER0_TYPE_SHIFT 0 170ef2ee5d0SMichal Meloun #define PACKET_HEADER0_TYPE_MASK 0x7 171ef2ee5d0SMichal Meloun 172ef2ee5d0SMichal Meloun /* I2C header */ 173ef2ee5d0SMichal Meloun #define I2C_HEADER_HIGHSPEED_MODE (1 << 22) 174ef2ee5d0SMichal Meloun #define I2C_HEADER_CONT_ON_NAK (1 << 21) 175ef2ee5d0SMichal Meloun #define I2C_HEADER_SEND_START_BYTE (1 << 20) 176ef2ee5d0SMichal Meloun #define I2C_HEADER_READ (1 << 19) 177ef2ee5d0SMichal Meloun #define I2C_HEADER_10BIT_ADDR (1 << 18) 178ef2ee5d0SMichal Meloun #define I2C_HEADER_IE_ENABLE (1 << 17) 179ef2ee5d0SMichal Meloun #define I2C_HEADER_REPEAT_START (1 << 16) 180ef2ee5d0SMichal Meloun #define I2C_HEADER_CONTINUE_XFER (1 << 15) 181ef2ee5d0SMichal Meloun #define I2C_HEADER_MASTER_ADDR_SHIFT 12 182ef2ee5d0SMichal Meloun #define I2C_HEADER_MASTER_ADDR_MASK 0x7 183ef2ee5d0SMichal Meloun #define I2C_HEADER_SLAVE_ADDR_SHIFT 0 184ef2ee5d0SMichal Meloun #define I2C_HEADER_SLAVE_ADDR_MASK 0x3ff 185ef2ee5d0SMichal Meloun 186ef2ee5d0SMichal Meloun #define I2C_CLK_DIVISOR_STD_FAST_MODE 0x19 187ef2ee5d0SMichal Meloun #define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8 188ef2ee5d0SMichal Meloun 189ef2ee5d0SMichal Meloun #define I2C_REQUEST_TIMEOUT (5 * hz) 190ef2ee5d0SMichal Meloun 191ef2ee5d0SMichal Meloun #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v)) 192ef2ee5d0SMichal Meloun #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r)) 193ef2ee5d0SMichal Meloun 194ef2ee5d0SMichal Meloun #define LOCK(_sc) mtx_lock(&(_sc)->mtx) 195ef2ee5d0SMichal Meloun #define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 196ef2ee5d0SMichal Meloun #define SLEEP(_sc, timeout) \ 197ef2ee5d0SMichal Meloun mtx_sleep(sc, &sc->mtx, 0, "i2cbuswait", timeout); 198ef2ee5d0SMichal Meloun #define LOCK_INIT(_sc) \ 199ef2ee5d0SMichal Meloun mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_i2c", MTX_DEF) 200ef2ee5d0SMichal Meloun #define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) 201ef2ee5d0SMichal Meloun #define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) 202ef2ee5d0SMichal Meloun #define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) 203ef2ee5d0SMichal Meloun 204ef2ee5d0SMichal Meloun static struct ofw_compat_data compat_data[] = { 205ef2ee5d0SMichal Meloun {"nvidia,tegra124-i2c", 1}, 206b9cbd68dSMichal Meloun {"nvidia,tegra210-i2c", 1}, 207ef2ee5d0SMichal Meloun {NULL, 0} 208ef2ee5d0SMichal Meloun }; 209ef2ee5d0SMichal Meloun enum tegra_i2c_xfer_type { 210ef2ee5d0SMichal Meloun XFER_STOP, /* Send stop condition after xfer */ 211ef2ee5d0SMichal Meloun XFER_REPEAT_START, /* Send repeated start after xfer */ 212ef2ee5d0SMichal Meloun XFER_CONTINUE /* Don't send nothing */ 213ef2ee5d0SMichal Meloun } ; 214ef2ee5d0SMichal Meloun 215ef2ee5d0SMichal Meloun struct tegra_i2c_softc { 216ef2ee5d0SMichal Meloun device_t dev; 217ef2ee5d0SMichal Meloun struct mtx mtx; 218ef2ee5d0SMichal Meloun 219ef2ee5d0SMichal Meloun struct resource *mem_res; 220ef2ee5d0SMichal Meloun struct resource *irq_res; 221ef2ee5d0SMichal Meloun void *irq_h; 222ef2ee5d0SMichal Meloun 223ef2ee5d0SMichal Meloun device_t iicbus; 224ef2ee5d0SMichal Meloun clk_t clk; 225ef2ee5d0SMichal Meloun hwreset_t reset; 226ef2ee5d0SMichal Meloun uint32_t core_freq; 227ef2ee5d0SMichal Meloun uint32_t bus_freq; 228ef2ee5d0SMichal Meloun int bus_inuse; 229ef2ee5d0SMichal Meloun 230ef2ee5d0SMichal Meloun struct iic_msg *msg; 231ef2ee5d0SMichal Meloun int msg_idx; 232ef2ee5d0SMichal Meloun uint32_t bus_err; 233ef2ee5d0SMichal Meloun int done; 234ef2ee5d0SMichal Meloun }; 235ef2ee5d0SMichal Meloun 236ef2ee5d0SMichal Meloun static int 237ef2ee5d0SMichal Meloun tegra_i2c_flush_fifo(struct tegra_i2c_softc *sc) 238ef2ee5d0SMichal Meloun { 239ef2ee5d0SMichal Meloun int timeout; 240ef2ee5d0SMichal Meloun uint32_t reg; 241ef2ee5d0SMichal Meloun 242ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_FIFO_CONTROL); 243ef2ee5d0SMichal Meloun reg |= I2C_FIFO_CONTROL_TX_FIFO_FLUSH | I2C_FIFO_CONTROL_RX_FIFO_FLUSH; 244ef2ee5d0SMichal Meloun WR4(sc, I2C_FIFO_CONTROL, reg); 245ef2ee5d0SMichal Meloun 246ef2ee5d0SMichal Meloun timeout = 10; 247ef2ee5d0SMichal Meloun while (timeout > 0) { 248ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_FIFO_CONTROL); 249ef2ee5d0SMichal Meloun reg &= I2C_FIFO_CONTROL_TX_FIFO_FLUSH | 250ef2ee5d0SMichal Meloun I2C_FIFO_CONTROL_RX_FIFO_FLUSH; 251ef2ee5d0SMichal Meloun if (reg == 0) 252ef2ee5d0SMichal Meloun break; 253ef2ee5d0SMichal Meloun DELAY(10); 254ef2ee5d0SMichal Meloun } 255ef2ee5d0SMichal Meloun if (timeout <= 0) { 256ef2ee5d0SMichal Meloun device_printf(sc->dev, "FIFO flush timedout\n"); 257ef2ee5d0SMichal Meloun return (ETIMEDOUT); 258ef2ee5d0SMichal Meloun } 259ef2ee5d0SMichal Meloun return (0); 260ef2ee5d0SMichal Meloun } 261ef2ee5d0SMichal Meloun 262ef2ee5d0SMichal Meloun static void 263ef2ee5d0SMichal Meloun tegra_i2c_setup_clk(struct tegra_i2c_softc *sc, int clk_freq) 264ef2ee5d0SMichal Meloun { 265ef2ee5d0SMichal Meloun int div; 266ef2ee5d0SMichal Meloun 267ef2ee5d0SMichal Meloun div = ((sc->core_freq / clk_freq) / 10) - 1; 268ef2ee5d0SMichal Meloun if ((sc->core_freq / (10 * (div + 1))) > clk_freq) 269ef2ee5d0SMichal Meloun div++; 270ef2ee5d0SMichal Meloun if (div > 65535) 271ef2ee5d0SMichal Meloun div = 65535; 272ef2ee5d0SMichal Meloun WR4(sc, I2C_CLK_DIVISOR, 273ef2ee5d0SMichal Meloun (1 << I2C_CLK_DIVISOR_HSMODE_SHIFT) | 274ef2ee5d0SMichal Meloun (div << I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT)); 275ef2ee5d0SMichal Meloun } 276ef2ee5d0SMichal Meloun 277ef2ee5d0SMichal Meloun static void 278ef2ee5d0SMichal Meloun tegra_i2c_bus_clear(struct tegra_i2c_softc *sc) 279ef2ee5d0SMichal Meloun { 280ef2ee5d0SMichal Meloun int timeout; 281ef2ee5d0SMichal Meloun uint32_t reg, status; 282ef2ee5d0SMichal Meloun 283ef2ee5d0SMichal Meloun WR4(sc, I2C_BUS_CLEAR_CONFIG, 284ef2ee5d0SMichal Meloun I2C_BUS_CLEAR_CONFIG_BC_SCLK_THRESHOLD(18) | 285ef2ee5d0SMichal Meloun I2C_BUS_CLEAR_CONFIG_BC_STOP_COND | 286ef2ee5d0SMichal Meloun I2C_BUS_CLEAR_CONFIG_BC_TERMINATE); 287ef2ee5d0SMichal Meloun 288ef2ee5d0SMichal Meloun WR4(sc, I2C_CONFIG_LOAD, I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD); 289ef2ee5d0SMichal Meloun for (timeout = 1000; timeout > 0; timeout--) { 290ef2ee5d0SMichal Meloun if (RD4(sc, I2C_CONFIG_LOAD) == 0) 291ef2ee5d0SMichal Meloun break; 292ef2ee5d0SMichal Meloun DELAY(10); 293ef2ee5d0SMichal Meloun } 294ef2ee5d0SMichal Meloun if (timeout <= 0) 295ef2ee5d0SMichal Meloun device_printf(sc->dev, "config load timeouted\n"); 296ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_BUS_CLEAR_CONFIG); 297ef2ee5d0SMichal Meloun reg |= I2C_BUS_CLEAR_CONFIG_BC_ENABLE; 298ef2ee5d0SMichal Meloun WR4(sc, I2C_BUS_CLEAR_CONFIG,reg); 299ef2ee5d0SMichal Meloun 300ef2ee5d0SMichal Meloun for (timeout = 1000; timeout > 0; timeout--) { 301ef2ee5d0SMichal Meloun if ((RD4(sc, I2C_BUS_CLEAR_CONFIG) & 302ef2ee5d0SMichal Meloun I2C_BUS_CLEAR_CONFIG_BC_ENABLE) == 0) 303ef2ee5d0SMichal Meloun break; 304ef2ee5d0SMichal Meloun DELAY(10); 305ef2ee5d0SMichal Meloun } 306ef2ee5d0SMichal Meloun if (timeout <= 0) 307ef2ee5d0SMichal Meloun device_printf(sc->dev, "bus clear timeouted\n"); 308ef2ee5d0SMichal Meloun 309ef2ee5d0SMichal Meloun status = RD4(sc, I2C_BUS_CLEAR_STATUS); 310ef2ee5d0SMichal Meloun if ((status & I2C_BUS_CLEAR_STATUS_BC_STATUS) == 0) 311ef2ee5d0SMichal Meloun device_printf(sc->dev, "bus clear failed\n"); 312ef2ee5d0SMichal Meloun } 313ef2ee5d0SMichal Meloun 314ef2ee5d0SMichal Meloun static int 315ef2ee5d0SMichal Meloun tegra_i2c_hw_init(struct tegra_i2c_softc *sc) 316ef2ee5d0SMichal Meloun { 317ef2ee5d0SMichal Meloun int rv, timeout; 318ef2ee5d0SMichal Meloun 319ef2ee5d0SMichal Meloun /* Reset the core. */ 320ef2ee5d0SMichal Meloun rv = hwreset_assert(sc->reset); 321ef2ee5d0SMichal Meloun if (rv != 0) { 322ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot assert reset\n"); 323ef2ee5d0SMichal Meloun return (rv); 324ef2ee5d0SMichal Meloun } 325ef2ee5d0SMichal Meloun DELAY(10); 326ef2ee5d0SMichal Meloun rv = hwreset_deassert(sc->reset); 327ef2ee5d0SMichal Meloun if (rv != 0) { 328ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot clear reset\n"); 329ef2ee5d0SMichal Meloun return (rv); 330ef2ee5d0SMichal Meloun } 331ef2ee5d0SMichal Meloun 332ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0); 333ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, 0xFFFFFFFF); 334ef2ee5d0SMichal Meloun WR4(sc, I2C_CNFG, I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | 335ef2ee5d0SMichal Meloun I2C_CNFG_DEBOUNCE_CNT(2)); 336ef2ee5d0SMichal Meloun 337ef2ee5d0SMichal Meloun tegra_i2c_setup_clk(sc, sc->bus_freq); 338ef2ee5d0SMichal Meloun 339ef2ee5d0SMichal Meloun WR4(sc, I2C_FIFO_CONTROL, I2C_FIFO_CONTROL_TX_FIFO_TRIG(7) | 340ef2ee5d0SMichal Meloun I2C_FIFO_CONTROL_RX_FIFO_TRIG(0)); 341ef2ee5d0SMichal Meloun 342ef2ee5d0SMichal Meloun WR4(sc, I2C_CONFIG_LOAD, I2C_CONFIG_LOAD_MSTR_CONFIG_LOAD); 343ef2ee5d0SMichal Meloun for (timeout = 1000; timeout > 0; timeout--) { 344ef2ee5d0SMichal Meloun if (RD4(sc, I2C_CONFIG_LOAD) == 0) 345ef2ee5d0SMichal Meloun break; 346ef2ee5d0SMichal Meloun DELAY(10); 347ef2ee5d0SMichal Meloun } 348ef2ee5d0SMichal Meloun if (timeout <= 0) 349ef2ee5d0SMichal Meloun device_printf(sc->dev, "config load timeouted\n"); 350ef2ee5d0SMichal Meloun 351ef2ee5d0SMichal Meloun tegra_i2c_bus_clear(sc); 352ef2ee5d0SMichal Meloun return (0); 353ef2ee5d0SMichal Meloun } 354ef2ee5d0SMichal Meloun 355ef2ee5d0SMichal Meloun static int 356ef2ee5d0SMichal Meloun tegra_i2c_tx(struct tegra_i2c_softc *sc) 357ef2ee5d0SMichal Meloun { 358ef2ee5d0SMichal Meloun uint32_t reg; 359ef2ee5d0SMichal Meloun int cnt, i; 360ef2ee5d0SMichal Meloun 361ef2ee5d0SMichal Meloun if (sc->msg_idx >= sc->msg->len) 362ef2ee5d0SMichal Meloun panic("Invalid call to tegra_i2c_tx\n"); 363ef2ee5d0SMichal Meloun 364ef2ee5d0SMichal Meloun while(sc->msg_idx < sc->msg->len) { 365ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_FIFO_STATUS); 366ef2ee5d0SMichal Meloun if (I2C_FIFO_STATUS_TX_FIFO_EMPTY_CNT(reg) == 0) 367ef2ee5d0SMichal Meloun break; 368ef2ee5d0SMichal Meloun cnt = min(4, sc->msg->len - sc->msg_idx); 369ef2ee5d0SMichal Meloun reg = 0; 370ef2ee5d0SMichal Meloun for (i = 0; i < cnt; i++) { 371ef2ee5d0SMichal Meloun reg |= sc->msg->buf[sc->msg_idx] << (i * 8); 372ef2ee5d0SMichal Meloun sc->msg_idx++; 373ef2ee5d0SMichal Meloun } 374ef2ee5d0SMichal Meloun WR4(sc, I2C_TX_PACKET_FIFO, reg); 375ef2ee5d0SMichal Meloun } 376ef2ee5d0SMichal Meloun if (sc->msg_idx >= sc->msg->len) 377ef2ee5d0SMichal Meloun return (0); 378ef2ee5d0SMichal Meloun return (sc->msg->len - sc->msg_idx - 1); 379ef2ee5d0SMichal Meloun } 380ef2ee5d0SMichal Meloun 381ef2ee5d0SMichal Meloun static int 382ef2ee5d0SMichal Meloun tegra_i2c_rx(struct tegra_i2c_softc *sc) 383ef2ee5d0SMichal Meloun { 384ef2ee5d0SMichal Meloun uint32_t reg; 385ef2ee5d0SMichal Meloun int cnt, i; 386ef2ee5d0SMichal Meloun 387ef2ee5d0SMichal Meloun if (sc->msg_idx >= sc->msg->len) 388ef2ee5d0SMichal Meloun panic("Invalid call to tegra_i2c_rx\n"); 389ef2ee5d0SMichal Meloun 390ef2ee5d0SMichal Meloun while(sc->msg_idx < sc->msg->len) { 391ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_FIFO_STATUS); 392ef2ee5d0SMichal Meloun if (I2C_FIFO_STATUS_RX_FIFO_FULL_CNT(reg) == 0) 393ef2ee5d0SMichal Meloun break; 394ef2ee5d0SMichal Meloun cnt = min(4, sc->msg->len - sc->msg_idx); 395ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_RX_FIFO); 396ef2ee5d0SMichal Meloun for (i = 0; i < cnt; i++) { 397ef2ee5d0SMichal Meloun sc->msg->buf[sc->msg_idx] = (reg >> (i * 8)) & 0xFF; 398ef2ee5d0SMichal Meloun sc->msg_idx++; 399ef2ee5d0SMichal Meloun } 400ef2ee5d0SMichal Meloun } 401ef2ee5d0SMichal Meloun 402ef2ee5d0SMichal Meloun if (sc->msg_idx >= sc->msg->len) 403ef2ee5d0SMichal Meloun return (0); 404ef2ee5d0SMichal Meloun return (sc->msg->len - sc->msg_idx - 1); 405ef2ee5d0SMichal Meloun } 406ef2ee5d0SMichal Meloun 407ef2ee5d0SMichal Meloun static void 408ef2ee5d0SMichal Meloun tegra_i2c_intr(void *arg) 409ef2ee5d0SMichal Meloun { 410ef2ee5d0SMichal Meloun struct tegra_i2c_softc *sc; 411ef2ee5d0SMichal Meloun uint32_t status, reg; 412ef2ee5d0SMichal Meloun int rv; 413ef2ee5d0SMichal Meloun 414ef2ee5d0SMichal Meloun sc = (struct tegra_i2c_softc *)arg; 415ef2ee5d0SMichal Meloun 416ef2ee5d0SMichal Meloun LOCK(sc); 417ef2ee5d0SMichal Meloun status = RD4(sc, I2C_INTERRUPT_SOURCE_REGISTER); 418ef2ee5d0SMichal Meloun if (sc->msg == NULL) { 419ef2ee5d0SMichal Meloun /* Unexpected interrupt - disable FIFOs, clear reset. */ 420ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER); 421ef2ee5d0SMichal Meloun reg &= ~I2C_INT_TFIFO_DATA_REQ; 422ef2ee5d0SMichal Meloun reg &= ~I2C_INT_RFIFO_DATA_REQ; 423ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0); 424ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status); 425ef2ee5d0SMichal Meloun UNLOCK(sc); 426ef2ee5d0SMichal Meloun return; 427ef2ee5d0SMichal Meloun } 428ef2ee5d0SMichal Meloun 429ef2ee5d0SMichal Meloun if ((status & I2C_ERROR_MASK) != 0) { 430ef2ee5d0SMichal Meloun if (status & I2C_INT_NOACK) 431ef2ee5d0SMichal Meloun sc->bus_err = IIC_ENOACK; 432ef2ee5d0SMichal Meloun if (status & I2C_INT_ARB_LOST) 433ef2ee5d0SMichal Meloun sc->bus_err = IIC_EBUSERR; 434ef2ee5d0SMichal Meloun if ((status & I2C_INT_TFIFO_OVR) || 435ef2ee5d0SMichal Meloun (status & I2C_INT_RFIFO_UNF)) 436ef2ee5d0SMichal Meloun sc->bus_err = IIC_EBUSERR; 437ef2ee5d0SMichal Meloun sc->done = 1; 438ef2ee5d0SMichal Meloun } else if ((status & I2C_INT_RFIFO_DATA_REQ) && 439ef2ee5d0SMichal Meloun (sc->msg != NULL) && (sc->msg->flags & IIC_M_RD)) { 440ef2ee5d0SMichal Meloun rv = tegra_i2c_rx(sc); 441ef2ee5d0SMichal Meloun if (rv == 0) { 442ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER); 443ef2ee5d0SMichal Meloun reg &= ~I2C_INT_RFIFO_DATA_REQ; 444ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg); 445ef2ee5d0SMichal Meloun } 446ef2ee5d0SMichal Meloun } else if ((status & I2C_INT_TFIFO_DATA_REQ) && 447ef2ee5d0SMichal Meloun (sc->msg != NULL) && !(sc->msg->flags & IIC_M_RD)) { 448ef2ee5d0SMichal Meloun rv = tegra_i2c_tx(sc); 449ef2ee5d0SMichal Meloun if (rv == 0) { 450ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER); 451ef2ee5d0SMichal Meloun reg &= ~I2C_INT_TFIFO_DATA_REQ; 452ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg); 453ef2ee5d0SMichal Meloun } 454ef2ee5d0SMichal Meloun } else if ((status & I2C_INT_RFIFO_DATA_REQ) || 455ef2ee5d0SMichal Meloun (status & I2C_INT_TFIFO_DATA_REQ)) { 456ef2ee5d0SMichal Meloun device_printf(sc->dev, "Unexpected data interrupt: 0x%08X\n", 457ef2ee5d0SMichal Meloun status); 458ef2ee5d0SMichal Meloun reg = RD4(sc, I2C_INTERRUPT_MASK_REGISTER); 459ef2ee5d0SMichal Meloun reg &= ~I2C_INT_TFIFO_DATA_REQ; 460ef2ee5d0SMichal Meloun reg &= ~I2C_INT_RFIFO_DATA_REQ; 461ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, reg); 462ef2ee5d0SMichal Meloun } 463ef2ee5d0SMichal Meloun if (status & I2C_INT_PACKET_XFER_COMPLETE) 464ef2ee5d0SMichal Meloun sc->done = 1; 465ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, status); 466ef2ee5d0SMichal Meloun if (sc->done) { 467ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0); 468ef2ee5d0SMichal Meloun wakeup(&(sc->done)); 469ef2ee5d0SMichal Meloun } 470ef2ee5d0SMichal Meloun UNLOCK(sc); 471ef2ee5d0SMichal Meloun } 472ef2ee5d0SMichal Meloun 473ef2ee5d0SMichal Meloun static void 474ef2ee5d0SMichal Meloun tegra_i2c_start_msg(struct tegra_i2c_softc *sc, struct iic_msg *msg, 475ef2ee5d0SMichal Meloun enum tegra_i2c_xfer_type xtype) 476ef2ee5d0SMichal Meloun { 477ef2ee5d0SMichal Meloun uint32_t tmp, mask; 478ef2ee5d0SMichal Meloun 479ef2ee5d0SMichal Meloun /* Packet header. */ 480ef2ee5d0SMichal Meloun tmp = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | 481ef2ee5d0SMichal Meloun PACKET_HEADER0_PROTOCOL_I2C | 482ef2ee5d0SMichal Meloun (1 << PACKET_HEADER0_CONT_ID_SHIFT) | 483ef2ee5d0SMichal Meloun (1 << PACKET_HEADER0_PACKET_ID_SHIFT); 484ef2ee5d0SMichal Meloun WR4(sc, I2C_TX_PACKET_FIFO, tmp); 485ef2ee5d0SMichal Meloun 486ef2ee5d0SMichal Meloun /* Packet size. */ 487ef2ee5d0SMichal Meloun WR4(sc, I2C_TX_PACKET_FIFO, msg->len - 1); 488ef2ee5d0SMichal Meloun 489ef2ee5d0SMichal Meloun /* I2C header. */ 490ef2ee5d0SMichal Meloun tmp = I2C_HEADER_IE_ENABLE; 491ef2ee5d0SMichal Meloun if (xtype == XFER_CONTINUE) 492ef2ee5d0SMichal Meloun tmp |= I2C_HEADER_CONTINUE_XFER; 493ef2ee5d0SMichal Meloun else if (xtype == XFER_REPEAT_START) 494ef2ee5d0SMichal Meloun tmp |= I2C_HEADER_REPEAT_START; 495ef2ee5d0SMichal Meloun tmp |= msg->slave << I2C_HEADER_SLAVE_ADDR_SHIFT; 496ef2ee5d0SMichal Meloun if (msg->flags & IIC_M_RD) { 497ef2ee5d0SMichal Meloun tmp |= I2C_HEADER_READ; 498ef2ee5d0SMichal Meloun tmp |= 1 << I2C_HEADER_SLAVE_ADDR_SHIFT; 499ef2ee5d0SMichal Meloun } else 500ef2ee5d0SMichal Meloun tmp &= ~(1 << I2C_HEADER_SLAVE_ADDR_SHIFT); 501ef2ee5d0SMichal Meloun 502ef2ee5d0SMichal Meloun WR4(sc, I2C_TX_PACKET_FIFO, tmp); 503ef2ee5d0SMichal Meloun 504ef2ee5d0SMichal Meloun /* Interrupt mask. */ 505ef2ee5d0SMichal Meloun mask = I2C_INT_NOACK | I2C_INT_ARB_LOST | I2C_INT_PACKET_XFER_COMPLETE; 506ef2ee5d0SMichal Meloun if (msg->flags & IIC_M_RD) 507ef2ee5d0SMichal Meloun mask |= I2C_INT_RFIFO_DATA_REQ; 508ef2ee5d0SMichal Meloun else 509ef2ee5d0SMichal Meloun mask |= I2C_INT_TFIFO_DATA_REQ; 510ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, mask); 511ef2ee5d0SMichal Meloun } 512ef2ee5d0SMichal Meloun 513ef2ee5d0SMichal Meloun static int 514ef2ee5d0SMichal Meloun tegra_i2c_poll(struct tegra_i2c_softc *sc) 515ef2ee5d0SMichal Meloun { 516ef2ee5d0SMichal Meloun int timeout; 517ef2ee5d0SMichal Meloun 518ef2ee5d0SMichal Meloun for(timeout = 10000; timeout > 0; timeout--) { 519ef2ee5d0SMichal Meloun UNLOCK(sc); 520ef2ee5d0SMichal Meloun tegra_i2c_intr(sc); 521ef2ee5d0SMichal Meloun LOCK(sc); 522ef2ee5d0SMichal Meloun if (sc->done != 0) 523ef2ee5d0SMichal Meloun break; 524ef2ee5d0SMichal Meloun DELAY(1); 525ef2ee5d0SMichal Meloun } 526ef2ee5d0SMichal Meloun if (timeout <= 0) 527ef2ee5d0SMichal Meloun return (ETIMEDOUT); 528ef2ee5d0SMichal Meloun return (0); 529ef2ee5d0SMichal Meloun } 530ef2ee5d0SMichal Meloun 531ef2ee5d0SMichal Meloun static int 532ef2ee5d0SMichal Meloun tegra_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 533ef2ee5d0SMichal Meloun { 534ef2ee5d0SMichal Meloun int rv, i; 535ef2ee5d0SMichal Meloun struct tegra_i2c_softc *sc; 536ef2ee5d0SMichal Meloun enum tegra_i2c_xfer_type xtype; 537ef2ee5d0SMichal Meloun 538ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 539ef2ee5d0SMichal Meloun LOCK(sc); 540ef2ee5d0SMichal Meloun 541ef2ee5d0SMichal Meloun /* Get the bus. */ 542ef2ee5d0SMichal Meloun while (sc->bus_inuse == 1) 543ef2ee5d0SMichal Meloun SLEEP(sc, 0); 544ef2ee5d0SMichal Meloun sc->bus_inuse = 1; 545ef2ee5d0SMichal Meloun 546ef2ee5d0SMichal Meloun rv = 0; 547ef2ee5d0SMichal Meloun for (i = 0; i < nmsgs; i++) { 548ef2ee5d0SMichal Meloun sc->msg = &msgs[i]; 549ef2ee5d0SMichal Meloun sc->msg_idx = 0; 550ef2ee5d0SMichal Meloun sc->bus_err = 0; 551ef2ee5d0SMichal Meloun sc->done = 0; 552ef2ee5d0SMichal Meloun /* Check for valid parameters. */ 553ef2ee5d0SMichal Meloun if (sc->msg == NULL || sc->msg->buf == NULL || 554ef2ee5d0SMichal Meloun sc->msg->len == 0) { 555ef2ee5d0SMichal Meloun rv = EINVAL; 556ef2ee5d0SMichal Meloun break; 557ef2ee5d0SMichal Meloun } 558ef2ee5d0SMichal Meloun 559ef2ee5d0SMichal Meloun /* Get flags for next transfer. */ 560ef2ee5d0SMichal Meloun if (i == (nmsgs - 1)) { 561ef2ee5d0SMichal Meloun if (msgs[i].flags & IIC_M_NOSTOP) 562ef2ee5d0SMichal Meloun xtype = XFER_CONTINUE; 563ef2ee5d0SMichal Meloun else 564ef2ee5d0SMichal Meloun xtype = XFER_STOP; 565ef2ee5d0SMichal Meloun } else { 566ef2ee5d0SMichal Meloun if (msgs[i + 1].flags & IIC_M_NOSTART) 567ef2ee5d0SMichal Meloun xtype = XFER_CONTINUE; 568ef2ee5d0SMichal Meloun else 569ef2ee5d0SMichal Meloun xtype = XFER_REPEAT_START; 570ef2ee5d0SMichal Meloun } 571ef2ee5d0SMichal Meloun tegra_i2c_start_msg(sc, sc->msg, xtype); 572ef2ee5d0SMichal Meloun if (cold) 573ef2ee5d0SMichal Meloun rv = tegra_i2c_poll(sc); 574ef2ee5d0SMichal Meloun else 575ef2ee5d0SMichal Meloun rv = msleep(&sc->done, &sc->mtx, PZERO, "iic", 576ef2ee5d0SMichal Meloun I2C_REQUEST_TIMEOUT); 577ef2ee5d0SMichal Meloun 578ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_MASK_REGISTER, 0); 579ef2ee5d0SMichal Meloun WR4(sc, I2C_INTERRUPT_STATUS_REGISTER, 0xFFFFFFFF); 580ef2ee5d0SMichal Meloun if (rv == 0) 581ef2ee5d0SMichal Meloun rv = sc->bus_err; 582ef2ee5d0SMichal Meloun if (rv != 0) 583ef2ee5d0SMichal Meloun break; 584ef2ee5d0SMichal Meloun } 585ef2ee5d0SMichal Meloun 586ef2ee5d0SMichal Meloun if (rv != 0) { 587ef2ee5d0SMichal Meloun tegra_i2c_hw_init(sc); 588ef2ee5d0SMichal Meloun tegra_i2c_flush_fifo(sc); 589ef2ee5d0SMichal Meloun } 590ef2ee5d0SMichal Meloun 591ef2ee5d0SMichal Meloun sc->msg = NULL; 592ef2ee5d0SMichal Meloun sc->msg_idx = 0; 593ef2ee5d0SMichal Meloun sc->bus_err = 0; 594ef2ee5d0SMichal Meloun sc->done = 0; 595ef2ee5d0SMichal Meloun 596ef2ee5d0SMichal Meloun /* Wake up the processes that are waiting for the bus. */ 597ef2ee5d0SMichal Meloun sc->bus_inuse = 0; 598ef2ee5d0SMichal Meloun wakeup(sc); 599ef2ee5d0SMichal Meloun UNLOCK(sc); 600ef2ee5d0SMichal Meloun 601ef2ee5d0SMichal Meloun return (rv); 602ef2ee5d0SMichal Meloun } 603ef2ee5d0SMichal Meloun 604ef2ee5d0SMichal Meloun static int 605ef2ee5d0SMichal Meloun tegra_i2c_iicbus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 606ef2ee5d0SMichal Meloun { 607ef2ee5d0SMichal Meloun struct tegra_i2c_softc *sc; 608ef2ee5d0SMichal Meloun int busfreq; 609ef2ee5d0SMichal Meloun 610ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 611ef2ee5d0SMichal Meloun busfreq = IICBUS_GET_FREQUENCY(sc->iicbus, speed); 612ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 613ef2ee5d0SMichal Meloun LOCK(sc); 614ef2ee5d0SMichal Meloun tegra_i2c_setup_clk(sc, busfreq); 615ef2ee5d0SMichal Meloun UNLOCK(sc); 616ef2ee5d0SMichal Meloun return (0); 617ef2ee5d0SMichal Meloun } 618ef2ee5d0SMichal Meloun 619ef2ee5d0SMichal Meloun static int 620ef2ee5d0SMichal Meloun tegra_i2c_probe(device_t dev) 621ef2ee5d0SMichal Meloun { 622ef2ee5d0SMichal Meloun if (!ofw_bus_status_okay(dev)) 623ef2ee5d0SMichal Meloun return (ENXIO); 624ef2ee5d0SMichal Meloun 625ef2ee5d0SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 626ef2ee5d0SMichal Meloun return (ENXIO); 627ef2ee5d0SMichal Meloun 628ef2ee5d0SMichal Meloun return (BUS_PROBE_DEFAULT); 629ef2ee5d0SMichal Meloun } 630ef2ee5d0SMichal Meloun 631ef2ee5d0SMichal Meloun static int 632ef2ee5d0SMichal Meloun tegra_i2c_attach(device_t dev) 633ef2ee5d0SMichal Meloun { 634ef2ee5d0SMichal Meloun int rv, rid; 635ef2ee5d0SMichal Meloun phandle_t node; 636ef2ee5d0SMichal Meloun struct tegra_i2c_softc *sc; 637ef2ee5d0SMichal Meloun uint64_t freq; 638ef2ee5d0SMichal Meloun 639ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 640ef2ee5d0SMichal Meloun sc->dev = dev; 641ef2ee5d0SMichal Meloun node = ofw_bus_get_node(dev); 642ef2ee5d0SMichal Meloun 643ef2ee5d0SMichal Meloun LOCK_INIT(sc); 644ef2ee5d0SMichal Meloun 645ef2ee5d0SMichal Meloun /* Get the memory resource for the register mapping. */ 646ef2ee5d0SMichal Meloun rid = 0; 647ef2ee5d0SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 648ef2ee5d0SMichal Meloun RF_ACTIVE); 649ef2ee5d0SMichal Meloun if (sc->mem_res == NULL) { 650ef2ee5d0SMichal Meloun device_printf(dev, "Cannot map registers.\n"); 651ef2ee5d0SMichal Meloun rv = ENXIO; 652ef2ee5d0SMichal Meloun goto fail; 653ef2ee5d0SMichal Meloun } 654ef2ee5d0SMichal Meloun 655ef2ee5d0SMichal Meloun /* Allocate our IRQ resource. */ 656ef2ee5d0SMichal Meloun rid = 0; 657ef2ee5d0SMichal Meloun sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 658ef2ee5d0SMichal Meloun RF_ACTIVE); 659ef2ee5d0SMichal Meloun if (sc->irq_res == NULL) { 660ef2ee5d0SMichal Meloun device_printf(dev, "Cannot allocate interrupt.\n"); 661ef2ee5d0SMichal Meloun rv = ENXIO; 662ef2ee5d0SMichal Meloun goto fail; 663ef2ee5d0SMichal Meloun } 664ef2ee5d0SMichal Meloun 665ef2ee5d0SMichal Meloun /* FDT resources. */ 666dac93553SMichal Meloun rv = clk_get_by_ofw_name(dev, 0, "div-clk", &sc->clk); 667ef2ee5d0SMichal Meloun if (rv != 0) { 668ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get i2c clock: %d\n", rv); 669ef2ee5d0SMichal Meloun goto fail; 670ef2ee5d0SMichal Meloun } 671dac93553SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "i2c", &sc->reset); 672ef2ee5d0SMichal Meloun if (rv != 0) { 673ef2ee5d0SMichal Meloun device_printf(sc->dev, "Cannot get i2c reset\n"); 674ef2ee5d0SMichal Meloun return (ENXIO); 675ef2ee5d0SMichal Meloun } 676ef2ee5d0SMichal Meloun rv = OF_getencprop(node, "clock-frequency", &sc->bus_freq, 677ef2ee5d0SMichal Meloun sizeof(sc->bus_freq)); 678ef2ee5d0SMichal Meloun if (rv != sizeof(sc->bus_freq)) { 679ef2ee5d0SMichal Meloun sc->bus_freq = 100000; 680ef2ee5d0SMichal Meloun } 681ef2ee5d0SMichal Meloun 682ef2ee5d0SMichal Meloun /* Request maximum frequency for I2C block 136MHz (408MHz / 3). */ 683ef2ee5d0SMichal Meloun rv = clk_set_freq(sc->clk, 136000000, CLK_SET_ROUND_DOWN); 684ef2ee5d0SMichal Meloun if (rv != 0) { 685ef2ee5d0SMichal Meloun device_printf(dev, "Cannot set clock frequency\n"); 686ef2ee5d0SMichal Meloun goto fail; 687ef2ee5d0SMichal Meloun } 688ef2ee5d0SMichal Meloun rv = clk_get_freq(sc->clk, &freq); 689ef2ee5d0SMichal Meloun if (rv != 0) { 690ef2ee5d0SMichal Meloun device_printf(dev, "Cannot get clock frequency\n"); 691ef2ee5d0SMichal Meloun goto fail; 692ef2ee5d0SMichal Meloun } 693ef2ee5d0SMichal Meloun sc->core_freq = (uint32_t)freq; 694ef2ee5d0SMichal Meloun 695ef2ee5d0SMichal Meloun rv = clk_enable(sc->clk); 696ef2ee5d0SMichal Meloun if (rv != 0) { 697ef2ee5d0SMichal Meloun device_printf(dev, "Cannot enable clock: %d\n", rv); 698ef2ee5d0SMichal Meloun goto fail; 699ef2ee5d0SMichal Meloun } 700ef2ee5d0SMichal Meloun 701ef2ee5d0SMichal Meloun /* Init hardware. */ 702ef2ee5d0SMichal Meloun rv = tegra_i2c_hw_init(sc); 703ef2ee5d0SMichal Meloun if (rv) { 704ef2ee5d0SMichal Meloun device_printf(dev, "tegra_i2c_activate failed\n"); 705ef2ee5d0SMichal Meloun goto fail; 706ef2ee5d0SMichal Meloun } 707ef2ee5d0SMichal Meloun 708ef2ee5d0SMichal Meloun /* Setup interrupt. */ 709ef2ee5d0SMichal Meloun rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 710ef2ee5d0SMichal Meloun NULL, tegra_i2c_intr, sc, &sc->irq_h); 711ef2ee5d0SMichal Meloun if (rv) { 712ef2ee5d0SMichal Meloun device_printf(dev, "Cannot setup interrupt.\n"); 713ef2ee5d0SMichal Meloun goto fail; 714ef2ee5d0SMichal Meloun } 715ef2ee5d0SMichal Meloun 716ef2ee5d0SMichal Meloun /* Attach the iicbus. */ 7175b56413dSWarner Losh sc->iicbus = device_add_child(dev, "iicbus", DEVICE_UNIT_ANY); 718ef2ee5d0SMichal Meloun if (sc->iicbus == NULL) { 719ef2ee5d0SMichal Meloun device_printf(dev, "Could not allocate iicbus instance.\n"); 720ef2ee5d0SMichal Meloun rv = ENXIO; 721ef2ee5d0SMichal Meloun goto fail; 722ef2ee5d0SMichal Meloun } 723ef2ee5d0SMichal Meloun 724ef2ee5d0SMichal Meloun /* Probe and attach the iicbus. */ 725*18250ec6SJohn Baldwin bus_attach_children(dev); 726*18250ec6SJohn Baldwin return (0); 727ef2ee5d0SMichal Meloun 728ef2ee5d0SMichal Meloun fail: 729ef2ee5d0SMichal Meloun if (sc->irq_h != NULL) 730ef2ee5d0SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 731ef2ee5d0SMichal Meloun if (sc->irq_res != NULL) 732ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 733ef2ee5d0SMichal Meloun if (sc->mem_res != NULL) 734ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 735ef2ee5d0SMichal Meloun LOCK_DESTROY(sc); 736ef2ee5d0SMichal Meloun 737ef2ee5d0SMichal Meloun return (rv); 738ef2ee5d0SMichal Meloun } 739ef2ee5d0SMichal Meloun 740ef2ee5d0SMichal Meloun static int 741ef2ee5d0SMichal Meloun tegra_i2c_detach(device_t dev) 742ef2ee5d0SMichal Meloun { 743ef2ee5d0SMichal Meloun struct tegra_i2c_softc *sc; 744d412c076SJohn Baldwin int error; 745d412c076SJohn Baldwin 746d412c076SJohn Baldwin error = bus_generic_detach(dev); 747d412c076SJohn Baldwin if (error != 0) 748d412c076SJohn Baldwin return (error); 749ef2ee5d0SMichal Meloun 750ef2ee5d0SMichal Meloun sc = device_get_softc(dev); 751ef2ee5d0SMichal Meloun tegra_i2c_hw_init(sc); 752ef2ee5d0SMichal Meloun if (sc->irq_h != NULL) 753ef2ee5d0SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_h); 754ef2ee5d0SMichal Meloun if (sc->irq_res != NULL) 755ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 756ef2ee5d0SMichal Meloun if (sc->mem_res != NULL) 757ef2ee5d0SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 758ef2ee5d0SMichal Meloun 759ef2ee5d0SMichal Meloun LOCK_DESTROY(sc); 760d412c076SJohn Baldwin return (0); 761ef2ee5d0SMichal Meloun } 762ef2ee5d0SMichal Meloun 763ef2ee5d0SMichal Meloun static phandle_t 764ef2ee5d0SMichal Meloun tegra_i2c_get_node(device_t bus, device_t dev) 765ef2ee5d0SMichal Meloun { 766ef2ee5d0SMichal Meloun 767ef2ee5d0SMichal Meloun /* Share controller node with iibus device. */ 768ef2ee5d0SMichal Meloun return (ofw_bus_get_node(bus)); 769ef2ee5d0SMichal Meloun } 770ef2ee5d0SMichal Meloun 771ef2ee5d0SMichal Meloun static device_method_t tegra_i2c_methods[] = { 772ef2ee5d0SMichal Meloun /* Device interface */ 773ef2ee5d0SMichal Meloun DEVMETHOD(device_probe, tegra_i2c_probe), 774ef2ee5d0SMichal Meloun DEVMETHOD(device_attach, tegra_i2c_attach), 775ef2ee5d0SMichal Meloun DEVMETHOD(device_detach, tegra_i2c_detach), 776ef2ee5d0SMichal Meloun 777ef2ee5d0SMichal Meloun /* Bus interface */ 778ef2ee5d0SMichal Meloun DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 779ef2ee5d0SMichal Meloun DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 780ef2ee5d0SMichal Meloun DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 781ef2ee5d0SMichal Meloun DEVMETHOD(bus_release_resource, bus_generic_release_resource), 782ef2ee5d0SMichal Meloun DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 783ef2ee5d0SMichal Meloun DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 784ef2ee5d0SMichal Meloun DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), 785ef2ee5d0SMichal Meloun DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 786ef2ee5d0SMichal Meloun DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 787ef2ee5d0SMichal Meloun 788ef2ee5d0SMichal Meloun /* OFW methods */ 789ef2ee5d0SMichal Meloun DEVMETHOD(ofw_bus_get_node, tegra_i2c_get_node), 790ef2ee5d0SMichal Meloun 791ef2ee5d0SMichal Meloun /* iicbus interface */ 792ef2ee5d0SMichal Meloun DEVMETHOD(iicbus_callback, iicbus_null_callback), 793ef2ee5d0SMichal Meloun DEVMETHOD(iicbus_reset, tegra_i2c_iicbus_reset), 794ef2ee5d0SMichal Meloun DEVMETHOD(iicbus_transfer, tegra_i2c_transfer), 795ef2ee5d0SMichal Meloun 796ef2ee5d0SMichal Meloun DEVMETHOD_END 797ef2ee5d0SMichal Meloun }; 798ef2ee5d0SMichal Meloun 7994bda238aSMichal Meloun static DEFINE_CLASS_0(iichb, tegra_i2c_driver, tegra_i2c_methods, 8004bda238aSMichal Meloun sizeof(struct tegra_i2c_softc)); 801289f133bSJohn Baldwin EARLY_DRIVER_MODULE(tegra_iic, simplebus, tegra_i2c_driver, NULL, NULL, 73); 802