162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Mellanox BlueField I2C bus driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2020 Mellanox Technologies, Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/acpi.h> 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/i2c.h> 1462306a36Sopenharmony_ci#include <linux/io.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/mutex.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/string.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Defines what functionality is present. */ 2362306a36Sopenharmony_ci#define MLXBF_I2C_FUNC_SMBUS_BLOCK \ 2462306a36Sopenharmony_ci (I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define MLXBF_I2C_FUNC_SMBUS_DEFAULT \ 2762306a36Sopenharmony_ci (I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | \ 2862306a36Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK | \ 2962306a36Sopenharmony_ci I2C_FUNC_SMBUS_PROC_CALL) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define MLXBF_I2C_FUNC_ALL \ 3262306a36Sopenharmony_ci (MLXBF_I2C_FUNC_SMBUS_DEFAULT | MLXBF_I2C_FUNC_SMBUS_BLOCK | \ 3362306a36Sopenharmony_ci I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SLAVE) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* Shared resources info in BlueField platforms. */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define MLXBF_I2C_COALESCE_TYU_ADDR 0x02801300 3862306a36Sopenharmony_ci#define MLXBF_I2C_COALESCE_TYU_SIZE 0x010 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_TYU_ADDR 0x02802000 4162306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_TYU_SIZE 0x100 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_TYU_ADDR 0x02800358 4462306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_TYU_SIZE 0x008 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_YU_ADDR 0x02800c30 4762306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_YU_SIZE 0x00c 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_RSH_YU_ADDR 0x13409824 5062306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_RSH_YU_SIZE 0x00c 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define MLXBF_I2C_SHARED_RES_MAX 3 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Note that the following SMBus, CAUSE, GPIO and PLL register addresses 5662306a36Sopenharmony_ci * refer to their respective offsets relative to the corresponding 5762306a36Sopenharmony_ci * memory-mapped region whose addresses are specified in either the DT or 5862306a36Sopenharmony_ci * the ACPI tables or above. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * SMBus Master core clock frequency. Timing configurations are 6362306a36Sopenharmony_ci * strongly dependent on the core clock frequency of the SMBus 6462306a36Sopenharmony_ci * Master. Default value is set to 400MHz. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_ci#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000) 6762306a36Sopenharmony_ci/* Reference clock for Bluefield - 156 MHz. */ 6862306a36Sopenharmony_ci#define MLXBF_I2C_PLL_IN_FREQ 156250000ULL 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Constant used to determine the PLL frequency. */ 7162306a36Sopenharmony_ci#define MLNXBF_I2C_COREPLL_CONST 16384ULL 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000ULL 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* PLL registers. */ 7662306a36Sopenharmony_ci#define MLXBF_I2C_CORE_PLL_REG1 0x4 7762306a36Sopenharmony_ci#define MLXBF_I2C_CORE_PLL_REG2 0x8 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* OR cause register. */ 8062306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_OR_EVTEN0 0x14 8162306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_OR_CLEAR 0x18 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* Arbiter Cause Register. */ 8462306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_ARBITER 0x1c 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * Cause Status flags. Note that those bits might be considered 8862306a36Sopenharmony_ci * as interrupt enabled bits. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Transaction ended with STOP. */ 9262306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_TRANSACTION_ENDED BIT(0) 9362306a36Sopenharmony_ci/* Master arbitration lost. */ 9462306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_ARBITRATION_LOST BIT(1) 9562306a36Sopenharmony_ci/* Unexpected start detected. */ 9662306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_UNEXPECTED_START BIT(2) 9762306a36Sopenharmony_ci/* Unexpected stop detected. */ 9862306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_UNEXPECTED_STOP BIT(3) 9962306a36Sopenharmony_ci/* Wait for transfer continuation. */ 10062306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_WAIT_FOR_FW_DATA BIT(4) 10162306a36Sopenharmony_ci/* Failed to generate STOP. */ 10262306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_PUT_STOP_FAILED BIT(5) 10362306a36Sopenharmony_ci/* Failed to generate START. */ 10462306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_PUT_START_FAILED BIT(6) 10562306a36Sopenharmony_ci/* Clock toggle completed. */ 10662306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_CLK_TOGGLE_DONE BIT(7) 10762306a36Sopenharmony_ci/* Transfer timeout occurred. */ 10862306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_FW_TIMEOUT BIT(8) 10962306a36Sopenharmony_ci/* Master busy bit reset. */ 11062306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_GW_BUSY_FALL BIT(9) 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK GENMASK(9, 0) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_MASTER_STATUS_ERROR \ 11562306a36Sopenharmony_ci (MLXBF_I2C_CAUSE_M_ARBITRATION_LOST | \ 11662306a36Sopenharmony_ci MLXBF_I2C_CAUSE_UNEXPECTED_START | \ 11762306a36Sopenharmony_ci MLXBF_I2C_CAUSE_UNEXPECTED_STOP | \ 11862306a36Sopenharmony_ci MLXBF_I2C_CAUSE_PUT_STOP_FAILED | \ 11962306a36Sopenharmony_ci MLXBF_I2C_CAUSE_PUT_START_FAILED | \ 12062306a36Sopenharmony_ci MLXBF_I2C_CAUSE_CLK_TOGGLE_DONE | \ 12162306a36Sopenharmony_ci MLXBF_I2C_CAUSE_M_FW_TIMEOUT) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * Slave cause status flags. Note that those bits might be considered 12562306a36Sopenharmony_ci * as interrupt enabled bits. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* Write transaction received successfully. */ 12962306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_WRITE_SUCCESS BIT(0) 13062306a36Sopenharmony_ci/* Read transaction received, waiting for response. */ 13162306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE BIT(13) 13262306a36Sopenharmony_ci/* Slave busy bit reset. */ 13362306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_S_GW_BUSY_FALL BIT(18) 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* Cause coalesce registers. */ 13662306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_COALESCE_0 0x00 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT 3 13962306a36Sopenharmony_ci#define MLXBF_I2C_CAUSE_YU_SLAVE_BIT 1 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/* Functional enable register. */ 14262306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_0_FUNC_EN_0 0x28 14362306a36Sopenharmony_ci/* Force OE enable register. */ 14462306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_0_FORCE_OE_EN 0x30 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * Note that Smbus GWs are on GPIOs 30:25. Two pins are used to control 14762306a36Sopenharmony_ci * SDA/SCL lines: 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * SMBUS GW0 -> bits[26:25] 15062306a36Sopenharmony_ci * SMBUS GW1 -> bits[28:27] 15162306a36Sopenharmony_ci * SMBUS GW2 -> bits[30:29] 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_PINS(num) (25 + ((num) << 1)) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* Note that gw_id can be 0,1 or 2. */ 15662306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_MASK(num) \ 15762306a36Sopenharmony_ci (0xffffffff & (~(0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num)))) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(num, val) \ 16062306a36Sopenharmony_ci ((val) & MLXBF_I2C_GPIO_SMBUS_GW_MASK(num)) 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(num, val) \ 16362306a36Sopenharmony_ci ((val) | (0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num))) 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* 16662306a36Sopenharmony_ci * Defines SMBus operating frequency and core clock frequency. 16762306a36Sopenharmony_ci * According to ADB files, default values are compliant to 100KHz SMBus 16862306a36Sopenharmony_ci * @ 400MHz core clock. The driver should be able to calculate core 16962306a36Sopenharmony_ci * frequency based on PLL parameters. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_FREQ MLXBF_I2C_TYU_PLL_OUT_FREQ 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* Core PLL TYU configuration. */ 17462306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(15, 3) 17562306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(19, 16) 17662306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(25, 20) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* Core PLL YU configuration. */ 17962306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_F_YU_MASK GENMASK(25, 0) 18062306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0) 18162306a36Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26) 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* SMBus timing parameters. */ 18462306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 18562306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 18662306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 18762306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c 18862306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 18962306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 19062306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci#define MLXBF_I2C_SHIFT_0 0 19362306a36Sopenharmony_ci#define MLXBF_I2C_SHIFT_8 8 19462306a36Sopenharmony_ci#define MLXBF_I2C_SHIFT_16 16 19562306a36Sopenharmony_ci#define MLXBF_I2C_SHIFT_24 24 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#define MLXBF_I2C_MASK_8 GENMASK(7, 0) 19862306a36Sopenharmony_ci#define MLXBF_I2C_MASK_16 GENMASK(15, 0) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci#define MLXBF_I2C_MST_ADDR_OFFSET 0x200 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* SMBus Master GW. */ 20362306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_GW 0x0 20462306a36Sopenharmony_ci/* Number of bytes received and sent. */ 20562306a36Sopenharmony_ci#define MLXBF_I2C_YU_SMBUS_RS_BYTES 0x100 20662306a36Sopenharmony_ci#define MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES 0x10c 20762306a36Sopenharmony_ci/* Packet error check (PEC) value. */ 20862306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_PEC 0x104 20962306a36Sopenharmony_ci/* Status bits (ACK/NACK/FW Timeout). */ 21062306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x108 21162306a36Sopenharmony_ci/* SMbus Master Finite State Machine. */ 21262306a36Sopenharmony_ci#define MLXBF_I2C_YU_SMBUS_MASTER_FSM 0x110 21362306a36Sopenharmony_ci#define MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM 0x100 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci/* SMBus master GW control bits offset in MLXBF_I2C_SMBUS_MASTER_GW[31:3]. */ 21662306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_LOCK_BIT BIT(31) /* Lock bit. */ 21762306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_BUSY_BIT BIT(30) /* Busy bit. */ 21862306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_START_BIT BIT(29) /* Control start. */ 21962306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_CTL_WRITE_BIT BIT(28) /* Control write phase. */ 22062306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_CTL_READ_BIT BIT(19) /* Control read phase. */ 22162306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_STOP_BIT BIT(3) /* Control stop. */ 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE \ 22462306a36Sopenharmony_ci (MLXBF_I2C_MASTER_LOCK_BIT | MLXBF_I2C_MASTER_BUSY_BIT | \ 22562306a36Sopenharmony_ci MLXBF_I2C_MASTER_START_BIT | MLXBF_I2C_MASTER_STOP_BIT) 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE_WRITE \ 22862306a36Sopenharmony_ci (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_WRITE_BIT) 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE_READ \ 23162306a36Sopenharmony_ci (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_READ_BIT) 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes */ 23462306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte when set to 1 */ 23562306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Control parse expected bytes */ 23662306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address */ 23762306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* SMBus master GW Data descriptor. */ 24062306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x80 24162306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_DESC_SIZE 0x80 /* Size in bytes. */ 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci/* Maximum bytes to read/write per SMBus transaction. */ 24462306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_R_LENGTH MLXBF_I2C_MASTER_DATA_DESC_SIZE 24562306a36Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_W_LENGTH (MLXBF_I2C_MASTER_DATA_DESC_SIZE - 1) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* All bytes were transmitted. */ 24862306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_BYTE_CNT_DONE BIT(0) 24962306a36Sopenharmony_ci/* NACK received. */ 25062306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_NACK_RCV BIT(1) 25162306a36Sopenharmony_ci/* Slave's byte count >128 bytes. */ 25262306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_READ_ERR BIT(2) 25362306a36Sopenharmony_ci/* Timeout occurred. */ 25462306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_FW_TIMEOUT BIT(3) 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS_MASK GENMASK(3, 0) 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS_ERROR \ 25962306a36Sopenharmony_ci (MLXBF_I2C_SMBUS_STATUS_NACK_RCV | \ 26062306a36Sopenharmony_ci MLXBF_I2C_SMBUS_STATUS_READ_ERR | \ 26162306a36Sopenharmony_ci MLXBF_I2C_SMBUS_STATUS_FW_TIMEOUT) 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK BIT(31) 26462306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK BIT(15) 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci#define MLXBF_I2C_SLV_ADDR_OFFSET 0x400 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* SMBus slave GW. */ 26962306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_GW 0x0 27062306a36Sopenharmony_ci/* Number of bytes received and sent from/to master. */ 27162306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x100 27262306a36Sopenharmony_ci/* Packet error check (PEC) value. */ 27362306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x104 27462306a36Sopenharmony_ci/* SMBus slave Finite State Machine (FSM). */ 27562306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x110 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * Should be set when all raised causes handled, and cleared by HW on 27862306a36Sopenharmony_ci * every new cause. 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_READY 0x12c 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* SMBus slave GW control bits offset in MLXBF_I2C_SMBUS_SLAVE_GW[31:19]. */ 28362306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_BUSY_BIT BIT(30) /* Busy bit. */ 28462306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_WRITE_BIT BIT(29) /* Control write enable. */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_ENABLE \ 28762306a36Sopenharmony_ci (MLXBF_I2C_SLAVE_BUSY_BIT | MLXBF_I2C_SLAVE_WRITE_BIT) 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT 22 /* Number of bytes to write. */ 29062306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_SEND_PEC_SHIFT 21 /* Send PEC byte shift. */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* SMBus slave GW Data descriptor. */ 29362306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x80 29462306a36Sopenharmony_ci#define MLXBF_I2C_SLAVE_DATA_DESC_SIZE 0x80 /* Size in bytes. */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/* SMbus slave configuration registers. */ 29762306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x114 29862306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT 16 29962306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT BIT(7) 30062306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0) 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * Timeout is given in microsends. Note also that timeout handling is not 30462306a36Sopenharmony_ci * exact. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */ 30762306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* Polling frequency in microseconds. */ 31062306a36Sopenharmony_ci#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_1 1 31362306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_2 2 31462306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_3 3 31562306a36Sopenharmony_ci#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci/* Helper macro to define an I2C resource parameters. */ 31862306a36Sopenharmony_ci#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ 31962306a36Sopenharmony_ci { \ 32062306a36Sopenharmony_ci .start = (addr), \ 32162306a36Sopenharmony_ci .end = (addr) + (size) - 1, \ 32262306a36Sopenharmony_ci .name = (str) \ 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cienum { 32662306a36Sopenharmony_ci MLXBF_I2C_TIMING_100KHZ = 100000, 32762306a36Sopenharmony_ci MLXBF_I2C_TIMING_400KHZ = 400000, 32862306a36Sopenharmony_ci MLXBF_I2C_TIMING_1000KHZ = 1000000, 32962306a36Sopenharmony_ci}; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cienum { 33262306a36Sopenharmony_ci MLXBF_I2C_F_READ = BIT(0), 33362306a36Sopenharmony_ci MLXBF_I2C_F_WRITE = BIT(1), 33462306a36Sopenharmony_ci MLXBF_I2C_F_NORESTART = BIT(3), 33562306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), 33662306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), 33762306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_PEC = BIT(6), 33862306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* Mellanox BlueField chip type. */ 34262306a36Sopenharmony_cienum mlxbf_i2c_chip_type { 34362306a36Sopenharmony_ci MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ 34462306a36Sopenharmony_ci MLXBF_I2C_CHIP_TYPE_2, /* Mellanox BlueField-2 chip. */ 34562306a36Sopenharmony_ci MLXBF_I2C_CHIP_TYPE_3 /* Mellanox BlueField-3 chip. */ 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* List of chip resources that are being accessed by the driver. */ 34962306a36Sopenharmony_cienum { 35062306a36Sopenharmony_ci MLXBF_I2C_SMBUS_RES, 35162306a36Sopenharmony_ci MLXBF_I2C_MST_CAUSE_RES, 35262306a36Sopenharmony_ci MLXBF_I2C_SLV_CAUSE_RES, 35362306a36Sopenharmony_ci MLXBF_I2C_COALESCE_RES, 35462306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_RES, 35562306a36Sopenharmony_ci MLXBF_I2C_SMBUS_MST_RES, 35662306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLV_RES, 35762306a36Sopenharmony_ci MLXBF_I2C_COREPLL_RES, 35862306a36Sopenharmony_ci MLXBF_I2C_GPIO_RES, 35962306a36Sopenharmony_ci MLXBF_I2C_END_RES 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* Encapsulates timing parameters. */ 36362306a36Sopenharmony_cistruct mlxbf_i2c_timings { 36462306a36Sopenharmony_ci u16 scl_high; /* Clock high period. */ 36562306a36Sopenharmony_ci u16 scl_low; /* Clock low period. */ 36662306a36Sopenharmony_ci u8 sda_rise; /* Data rise time. */ 36762306a36Sopenharmony_ci u8 sda_fall; /* Data fall time. */ 36862306a36Sopenharmony_ci u8 scl_rise; /* Clock rise time. */ 36962306a36Sopenharmony_ci u8 scl_fall; /* Clock fall time. */ 37062306a36Sopenharmony_ci u16 hold_start; /* Hold time after (REPEATED) START. */ 37162306a36Sopenharmony_ci u16 hold_data; /* Data hold time. */ 37262306a36Sopenharmony_ci u16 setup_start; /* REPEATED START condition setup time. */ 37362306a36Sopenharmony_ci u16 setup_stop; /* STOP condition setup time. */ 37462306a36Sopenharmony_ci u16 setup_data; /* Data setup time. */ 37562306a36Sopenharmony_ci u16 pad; /* Padding. */ 37662306a36Sopenharmony_ci u16 buf; /* Bus free time between STOP and START. */ 37762306a36Sopenharmony_ci u16 thigh_max; /* Thigh max. */ 37862306a36Sopenharmony_ci u32 timeout; /* Detect clock low timeout. */ 37962306a36Sopenharmony_ci}; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistruct mlxbf_i2c_smbus_operation { 38262306a36Sopenharmony_ci u32 flags; 38362306a36Sopenharmony_ci u32 length; /* Buffer length in bytes. */ 38462306a36Sopenharmony_ci u8 *buffer; 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistruct mlxbf_i2c_smbus_request { 38862306a36Sopenharmony_ci u8 slave; 38962306a36Sopenharmony_ci u8 operation_cnt; 39062306a36Sopenharmony_ci struct mlxbf_i2c_smbus_operation operation[MLXBF_I2C_SMBUS_MAX_OP_CNT]; 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistruct mlxbf_i2c_resource { 39462306a36Sopenharmony_ci void __iomem *io; 39562306a36Sopenharmony_ci struct resource *params; 39662306a36Sopenharmony_ci struct mutex *lock; /* Mutex to protect mlxbf_i2c_resource. */ 39762306a36Sopenharmony_ci u8 type; 39862306a36Sopenharmony_ci}; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistruct mlxbf_i2c_chip_info { 40162306a36Sopenharmony_ci enum mlxbf_i2c_chip_type type; 40262306a36Sopenharmony_ci /* Chip shared resources that are being used by the I2C controller. */ 40362306a36Sopenharmony_ci struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Callback to calculate the core PLL frequency. */ 40662306a36Sopenharmony_ci u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* Registers' address offset */ 40962306a36Sopenharmony_ci u32 smbus_master_rs_bytes_off; 41062306a36Sopenharmony_ci u32 smbus_master_fsm_off; 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistruct mlxbf_i2c_priv { 41462306a36Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip; 41562306a36Sopenharmony_ci struct i2c_adapter adap; 41662306a36Sopenharmony_ci struct mlxbf_i2c_resource *smbus; 41762306a36Sopenharmony_ci struct mlxbf_i2c_resource *timer; 41862306a36Sopenharmony_ci struct mlxbf_i2c_resource *mst; 41962306a36Sopenharmony_ci struct mlxbf_i2c_resource *slv; 42062306a36Sopenharmony_ci struct mlxbf_i2c_resource *mst_cause; 42162306a36Sopenharmony_ci struct mlxbf_i2c_resource *slv_cause; 42262306a36Sopenharmony_ci struct mlxbf_i2c_resource *coalesce; 42362306a36Sopenharmony_ci u64 frequency; /* Core frequency in Hz. */ 42462306a36Sopenharmony_ci int bus; /* Physical bus identifier. */ 42562306a36Sopenharmony_ci int irq; 42662306a36Sopenharmony_ci struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT]; 42762306a36Sopenharmony_ci u32 resource_version; 42862306a36Sopenharmony_ci}; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci/* Core PLL frequency. */ 43162306a36Sopenharmony_cistatic u64 mlxbf_i2c_corepll_frequency; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic struct resource mlxbf_i2c_coalesce_tyu_params = 43462306a36Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COALESCE_TYU_ADDR, 43562306a36Sopenharmony_ci MLXBF_I2C_COALESCE_TYU_SIZE, 43662306a36Sopenharmony_ci "COALESCE_MEM"); 43762306a36Sopenharmony_cistatic struct resource mlxbf_i2c_corepll_tyu_params = 43862306a36Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_TYU_ADDR, 43962306a36Sopenharmony_ci MLXBF_I2C_COREPLL_TYU_SIZE, 44062306a36Sopenharmony_ci "COREPLL_MEM"); 44162306a36Sopenharmony_cistatic struct resource mlxbf_i2c_corepll_yu_params = 44262306a36Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_YU_ADDR, 44362306a36Sopenharmony_ci MLXBF_I2C_COREPLL_YU_SIZE, 44462306a36Sopenharmony_ci "COREPLL_MEM"); 44562306a36Sopenharmony_cistatic struct resource mlxbf_i2c_corepll_rsh_yu_params = 44662306a36Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_RSH_YU_ADDR, 44762306a36Sopenharmony_ci MLXBF_I2C_COREPLL_RSH_YU_SIZE, 44862306a36Sopenharmony_ci "COREPLL_MEM"); 44962306a36Sopenharmony_cistatic struct resource mlxbf_i2c_gpio_tyu_params = 45062306a36Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_GPIO_TYU_ADDR, 45162306a36Sopenharmony_ci MLXBF_I2C_GPIO_TYU_SIZE, 45262306a36Sopenharmony_ci "GPIO_MEM"); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cistatic struct mutex mlxbf_i2c_coalesce_lock; 45562306a36Sopenharmony_cistatic struct mutex mlxbf_i2c_corepll_lock; 45662306a36Sopenharmony_cistatic struct mutex mlxbf_i2c_gpio_lock; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = { 45962306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 46062306a36Sopenharmony_ci .params = &mlxbf_i2c_coalesce_tyu_params, 46162306a36Sopenharmony_ci .lock = &mlxbf_i2c_coalesce_lock, 46262306a36Sopenharmony_ci .type = MLXBF_I2C_COALESCE_RES 46362306a36Sopenharmony_ci }, 46462306a36Sopenharmony_ci {} 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_corepll_res[] = { 46862306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 46962306a36Sopenharmony_ci .params = &mlxbf_i2c_corepll_tyu_params, 47062306a36Sopenharmony_ci .lock = &mlxbf_i2c_corepll_lock, 47162306a36Sopenharmony_ci .type = MLXBF_I2C_COREPLL_RES 47262306a36Sopenharmony_ci }, 47362306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_2] = { 47462306a36Sopenharmony_ci .params = &mlxbf_i2c_corepll_yu_params, 47562306a36Sopenharmony_ci .lock = &mlxbf_i2c_corepll_lock, 47662306a36Sopenharmony_ci .type = MLXBF_I2C_COREPLL_RES, 47762306a36Sopenharmony_ci }, 47862306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_3] = { 47962306a36Sopenharmony_ci .params = &mlxbf_i2c_corepll_rsh_yu_params, 48062306a36Sopenharmony_ci .lock = &mlxbf_i2c_corepll_lock, 48162306a36Sopenharmony_ci .type = MLXBF_I2C_COREPLL_RES, 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci}; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_gpio_res[] = { 48662306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 48762306a36Sopenharmony_ci .params = &mlxbf_i2c_gpio_tyu_params, 48862306a36Sopenharmony_ci .lock = &mlxbf_i2c_gpio_lock, 48962306a36Sopenharmony_ci .type = MLXBF_I2C_GPIO_RES 49062306a36Sopenharmony_ci }, 49162306a36Sopenharmony_ci {} 49262306a36Sopenharmony_ci}; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic u8 mlxbf_i2c_bus_count; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic struct mutex mlxbf_i2c_bus_lock; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* 49962306a36Sopenharmony_ci * Function to poll a set of bits at a specific address; it checks whether 50062306a36Sopenharmony_ci * the bits are equal to zero when eq_zero is set to 'true', and not equal 50162306a36Sopenharmony_ci * to zero when eq_zero is set to 'false'. 50262306a36Sopenharmony_ci * Note that the timeout is given in microseconds. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask, 50562306a36Sopenharmony_ci bool eq_zero, u32 timeout) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci u32 bits; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci do { 51262306a36Sopenharmony_ci bits = readl(io + addr) & mask; 51362306a36Sopenharmony_ci if (eq_zero ? bits == 0 : bits != 0) 51462306a36Sopenharmony_ci return eq_zero ? 1 : bits; 51562306a36Sopenharmony_ci udelay(MLXBF_I2C_POLL_FREQ_IN_USEC); 51662306a36Sopenharmony_ci } while (timeout-- != 0); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci return 0; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* 52262306a36Sopenharmony_ci * SW must make sure that the SMBus Master GW is idle before starting 52362306a36Sopenharmony_ci * a transaction. Accordingly, this function polls the Master FSM stop 52462306a36Sopenharmony_ci * bit; it returns false when the bit is asserted, true if not. 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cistatic bool mlxbf_i2c_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK; 52962306a36Sopenharmony_ci u32 addr = priv->chip->smbus_master_fsm_off; 53062306a36Sopenharmony_ci u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (mlxbf_i2c_poll(priv->mst->io, addr, mask, true, timeout)) 53362306a36Sopenharmony_ci return true; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci return false; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci/* 53962306a36Sopenharmony_ci * wait for the lock to be released before acquiring it. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_cistatic bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci if (mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, 54462306a36Sopenharmony_ci MLXBF_I2C_MASTER_LOCK_BIT, true, 54562306a36Sopenharmony_ci MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT)) 54662306a36Sopenharmony_ci return true; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return false; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci /* Clear the gw to clear the lock */ 55462306a36Sopenharmony_ci writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic bool mlxbf_i2c_smbus_transaction_success(u32 master_status, 55862306a36Sopenharmony_ci u32 cause_status) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci /* 56162306a36Sopenharmony_ci * When transaction ended with STOP, all bytes were transmitted, 56262306a36Sopenharmony_ci * and no NACK received, then the transaction ended successfully. 56362306a36Sopenharmony_ci * On the other hand, when the GW is configured with the stop bit 56462306a36Sopenharmony_ci * de-asserted then the SMBus expects the following GW configuration 56562306a36Sopenharmony_ci * for transfer continuation. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci if ((cause_status & MLXBF_I2C_CAUSE_WAIT_FOR_FW_DATA) || 56862306a36Sopenharmony_ci ((cause_status & MLXBF_I2C_CAUSE_TRANSACTION_ENDED) && 56962306a36Sopenharmony_ci (master_status & MLXBF_I2C_SMBUS_STATUS_BYTE_CNT_DONE) && 57062306a36Sopenharmony_ci !(master_status & MLXBF_I2C_SMBUS_STATUS_NACK_RCV))) 57162306a36Sopenharmony_ci return true; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return false; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/* 57762306a36Sopenharmony_ci * Poll SMBus master status and return transaction status, 57862306a36Sopenharmony_ci * i.e. whether succeeded or failed. I2C and SMBus fault codes 57962306a36Sopenharmony_ci * are returned as negative numbers from most calls, with zero 58062306a36Sopenharmony_ci * or some positive number indicating a non-fault return. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_cistatic int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci u32 master_status_bits; 58562306a36Sopenharmony_ci u32 cause_status_bits; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* 58862306a36Sopenharmony_ci * GW busy bit is raised by the driver and cleared by the HW 58962306a36Sopenharmony_ci * when the transaction is completed. The busy bit is a good 59062306a36Sopenharmony_ci * indicator of transaction status. So poll the busy bit, and 59162306a36Sopenharmony_ci * then read the cause and master status bits to determine if 59262306a36Sopenharmony_ci * errors occurred during the transaction. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, 59562306a36Sopenharmony_ci MLXBF_I2C_MASTER_BUSY_BIT, true, 59662306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMEOUT); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* Read cause status bits. */ 59962306a36Sopenharmony_ci cause_status_bits = readl(priv->mst_cause->io + 60062306a36Sopenharmony_ci MLXBF_I2C_CAUSE_ARBITER); 60162306a36Sopenharmony_ci cause_status_bits &= MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* 60462306a36Sopenharmony_ci * Parse both Cause and Master GW bits, then return transaction status. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci master_status_bits = readl(priv->mst->io + 60862306a36Sopenharmony_ci MLXBF_I2C_SMBUS_MASTER_STATUS); 60962306a36Sopenharmony_ci master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci if (mlxbf_i2c_smbus_transaction_success(master_status_bits, 61262306a36Sopenharmony_ci cause_status_bits)) 61362306a36Sopenharmony_ci return 0; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* 61662306a36Sopenharmony_ci * In case of timeout on GW busy, the ISR will clear busy bit but 61762306a36Sopenharmony_ci * transaction ended bits cause will not be set so the transaction 61862306a36Sopenharmony_ci * fails. Then, we must check Master GW status bits. 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci if ((master_status_bits & MLXBF_I2C_SMBUS_MASTER_STATUS_ERROR) && 62162306a36Sopenharmony_ci (cause_status_bits & (MLXBF_I2C_CAUSE_TRANSACTION_ENDED | 62262306a36Sopenharmony_ci MLXBF_I2C_CAUSE_M_GW_BUSY_FALL))) 62362306a36Sopenharmony_ci return -EIO; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (cause_status_bits & MLXBF_I2C_CAUSE_MASTER_STATUS_ERROR) 62662306a36Sopenharmony_ci return -EAGAIN; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return -ETIMEDOUT; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, 63262306a36Sopenharmony_ci const u8 *data, u8 length, u32 addr, 63362306a36Sopenharmony_ci bool is_master) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci u8 offset, aligned_length; 63662306a36Sopenharmony_ci u32 data32; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci aligned_length = round_up(length, 4); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * Copy data bytes from 4-byte aligned source buffer. 64262306a36Sopenharmony_ci * Data copied to the Master GW Data Descriptor MUST be shifted 64362306a36Sopenharmony_ci * left so the data starts at the MSB of the descriptor registers 64462306a36Sopenharmony_ci * as required by the underlying hardware. Enable byte swapping 64562306a36Sopenharmony_ci * when writing data bytes to the 32 * 32-bit HW Data registers 64662306a36Sopenharmony_ci * a.k.a Master GW Data Descriptor. 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci for (offset = 0; offset < aligned_length; offset += sizeof(u32)) { 64962306a36Sopenharmony_ci data32 = *((u32 *)(data + offset)); 65062306a36Sopenharmony_ci if (is_master) 65162306a36Sopenharmony_ci iowrite32be(data32, priv->mst->io + addr + offset); 65262306a36Sopenharmony_ci else 65362306a36Sopenharmony_ci iowrite32be(data32, priv->slv->io + addr + offset); 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, 65862306a36Sopenharmony_ci u8 *data, u8 length, u32 addr, 65962306a36Sopenharmony_ci bool is_master) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci u32 data32, mask; 66262306a36Sopenharmony_ci u8 byte, offset; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci mask = sizeof(u32) - 1; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* 66762306a36Sopenharmony_ci * Data bytes in the Master GW Data Descriptor are shifted left 66862306a36Sopenharmony_ci * so the data starts at the MSB of the descriptor registers as 66962306a36Sopenharmony_ci * set by the underlying hardware. Enable byte swapping while 67062306a36Sopenharmony_ci * reading data bytes from the 32 * 32-bit HW Data registers 67162306a36Sopenharmony_ci * a.k.a Master GW Data Descriptor. 67262306a36Sopenharmony_ci */ 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) { 67562306a36Sopenharmony_ci if (is_master) 67662306a36Sopenharmony_ci data32 = ioread32be(priv->mst->io + addr + offset); 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci data32 = ioread32be(priv->slv->io + addr + offset); 67962306a36Sopenharmony_ci *((u32 *)(data + offset)) = data32; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (!(length & mask)) 68362306a36Sopenharmony_ci return; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (is_master) 68662306a36Sopenharmony_ci data32 = ioread32be(priv->mst->io + addr + offset); 68762306a36Sopenharmony_ci else 68862306a36Sopenharmony_ci data32 = ioread32be(priv->slv->io + addr + offset); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci for (byte = 0; byte < (length & mask); byte++) { 69162306a36Sopenharmony_ci data[offset + byte] = data32 & GENMASK(7, 0); 69262306a36Sopenharmony_ci data32 = ror32(data32, MLXBF_I2C_SHIFT_8); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, 69762306a36Sopenharmony_ci u8 len, u8 block_en, u8 pec_en, bool read) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci u32 command; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* Set Master GW control word. */ 70262306a36Sopenharmony_ci if (read) { 70362306a36Sopenharmony_ci command = MLXBF_I2C_MASTER_ENABLE_READ; 70462306a36Sopenharmony_ci command |= rol32(len, MLXBF_I2C_MASTER_READ_SHIFT); 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci command = MLXBF_I2C_MASTER_ENABLE_WRITE; 70762306a36Sopenharmony_ci command |= rol32(len, MLXBF_I2C_MASTER_WRITE_SHIFT); 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci command |= rol32(slave, MLXBF_I2C_MASTER_SLV_ADDR_SHIFT); 71062306a36Sopenharmony_ci command |= rol32(block_en, MLXBF_I2C_MASTER_PARSE_EXP_SHIFT); 71162306a36Sopenharmony_ci command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* Clear status bits. */ 71462306a36Sopenharmony_ci writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_STATUS); 71562306a36Sopenharmony_ci /* Set the cause data. */ 71662306a36Sopenharmony_ci writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 71762306a36Sopenharmony_ci /* Zero PEC byte. */ 71862306a36Sopenharmony_ci writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_PEC); 71962306a36Sopenharmony_ci /* Zero byte count. */ 72062306a36Sopenharmony_ci writel(0x0, priv->mst->io + priv->chip->smbus_master_rs_bytes_off); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* GW activation. */ 72362306a36Sopenharmony_ci writel(command, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * Poll master status and check status bits. An ACK is sent when 72762306a36Sopenharmony_ci * completing writing data to the bus (Master 'byte_count_done' bit 72862306a36Sopenharmony_ci * is set to 1). 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci return mlxbf_i2c_smbus_check_status(priv); 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int 73462306a36Sopenharmony_cimlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, 73562306a36Sopenharmony_ci struct mlxbf_i2c_smbus_request *request) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci u8 data_desc[MLXBF_I2C_MASTER_DATA_DESC_SIZE] = { 0 }; 73862306a36Sopenharmony_ci u8 op_idx, data_idx, data_len, write_len, read_len; 73962306a36Sopenharmony_ci struct mlxbf_i2c_smbus_operation *operation; 74062306a36Sopenharmony_ci u8 read_en, write_en, block_en, pec_en; 74162306a36Sopenharmony_ci u8 slave, flags, addr; 74262306a36Sopenharmony_ci u8 *read_buf; 74362306a36Sopenharmony_ci int ret = 0; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (request->operation_cnt > MLXBF_I2C_SMBUS_MAX_OP_CNT) 74662306a36Sopenharmony_ci return -EINVAL; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci read_buf = NULL; 74962306a36Sopenharmony_ci data_idx = 0; 75062306a36Sopenharmony_ci read_en = 0; 75162306a36Sopenharmony_ci write_en = 0; 75262306a36Sopenharmony_ci write_len = 0; 75362306a36Sopenharmony_ci read_len = 0; 75462306a36Sopenharmony_ci block_en = 0; 75562306a36Sopenharmony_ci pec_en = 0; 75662306a36Sopenharmony_ci slave = request->slave & GENMASK(6, 0); 75762306a36Sopenharmony_ci addr = slave << 1; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* 76062306a36Sopenharmony_ci * Try to acquire the smbus gw lock before any reads of the GW register since 76162306a36Sopenharmony_ci * a read sets the lock. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv))) 76462306a36Sopenharmony_ci return -EBUSY; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Check whether the HW is idle */ 76762306a36Sopenharmony_ci if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) { 76862306a36Sopenharmony_ci ret = -EBUSY; 76962306a36Sopenharmony_ci goto out_unlock; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci /* Set first byte. */ 77362306a36Sopenharmony_ci data_desc[data_idx++] = addr; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci for (op_idx = 0; op_idx < request->operation_cnt; op_idx++) { 77662306a36Sopenharmony_ci operation = &request->operation[op_idx]; 77762306a36Sopenharmony_ci flags = operation->flags; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * Note that read and write operations might be handled by a 78162306a36Sopenharmony_ci * single command. If the MLXBF_I2C_F_SMBUS_OPERATION is set 78262306a36Sopenharmony_ci * then write command byte and set the optional SMBus specific 78362306a36Sopenharmony_ci * bits such as block_en and pec_en. These bits MUST be 78462306a36Sopenharmony_ci * submitted by the first operation only. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci if (op_idx == 0 && flags & MLXBF_I2C_F_SMBUS_OPERATION) { 78762306a36Sopenharmony_ci block_en = flags & MLXBF_I2C_F_SMBUS_BLOCK; 78862306a36Sopenharmony_ci pec_en = flags & MLXBF_I2C_F_SMBUS_PEC; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (flags & MLXBF_I2C_F_WRITE) { 79262306a36Sopenharmony_ci write_en = 1; 79362306a36Sopenharmony_ci write_len += operation->length; 79462306a36Sopenharmony_ci if (data_idx + operation->length > 79562306a36Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_SIZE) { 79662306a36Sopenharmony_ci ret = -ENOBUFS; 79762306a36Sopenharmony_ci goto out_unlock; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci memcpy(data_desc + data_idx, 80062306a36Sopenharmony_ci operation->buffer, operation->length); 80162306a36Sopenharmony_ci data_idx += operation->length; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci /* 80462306a36Sopenharmony_ci * We assume that read operations are performed only once per 80562306a36Sopenharmony_ci * SMBus transaction. *TBD* protect this statement so it won't 80662306a36Sopenharmony_ci * be executed twice? or return an error if we try to read more 80762306a36Sopenharmony_ci * than once? 80862306a36Sopenharmony_ci */ 80962306a36Sopenharmony_ci if (flags & MLXBF_I2C_F_READ) { 81062306a36Sopenharmony_ci read_en = 1; 81162306a36Sopenharmony_ci /* Subtract 1 as required by HW. */ 81262306a36Sopenharmony_ci read_len = operation->length - 1; 81362306a36Sopenharmony_ci read_buf = operation->buffer; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* Set Master GW data descriptor. */ 81862306a36Sopenharmony_ci data_len = write_len + 1; /* Add one byte of the slave address. */ 81962306a36Sopenharmony_ci /* 82062306a36Sopenharmony_ci * Note that data_len cannot be 0. Indeed, the slave address byte 82162306a36Sopenharmony_ci * must be written to the data registers. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, (const u8 *)data_desc, data_len, 82462306a36Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (write_en) { 82762306a36Sopenharmony_ci ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en, 82862306a36Sopenharmony_ci pec_en, 0); 82962306a36Sopenharmony_ci if (ret) 83062306a36Sopenharmony_ci goto out_unlock; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (read_en) { 83462306a36Sopenharmony_ci /* Write slave address to Master GW data descriptor. */ 83562306a36Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1, 83662306a36Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); 83762306a36Sopenharmony_ci ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en, 83862306a36Sopenharmony_ci pec_en, 1); 83962306a36Sopenharmony_ci if (!ret) { 84062306a36Sopenharmony_ci /* Get Master GW data descriptor. */ 84162306a36Sopenharmony_ci mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1, 84262306a36Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* Get data from Master GW data descriptor. */ 84562306a36Sopenharmony_ci memcpy(read_buf, data_desc, read_len + 1); 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* 84962306a36Sopenharmony_ci * After a read operation the SMBus FSM ps (present state) 85062306a36Sopenharmony_ci * needs to be 'manually' reset. This should be removed in 85162306a36Sopenharmony_ci * next tag integration. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_ci writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK, 85462306a36Sopenharmony_ci priv->mst->io + priv->chip->smbus_master_fsm_off); 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ciout_unlock: 85862306a36Sopenharmony_ci mlxbf_i2c_smbus_master_unlock(priv); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return ret; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci/* I2C SMBus protocols. */ 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void 86662306a36Sopenharmony_cimlxbf_i2c_smbus_quick_command(struct mlxbf_i2c_smbus_request *request, 86762306a36Sopenharmony_ci u8 read) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_1; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci request->operation[0].length = 0; 87262306a36Sopenharmony_ci request->operation[0].flags = MLXBF_I2C_F_WRITE; 87362306a36Sopenharmony_ci request->operation[0].flags |= read ? MLXBF_I2C_F_READ : 0; 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic void mlxbf_i2c_smbus_byte_func(struct mlxbf_i2c_smbus_request *request, 87762306a36Sopenharmony_ci u8 *data, bool read, bool pec_check) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_1; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci request->operation[0].length = 1; 88262306a36Sopenharmony_ci request->operation[0].length += pec_check; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci request->operation[0].flags = MLXBF_I2C_F_SMBUS_OPERATION; 88562306a36Sopenharmony_ci request->operation[0].flags |= read ? 88662306a36Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 88762306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci request->operation[0].buffer = data; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void 89362306a36Sopenharmony_cimlxbf_i2c_smbus_data_byte_func(struct mlxbf_i2c_smbus_request *request, 89462306a36Sopenharmony_ci u8 *command, u8 *data, bool read, bool pec_check) 89562306a36Sopenharmony_ci{ 89662306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci request->operation[0].length = 1; 89962306a36Sopenharmony_ci request->operation[0].flags = 90062306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 90162306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 90262306a36Sopenharmony_ci request->operation[0].buffer = command; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci request->operation[1].length = 1; 90562306a36Sopenharmony_ci request->operation[1].length += pec_check; 90662306a36Sopenharmony_ci request->operation[1].flags = read ? 90762306a36Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 90862306a36Sopenharmony_ci request->operation[1].buffer = data; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_cistatic void 91262306a36Sopenharmony_cimlxbf_i2c_smbus_data_word_func(struct mlxbf_i2c_smbus_request *request, 91362306a36Sopenharmony_ci u8 *command, u8 *data, bool read, bool pec_check) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci request->operation[0].length = 1; 91862306a36Sopenharmony_ci request->operation[0].flags = 91962306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 92062306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 92162306a36Sopenharmony_ci request->operation[0].buffer = command; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci request->operation[1].length = 2; 92462306a36Sopenharmony_ci request->operation[1].length += pec_check; 92562306a36Sopenharmony_ci request->operation[1].flags = read ? 92662306a36Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 92762306a36Sopenharmony_ci request->operation[1].buffer = data; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic void 93162306a36Sopenharmony_cimlxbf_i2c_smbus_i2c_block_func(struct mlxbf_i2c_smbus_request *request, 93262306a36Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, bool read, 93362306a36Sopenharmony_ci bool pec_check) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci request->operation[0].length = 1; 93862306a36Sopenharmony_ci request->operation[0].flags = 93962306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 94062306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 94162306a36Sopenharmony_ci request->operation[0].buffer = command; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* 94462306a36Sopenharmony_ci * As specified in the standard, the max number of bytes to read/write 94562306a36Sopenharmony_ci * per block operation is 32 bytes. In Golan code, the controller can 94662306a36Sopenharmony_ci * read up to 128 bytes and write up to 127 bytes. 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_ci request->operation[1].length = 94962306a36Sopenharmony_ci (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 95062306a36Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 95162306a36Sopenharmony_ci request->operation[1].flags = read ? 95262306a36Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 95362306a36Sopenharmony_ci /* 95462306a36Sopenharmony_ci * Skip the first data byte, which corresponds to the number of bytes 95562306a36Sopenharmony_ci * to read/write. 95662306a36Sopenharmony_ci */ 95762306a36Sopenharmony_ci request->operation[1].buffer = data + 1; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci *data_len = request->operation[1].length; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci /* Set the number of byte to read. This will be used by userspace. */ 96262306a36Sopenharmony_ci if (read) 96362306a36Sopenharmony_ci data[0] = *data_len; 96462306a36Sopenharmony_ci} 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_cistatic void mlxbf_i2c_smbus_block_func(struct mlxbf_i2c_smbus_request *request, 96762306a36Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, 96862306a36Sopenharmony_ci bool read, bool pec_check) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci request->operation[0].length = 1; 97362306a36Sopenharmony_ci request->operation[0].flags = 97462306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 97562306a36Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 97662306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 97762306a36Sopenharmony_ci request->operation[0].buffer = command; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci request->operation[1].length = 98062306a36Sopenharmony_ci (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 98162306a36Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 98262306a36Sopenharmony_ci request->operation[1].flags = read ? 98362306a36Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 98462306a36Sopenharmony_ci request->operation[1].buffer = data + 1; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci *data_len = request->operation[1].length; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* Set the number of bytes to read. This will be used by userspace. */ 98962306a36Sopenharmony_ci if (read) 99062306a36Sopenharmony_ci data[0] = *data_len; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic void 99462306a36Sopenharmony_cimlxbf_i2c_smbus_process_call_func(struct mlxbf_i2c_smbus_request *request, 99562306a36Sopenharmony_ci u8 *command, u8 *data, bool pec_check) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_3; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci request->operation[0].length = 1; 100062306a36Sopenharmony_ci request->operation[0].flags = 100162306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 100262306a36Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 100362306a36Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 100462306a36Sopenharmony_ci request->operation[0].buffer = command; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci request->operation[1].length = 2; 100762306a36Sopenharmony_ci request->operation[1].flags = MLXBF_I2C_F_WRITE; 100862306a36Sopenharmony_ci request->operation[1].buffer = data; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci request->operation[2].length = 3; 101162306a36Sopenharmony_ci request->operation[2].flags = MLXBF_I2C_F_READ; 101262306a36Sopenharmony_ci request->operation[2].buffer = data; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic void 101662306a36Sopenharmony_cimlxbf_i2c_smbus_blk_process_call_func(struct mlxbf_i2c_smbus_request *request, 101762306a36Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, 101862306a36Sopenharmony_ci bool pec_check) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci u32 length; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_3; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci request->operation[0].length = 1; 102562306a36Sopenharmony_ci request->operation[0].flags = 102662306a36Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 102762306a36Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 102862306a36Sopenharmony_ci request->operation[0].flags |= (pec_check) ? MLXBF_I2C_F_SMBUS_PEC : 0; 102962306a36Sopenharmony_ci request->operation[0].buffer = command; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci length = (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 103262306a36Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci request->operation[1].length = length - pec_check; 103562306a36Sopenharmony_ci request->operation[1].flags = MLXBF_I2C_F_WRITE; 103662306a36Sopenharmony_ci request->operation[1].buffer = data; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci request->operation[2].length = length; 103962306a36Sopenharmony_ci request->operation[2].flags = MLXBF_I2C_F_READ; 104062306a36Sopenharmony_ci request->operation[2].buffer = data; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci *data_len = length; /* including PEC byte. */ 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci/* Initialization functions. */ 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic bool mlxbf_i2c_has_chip_type(struct mlxbf_i2c_priv *priv, u8 type) 104862306a36Sopenharmony_ci{ 104962306a36Sopenharmony_ci return priv->chip->type == type; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic struct mlxbf_i2c_resource * 105362306a36Sopenharmony_cimlxbf_i2c_get_shared_resource(struct mlxbf_i2c_priv *priv, u8 type) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 105662306a36Sopenharmony_ci struct mlxbf_i2c_resource *res; 105762306a36Sopenharmony_ci u8 res_idx = 0; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci for (res_idx = 0; res_idx < MLXBF_I2C_SHARED_RES_MAX; res_idx++) { 106062306a36Sopenharmony_ci res = chip->shared_res[res_idx]; 106162306a36Sopenharmony_ci if (res && res->type == type) 106262306a36Sopenharmony_ci return res; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return NULL; 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_cistatic int mlxbf_i2c_init_resource(struct platform_device *pdev, 106962306a36Sopenharmony_ci struct mlxbf_i2c_resource **res, 107062306a36Sopenharmony_ci u8 type) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct mlxbf_i2c_resource *tmp_res; 107362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (!res || *res || type >= MLXBF_I2C_END_RES) 107662306a36Sopenharmony_ci return -EINVAL; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci tmp_res = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), 107962306a36Sopenharmony_ci GFP_KERNEL); 108062306a36Sopenharmony_ci if (!tmp_res) 108162306a36Sopenharmony_ci return -ENOMEM; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci tmp_res->io = devm_platform_get_and_ioremap_resource(pdev, type, &tmp_res->params); 108462306a36Sopenharmony_ci if (IS_ERR(tmp_res->io)) { 108562306a36Sopenharmony_ci devm_kfree(dev, tmp_res); 108662306a36Sopenharmony_ci return PTR_ERR(tmp_res->io); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci tmp_res->type = type; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci *res = tmp_res; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic u32 mlxbf_i2c_get_ticks(struct mlxbf_i2c_priv *priv, u64 nanoseconds, 109762306a36Sopenharmony_ci bool minimum) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci u64 frequency; 110062306a36Sopenharmony_ci u32 ticks; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci /* 110362306a36Sopenharmony_ci * Compute ticks as follow: 110462306a36Sopenharmony_ci * 110562306a36Sopenharmony_ci * Ticks 110662306a36Sopenharmony_ci * Time = --------- x 10^9 => Ticks = Time x Frequency x 10^-9 110762306a36Sopenharmony_ci * Frequency 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci frequency = priv->frequency; 111062306a36Sopenharmony_ci ticks = (nanoseconds * frequency) / MLXBF_I2C_FREQUENCY_1GHZ; 111162306a36Sopenharmony_ci /* 111262306a36Sopenharmony_ci * The number of ticks is rounded down and if minimum is equal to 1 111362306a36Sopenharmony_ci * then add one tick. 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci if (minimum) 111662306a36Sopenharmony_ci ticks++; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return ticks; 111962306a36Sopenharmony_ci} 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_cistatic u32 mlxbf_i2c_set_timer(struct mlxbf_i2c_priv *priv, u64 nsec, bool opt, 112262306a36Sopenharmony_ci u32 mask, u8 shift) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci u32 val = (mlxbf_i2c_get_ticks(priv, nsec, opt) & mask) << shift; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci return val; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, 113062306a36Sopenharmony_ci const struct mlxbf_i2c_timings *timings) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci u32 timer; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->scl_high, 113562306a36Sopenharmony_ci false, MLXBF_I2C_MASK_16, 113662306a36Sopenharmony_ci MLXBF_I2C_SHIFT_0); 113762306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_low, 113862306a36Sopenharmony_ci false, MLXBF_I2C_MASK_16, 113962306a36Sopenharmony_ci MLXBF_I2C_SHIFT_16); 114062306a36Sopenharmony_ci writel(timer, priv->timer->io + 114162306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false, 114462306a36Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_0); 114562306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->sda_fall, false, 114662306a36Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_8); 114762306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_rise, false, 114862306a36Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16); 114962306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false, 115062306a36Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24); 115162306a36Sopenharmony_ci writel(timer, priv->timer->io + 115262306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true, 115562306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 115662306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true, 115762306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 115862306a36Sopenharmony_ci writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_THOLD); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true, 116162306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 116262306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true, 116362306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 116462306a36Sopenharmony_ci writel(timer, priv->timer->io + 116562306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP); 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true, 116862306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 116962306a36Sopenharmony_ci writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->buf, false, 117262306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 117362306a36Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false, 117462306a36Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 117562306a36Sopenharmony_ci writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci timer = timings->timeout; 117862306a36Sopenharmony_ci writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT); 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cienum mlxbf_i2c_timings_config { 118262306a36Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_100KHZ, 118362306a36Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_400KHZ, 118462306a36Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_1000KHZ, 118562306a36Sopenharmony_ci}; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci/* 118862306a36Sopenharmony_ci * Note that the mlxbf_i2c_timings->timeout value is not related to the 118962306a36Sopenharmony_ci * bus frequency, it is impacted by the time it takes the driver to 119062306a36Sopenharmony_ci * complete data transmission before transaction abort. 119162306a36Sopenharmony_ci */ 119262306a36Sopenharmony_cistatic const struct mlxbf_i2c_timings mlxbf_i2c_timings[] = { 119362306a36Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_100KHZ] = { 119462306a36Sopenharmony_ci .scl_high = 4810, 119562306a36Sopenharmony_ci .scl_low = 5000, 119662306a36Sopenharmony_ci .hold_start = 4000, 119762306a36Sopenharmony_ci .setup_start = 4800, 119862306a36Sopenharmony_ci .setup_stop = 4000, 119962306a36Sopenharmony_ci .setup_data = 250, 120062306a36Sopenharmony_ci .sda_rise = 50, 120162306a36Sopenharmony_ci .sda_fall = 50, 120262306a36Sopenharmony_ci .scl_rise = 50, 120362306a36Sopenharmony_ci .scl_fall = 50, 120462306a36Sopenharmony_ci .hold_data = 300, 120562306a36Sopenharmony_ci .buf = 20000, 120662306a36Sopenharmony_ci .thigh_max = 5000, 120762306a36Sopenharmony_ci .timeout = 106500 120862306a36Sopenharmony_ci }, 120962306a36Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_400KHZ] = { 121062306a36Sopenharmony_ci .scl_high = 1011, 121162306a36Sopenharmony_ci .scl_low = 1300, 121262306a36Sopenharmony_ci .hold_start = 600, 121362306a36Sopenharmony_ci .setup_start = 700, 121462306a36Sopenharmony_ci .setup_stop = 600, 121562306a36Sopenharmony_ci .setup_data = 100, 121662306a36Sopenharmony_ci .sda_rise = 50, 121762306a36Sopenharmony_ci .sda_fall = 50, 121862306a36Sopenharmony_ci .scl_rise = 50, 121962306a36Sopenharmony_ci .scl_fall = 50, 122062306a36Sopenharmony_ci .hold_data = 300, 122162306a36Sopenharmony_ci .buf = 20000, 122262306a36Sopenharmony_ci .thigh_max = 5000, 122362306a36Sopenharmony_ci .timeout = 106500 122462306a36Sopenharmony_ci }, 122562306a36Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_1000KHZ] = { 122662306a36Sopenharmony_ci .scl_high = 600, 122762306a36Sopenharmony_ci .scl_low = 1300, 122862306a36Sopenharmony_ci .hold_start = 600, 122962306a36Sopenharmony_ci .setup_start = 600, 123062306a36Sopenharmony_ci .setup_stop = 600, 123162306a36Sopenharmony_ci .setup_data = 100, 123262306a36Sopenharmony_ci .sda_rise = 50, 123362306a36Sopenharmony_ci .sda_fall = 50, 123462306a36Sopenharmony_ci .scl_rise = 50, 123562306a36Sopenharmony_ci .scl_fall = 50, 123662306a36Sopenharmony_ci .hold_data = 300, 123762306a36Sopenharmony_ci .buf = 20000, 123862306a36Sopenharmony_ci .thigh_max = 5000, 123962306a36Sopenharmony_ci .timeout = 106500 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci}; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic int mlxbf_i2c_init_timings(struct platform_device *pdev, 124462306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci enum mlxbf_i2c_timings_config config_idx; 124762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 124862306a36Sopenharmony_ci u32 config_khz; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci int ret; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci ret = device_property_read_u32(dev, "clock-frequency", &config_khz); 125362306a36Sopenharmony_ci if (ret < 0) 125462306a36Sopenharmony_ci config_khz = I2C_MAX_STANDARD_MODE_FREQ; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci switch (config_khz) { 125762306a36Sopenharmony_ci default: 125862306a36Sopenharmony_ci /* Default settings is 100 KHz. */ 125962306a36Sopenharmony_ci pr_warn("Illegal value %d: defaulting to 100 KHz\n", 126062306a36Sopenharmony_ci config_khz); 126162306a36Sopenharmony_ci fallthrough; 126262306a36Sopenharmony_ci case I2C_MAX_STANDARD_MODE_FREQ: 126362306a36Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_100KHZ; 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci case I2C_MAX_FAST_MODE_FREQ: 126762306a36Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_400KHZ; 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci case I2C_MAX_FAST_MODE_PLUS_FREQ: 127162306a36Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_1000KHZ; 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci mlxbf_i2c_set_timings(priv, &mlxbf_i2c_timings[config_idx]); 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci return 0; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int mlxbf_i2c_get_gpio(struct platform_device *pdev, 128162306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 128262306a36Sopenharmony_ci{ 128362306a36Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 128462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 128562306a36Sopenharmony_ci struct resource *params; 128662306a36Sopenharmony_ci resource_size_t size; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 128962306a36Sopenharmony_ci if (!gpio_res) 129062306a36Sopenharmony_ci return -EPERM; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* 129362306a36Sopenharmony_ci * The GPIO region in TYU space is shared among I2C busses. 129462306a36Sopenharmony_ci * This function MUST be serialized to avoid racing when 129562306a36Sopenharmony_ci * claiming the memory region and/or setting up the GPIO. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_ci lockdep_assert_held(gpio_res->lock); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* Check whether the memory map exist. */ 130062306a36Sopenharmony_ci if (gpio_res->io) 130162306a36Sopenharmony_ci return 0; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci params = gpio_res->params; 130462306a36Sopenharmony_ci size = resource_size(params); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (!devm_request_mem_region(dev, params->start, size, params->name)) 130762306a36Sopenharmony_ci return -EFAULT; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci gpio_res->io = devm_ioremap(dev, params->start, size); 131062306a36Sopenharmony_ci if (!gpio_res->io) { 131162306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 131262306a36Sopenharmony_ci return -ENOMEM; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci return 0; 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic int mlxbf_i2c_release_gpio(struct platform_device *pdev, 131962306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 132262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 132362306a36Sopenharmony_ci struct resource *params; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 132662306a36Sopenharmony_ci if (!gpio_res) 132762306a36Sopenharmony_ci return 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci mutex_lock(gpio_res->lock); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (gpio_res->io) { 133262306a36Sopenharmony_ci /* Release the GPIO resource. */ 133362306a36Sopenharmony_ci params = gpio_res->params; 133462306a36Sopenharmony_ci devm_iounmap(dev, gpio_res->io); 133562306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, 133662306a36Sopenharmony_ci resource_size(params)); 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci mutex_unlock(gpio_res->lock); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci return 0; 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic int mlxbf_i2c_get_corepll(struct platform_device *pdev, 134562306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 134862306a36Sopenharmony_ci struct device *dev = &pdev->dev; 134962306a36Sopenharmony_ci struct resource *params; 135062306a36Sopenharmony_ci resource_size_t size; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 135362306a36Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 135462306a36Sopenharmony_ci if (!corepll_res) 135562306a36Sopenharmony_ci return -EPERM; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci /* 135862306a36Sopenharmony_ci * The COREPLL region in TYU space is shared among I2C busses. 135962306a36Sopenharmony_ci * This function MUST be serialized to avoid racing when 136062306a36Sopenharmony_ci * claiming the memory region. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci lockdep_assert_held(corepll_res->lock); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci /* Check whether the memory map exist. */ 136562306a36Sopenharmony_ci if (corepll_res->io) 136662306a36Sopenharmony_ci return 0; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci params = corepll_res->params; 136962306a36Sopenharmony_ci size = resource_size(params); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (!devm_request_mem_region(dev, params->start, size, params->name)) 137262306a36Sopenharmony_ci return -EFAULT; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci corepll_res->io = devm_ioremap(dev, params->start, size); 137562306a36Sopenharmony_ci if (!corepll_res->io) { 137662306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 137762306a36Sopenharmony_ci return -ENOMEM; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci return 0; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_cistatic int mlxbf_i2c_release_corepll(struct platform_device *pdev, 138462306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 138762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 138862306a36Sopenharmony_ci struct resource *params; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 139162306a36Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci mutex_lock(corepll_res->lock); 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (corepll_res->io) { 139662306a36Sopenharmony_ci /* Release the CorePLL resource. */ 139762306a36Sopenharmony_ci params = corepll_res->params; 139862306a36Sopenharmony_ci devm_iounmap(dev, corepll_res->io); 139962306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, 140062306a36Sopenharmony_ci resource_size(params)); 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci mutex_unlock(corepll_res->lock); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci return 0; 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic int mlxbf_i2c_init_master(struct platform_device *pdev, 140962306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 141262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 141362306a36Sopenharmony_ci u32 config_reg; 141462306a36Sopenharmony_ci int ret; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* This configuration is only needed for BlueField 1. */ 141762306a36Sopenharmony_ci if (!mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) 141862306a36Sopenharmony_ci return 0; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 142162306a36Sopenharmony_ci if (!gpio_res) 142262306a36Sopenharmony_ci return -EPERM; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci /* 142562306a36Sopenharmony_ci * The GPIO region in TYU space is shared among I2C busses. 142662306a36Sopenharmony_ci * This function MUST be serialized to avoid racing when 142762306a36Sopenharmony_ci * claiming the memory region and/or setting up the GPIO. 142862306a36Sopenharmony_ci */ 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci mutex_lock(gpio_res->lock); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci ret = mlxbf_i2c_get_gpio(pdev, priv); 143362306a36Sopenharmony_ci if (ret < 0) { 143462306a36Sopenharmony_ci dev_err(dev, "Failed to get gpio resource"); 143562306a36Sopenharmony_ci mutex_unlock(gpio_res->lock); 143662306a36Sopenharmony_ci return ret; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci /* 144062306a36Sopenharmony_ci * TYU - Configuration for GPIO pins. Those pins must be asserted in 144162306a36Sopenharmony_ci * MLXBF_I2C_GPIO_0_FUNC_EN_0, i.e. GPIO 0 is controlled by HW, and must 144262306a36Sopenharmony_ci * be reset in MLXBF_I2C_GPIO_0_FORCE_OE_EN, i.e. GPIO_OE will be driven 144362306a36Sopenharmony_ci * instead of HW_OE. 144462306a36Sopenharmony_ci * For now, we do not reset the GPIO state when the driver is removed. 144562306a36Sopenharmony_ci * First, it is not necessary to disable the bus since we are using 144662306a36Sopenharmony_ci * the same busses. Then, some busses might be shared among Linux and 144762306a36Sopenharmony_ci * platform firmware; disabling the bus might compromise the system 144862306a36Sopenharmony_ci * functionality. 144962306a36Sopenharmony_ci */ 145062306a36Sopenharmony_ci config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0); 145162306a36Sopenharmony_ci config_reg = MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(priv->bus, 145262306a36Sopenharmony_ci config_reg); 145362306a36Sopenharmony_ci writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN); 145662306a36Sopenharmony_ci config_reg = MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(priv->bus, 145762306a36Sopenharmony_ci config_reg); 145862306a36Sopenharmony_ci writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci mutex_unlock(gpio_res->lock); 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return 0; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic u64 mlxbf_i2c_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci u64 core_frequency; 146862306a36Sopenharmony_ci u8 core_od, core_r; 146962306a36Sopenharmony_ci u32 corepll_val; 147062306a36Sopenharmony_ci u16 core_f; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci /* Get Core PLL configuration bits. */ 147562306a36Sopenharmony_ci core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_TYU_MASK, corepll_val); 147662306a36Sopenharmony_ci core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK, corepll_val); 147762306a36Sopenharmony_ci core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_TYU_MASK, corepll_val); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* 148062306a36Sopenharmony_ci * Compute PLL output frequency as follow: 148162306a36Sopenharmony_ci * 148262306a36Sopenharmony_ci * CORE_F + 1 148362306a36Sopenharmony_ci * PLL_OUT_FREQ = PLL_IN_FREQ * ---------------------------- 148462306a36Sopenharmony_ci * (CORE_R + 1) * (CORE_OD + 1) 148562306a36Sopenharmony_ci * 148662306a36Sopenharmony_ci * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency 148762306a36Sopenharmony_ci * and PadFrequency, respectively. 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_ci core_frequency = MLXBF_I2C_PLL_IN_FREQ * (++core_f); 149062306a36Sopenharmony_ci core_frequency /= (++core_r) * (++core_od); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci return core_frequency; 149362306a36Sopenharmony_ci} 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_cistatic u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci u32 corepll_reg1_val, corepll_reg2_val; 149862306a36Sopenharmony_ci u64 corepll_frequency; 149962306a36Sopenharmony_ci u8 core_od, core_r; 150062306a36Sopenharmony_ci u32 core_f; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); 150362306a36Sopenharmony_ci corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* Get Core PLL configuration bits */ 150662306a36Sopenharmony_ci core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_YU_MASK, corepll_reg1_val); 150762306a36Sopenharmony_ci core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_YU_MASK, corepll_reg1_val); 150862306a36Sopenharmony_ci core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_YU_MASK, corepll_reg2_val); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* 151162306a36Sopenharmony_ci * Compute PLL output frequency as follow: 151262306a36Sopenharmony_ci * 151362306a36Sopenharmony_ci * CORE_F / 16384 151462306a36Sopenharmony_ci * PLL_OUT_FREQ = PLL_IN_FREQ * ---------------------------- 151562306a36Sopenharmony_ci * (CORE_R + 1) * (CORE_OD + 1) 151662306a36Sopenharmony_ci * 151762306a36Sopenharmony_ci * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency 151862306a36Sopenharmony_ci * and PadFrequency, respectively. 151962306a36Sopenharmony_ci */ 152062306a36Sopenharmony_ci corepll_frequency = (MLXBF_I2C_PLL_IN_FREQ * core_f) / MLNXBF_I2C_COREPLL_CONST; 152162306a36Sopenharmony_ci corepll_frequency /= (++core_r) * (++core_od); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci return corepll_frequency; 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_cistatic int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, 152762306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 152862306a36Sopenharmony_ci{ 152962306a36Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 153062306a36Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 153162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 153262306a36Sopenharmony_ci u64 *freq = &priv->frequency; 153362306a36Sopenharmony_ci int ret; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 153662306a36Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 153762306a36Sopenharmony_ci if (!corepll_res) 153862306a36Sopenharmony_ci return -EPERM; 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci /* 154162306a36Sopenharmony_ci * First, check whether the TYU core Clock frequency is set. 154262306a36Sopenharmony_ci * The TYU core frequency is the same for all I2C busses; when 154362306a36Sopenharmony_ci * the first device gets probed the frequency is determined and 154462306a36Sopenharmony_ci * stored into a globally visible variable. So, first of all, 154562306a36Sopenharmony_ci * check whether the frequency is already set. Here, we assume 154662306a36Sopenharmony_ci * that the frequency is expected to be greater than 0. 154762306a36Sopenharmony_ci */ 154862306a36Sopenharmony_ci mutex_lock(corepll_res->lock); 154962306a36Sopenharmony_ci if (!mlxbf_i2c_corepll_frequency) { 155062306a36Sopenharmony_ci if (!chip->calculate_freq) { 155162306a36Sopenharmony_ci mutex_unlock(corepll_res->lock); 155262306a36Sopenharmony_ci return -EPERM; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci ret = mlxbf_i2c_get_corepll(pdev, priv); 155662306a36Sopenharmony_ci if (ret < 0) { 155762306a36Sopenharmony_ci dev_err(dev, "Failed to get corePLL resource"); 155862306a36Sopenharmony_ci mutex_unlock(corepll_res->lock); 155962306a36Sopenharmony_ci return ret; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci mlxbf_i2c_corepll_frequency = chip->calculate_freq(corepll_res); 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci mutex_unlock(corepll_res->lock); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci *freq = mlxbf_i2c_corepll_frequency; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci return 0; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv, 157262306a36Sopenharmony_ci struct i2c_client *slave) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci u8 reg, reg_cnt, byte, addr_tmp; 157562306a36Sopenharmony_ci u32 slave_reg, slave_reg_tmp; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci if (!priv) 157862306a36Sopenharmony_ci return -EPERM; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* 158362306a36Sopenharmony_ci * Read the slave registers. There are 4 * 32-bit slave registers. 158462306a36Sopenharmony_ci * Each slave register can hold up to 4 * 8-bit slave configuration: 158562306a36Sopenharmony_ci * 1) A 7-bit address 158662306a36Sopenharmony_ci * 2) And a status bit (1 if enabled, 0 if not). 158762306a36Sopenharmony_ci * Look for the next available slave register slot. 158862306a36Sopenharmony_ci */ 158962306a36Sopenharmony_ci for (reg = 0; reg < reg_cnt; reg++) { 159062306a36Sopenharmony_ci slave_reg = readl(priv->slv->io + 159162306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); 159262306a36Sopenharmony_ci /* 159362306a36Sopenharmony_ci * Each register holds 4 slave addresses. So, we have to keep 159462306a36Sopenharmony_ci * the byte order consistent with the value read in order to 159562306a36Sopenharmony_ci * update the register correctly, if needed. 159662306a36Sopenharmony_ci */ 159762306a36Sopenharmony_ci slave_reg_tmp = slave_reg; 159862306a36Sopenharmony_ci for (byte = 0; byte < 4; byte++) { 159962306a36Sopenharmony_ci addr_tmp = slave_reg_tmp & GENMASK(7, 0); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* 160262306a36Sopenharmony_ci * If an enable bit is not set in the 160362306a36Sopenharmony_ci * MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG register, then the 160462306a36Sopenharmony_ci * slave address slot associated with that bit is 160562306a36Sopenharmony_ci * free. So set the enable bit and write the 160662306a36Sopenharmony_ci * slave address bits. 160762306a36Sopenharmony_ci */ 160862306a36Sopenharmony_ci if (!(addr_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) { 160962306a36Sopenharmony_ci slave_reg &= ~(MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK << (byte * 8)); 161062306a36Sopenharmony_ci slave_reg |= (slave->addr << (byte * 8)); 161162306a36Sopenharmony_ci slave_reg |= MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT << (byte * 8); 161262306a36Sopenharmony_ci writel(slave_reg, priv->slv->io + 161362306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + 161462306a36Sopenharmony_ci (reg * 0x4)); 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci /* 161762306a36Sopenharmony_ci * Set the slave at the corresponding index. 161862306a36Sopenharmony_ci */ 161962306a36Sopenharmony_ci priv->slave[(reg * 4) + byte] = slave; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci /* Parse next byte. */ 162562306a36Sopenharmony_ci slave_reg_tmp >>= 8; 162662306a36Sopenharmony_ci } 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci return -EBUSY; 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci u8 addr_tmp, reg, reg_cnt, byte; 163562306a36Sopenharmony_ci u32 slave_reg, slave_reg_tmp; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci /* 164062306a36Sopenharmony_ci * Read the slave registers. There are 4 * 32-bit slave registers. 164162306a36Sopenharmony_ci * Each slave register can hold up to 4 * 8-bit slave configuration: 164262306a36Sopenharmony_ci * 1) A 7-bit address 164362306a36Sopenharmony_ci * 2) And a status bit (1 if enabled, 0 if not). 164462306a36Sopenharmony_ci * Check if addr is present in the registers. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci for (reg = 0; reg < reg_cnt; reg++) { 164762306a36Sopenharmony_ci slave_reg = readl(priv->slv->io + 164862306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci /* Check whether the address slots are empty. */ 165162306a36Sopenharmony_ci if (!slave_reg) 165262306a36Sopenharmony_ci continue; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci /* 165562306a36Sopenharmony_ci * Check if addr matches any of the 4 slave addresses 165662306a36Sopenharmony_ci * in the register. 165762306a36Sopenharmony_ci */ 165862306a36Sopenharmony_ci slave_reg_tmp = slave_reg; 165962306a36Sopenharmony_ci for (byte = 0; byte < 4; byte++) { 166062306a36Sopenharmony_ci addr_tmp = slave_reg_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; 166162306a36Sopenharmony_ci /* 166262306a36Sopenharmony_ci * Parse slave address bytes and check whether the 166362306a36Sopenharmony_ci * slave address already exists. 166462306a36Sopenharmony_ci */ 166562306a36Sopenharmony_ci if (addr_tmp == addr) { 166662306a36Sopenharmony_ci /* Clear the slave address slot. */ 166762306a36Sopenharmony_ci slave_reg &= ~(GENMASK(7, 0) << (byte * 8)); 166862306a36Sopenharmony_ci writel(slave_reg, priv->slv->io + 166962306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + 167062306a36Sopenharmony_ci (reg * 0x4)); 167162306a36Sopenharmony_ci /* Free slave at the corresponding index */ 167262306a36Sopenharmony_ci priv->slave[(reg * 4) + byte] = NULL; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci return 0; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* Parse next byte. */ 167862306a36Sopenharmony_ci slave_reg_tmp >>= 8; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci return -ENXIO; 168362306a36Sopenharmony_ci} 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_cistatic int mlxbf_i2c_init_coalesce(struct platform_device *pdev, 168662306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 168762306a36Sopenharmony_ci{ 168862306a36Sopenharmony_ci struct mlxbf_i2c_resource *coalesce_res; 168962306a36Sopenharmony_ci struct resource *params; 169062306a36Sopenharmony_ci resource_size_t size; 169162306a36Sopenharmony_ci int ret = 0; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci /* 169462306a36Sopenharmony_ci * Unlike BlueField-1 platform, the coalesce registers is a dedicated 169562306a36Sopenharmony_ci * resource in the next generations of BlueField. 169662306a36Sopenharmony_ci */ 169762306a36Sopenharmony_ci if (mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) { 169862306a36Sopenharmony_ci coalesce_res = mlxbf_i2c_get_shared_resource(priv, 169962306a36Sopenharmony_ci MLXBF_I2C_COALESCE_RES); 170062306a36Sopenharmony_ci if (!coalesce_res) 170162306a36Sopenharmony_ci return -EPERM; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci /* 170462306a36Sopenharmony_ci * The Cause Coalesce group in TYU space is shared among 170562306a36Sopenharmony_ci * I2C busses. This function MUST be serialized to avoid 170662306a36Sopenharmony_ci * racing when claiming the memory region. 170762306a36Sopenharmony_ci */ 170862306a36Sopenharmony_ci lockdep_assert_held(mlxbf_i2c_gpio_res->lock); 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci /* Check whether the memory map exist. */ 171162306a36Sopenharmony_ci if (coalesce_res->io) { 171262306a36Sopenharmony_ci priv->coalesce = coalesce_res; 171362306a36Sopenharmony_ci return 0; 171462306a36Sopenharmony_ci } 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci params = coalesce_res->params; 171762306a36Sopenharmony_ci size = resource_size(params); 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci if (!request_mem_region(params->start, size, params->name)) 172062306a36Sopenharmony_ci return -EFAULT; 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci coalesce_res->io = ioremap(params->start, size); 172362306a36Sopenharmony_ci if (!coalesce_res->io) { 172462306a36Sopenharmony_ci release_mem_region(params->start, size); 172562306a36Sopenharmony_ci return -ENOMEM; 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci priv->coalesce = coalesce_res; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci } else { 173162306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->coalesce, 173262306a36Sopenharmony_ci MLXBF_I2C_COALESCE_RES); 173362306a36Sopenharmony_ci } 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci return ret; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic int mlxbf_i2c_release_coalesce(struct platform_device *pdev, 173962306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci struct mlxbf_i2c_resource *coalesce_res; 174262306a36Sopenharmony_ci struct device *dev = &pdev->dev; 174362306a36Sopenharmony_ci struct resource *params; 174462306a36Sopenharmony_ci resource_size_t size; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci coalesce_res = priv->coalesce; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (coalesce_res->io) { 174962306a36Sopenharmony_ci params = coalesce_res->params; 175062306a36Sopenharmony_ci size = resource_size(params); 175162306a36Sopenharmony_ci if (mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) { 175262306a36Sopenharmony_ci mutex_lock(coalesce_res->lock); 175362306a36Sopenharmony_ci iounmap(coalesce_res->io); 175462306a36Sopenharmony_ci release_mem_region(params->start, size); 175562306a36Sopenharmony_ci mutex_unlock(coalesce_res->lock); 175662306a36Sopenharmony_ci } else { 175762306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci return 0; 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_cistatic int mlxbf_i2c_init_slave(struct platform_device *pdev, 176562306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 176862306a36Sopenharmony_ci u32 int_reg; 176962306a36Sopenharmony_ci int ret; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* Reset FSM. */ 177262306a36Sopenharmony_ci writel(0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_FSM); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* 177562306a36Sopenharmony_ci * Enable slave cause interrupt bits. Drive 177662306a36Sopenharmony_ci * MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE and 177762306a36Sopenharmony_ci * MLXBF_I2C_CAUSE_WRITE_SUCCESS, these are enabled when an external 177862306a36Sopenharmony_ci * masters issue a Read and Write, respectively. But, clear all 177962306a36Sopenharmony_ci * interrupts first. 178062306a36Sopenharmony_ci */ 178162306a36Sopenharmony_ci writel(~0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 178262306a36Sopenharmony_ci int_reg = MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE; 178362306a36Sopenharmony_ci int_reg |= MLXBF_I2C_CAUSE_WRITE_SUCCESS; 178462306a36Sopenharmony_ci writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0); 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci /* Finally, set the 'ready' bit to start handling transactions. */ 178762306a36Sopenharmony_ci writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* Initialize the cause coalesce resource. */ 179062306a36Sopenharmony_ci ret = mlxbf_i2c_init_coalesce(pdev, priv); 179162306a36Sopenharmony_ci if (ret < 0) { 179262306a36Sopenharmony_ci dev_err(dev, "failed to initialize cause coalesce\n"); 179362306a36Sopenharmony_ci return ret; 179462306a36Sopenharmony_ci } 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci return 0; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read, 180062306a36Sopenharmony_ci bool *write) 180162306a36Sopenharmony_ci{ 180262306a36Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 180362306a36Sopenharmony_ci u32 coalesce0_reg, cause_reg; 180462306a36Sopenharmony_ci u8 slave_shift, is_set; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci *write = false; 180762306a36Sopenharmony_ci *read = false; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci slave_shift = chip->type != MLXBF_I2C_CHIP_TYPE_1 ? 181062306a36Sopenharmony_ci MLXBF_I2C_CAUSE_YU_SLAVE_BIT : 181162306a36Sopenharmony_ci priv->bus + MLXBF_I2C_CAUSE_TYU_SLAVE_BIT; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci coalesce0_reg = readl(priv->coalesce->io + MLXBF_I2C_CAUSE_COALESCE_0); 181462306a36Sopenharmony_ci is_set = coalesce0_reg & (1 << slave_shift); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (!is_set) 181762306a36Sopenharmony_ci return false; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* Check the source of the interrupt, i.e. whether a Read or Write. */ 182062306a36Sopenharmony_ci cause_reg = readl(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER); 182162306a36Sopenharmony_ci if (cause_reg & MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE) 182262306a36Sopenharmony_ci *read = true; 182362306a36Sopenharmony_ci else if (cause_reg & MLXBF_I2C_CAUSE_WRITE_SUCCESS) 182462306a36Sopenharmony_ci *write = true; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci /* Clear cause bits. */ 182762306a36Sopenharmony_ci writel(~0x0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci return true; 183062306a36Sopenharmony_ci} 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_cistatic bool mlxbf_i2c_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, 183362306a36Sopenharmony_ci u32 timeout) 183462306a36Sopenharmony_ci{ 183562306a36Sopenharmony_ci u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL; 183662306a36Sopenharmony_ci u32 addr = MLXBF_I2C_CAUSE_ARBITER; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout)) 183962306a36Sopenharmony_ci return true; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci return false; 184262306a36Sopenharmony_ci} 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_cistatic struct i2c_client *mlxbf_i2c_get_slave_from_addr( 184562306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv, u8 addr) 184662306a36Sopenharmony_ci{ 184762306a36Sopenharmony_ci int i; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci for (i = 0; i < MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT; i++) { 185062306a36Sopenharmony_ci if (!priv->slave[i]) 185162306a36Sopenharmony_ci continue; 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (priv->slave[i]->addr == addr) 185462306a36Sopenharmony_ci return priv->slave[i]; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci return NULL; 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci/* 186162306a36Sopenharmony_ci * Send byte to 'external' smbus master. This function is executed when 186262306a36Sopenharmony_ci * an external smbus master wants to read data from the BlueField. 186362306a36Sopenharmony_ci */ 186462306a36Sopenharmony_cistatic int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; 186762306a36Sopenharmony_ci u8 write_size, pec_en, addr, value, byte_cnt; 186862306a36Sopenharmony_ci struct i2c_client *slave; 186962306a36Sopenharmony_ci u32 control32, data32; 187062306a36Sopenharmony_ci int ret = 0; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci /* 187362306a36Sopenharmony_ci * Read the first byte received from the external master to 187462306a36Sopenharmony_ci * determine the slave address. This byte is located in the 187562306a36Sopenharmony_ci * first data descriptor register of the slave GW. 187662306a36Sopenharmony_ci */ 187762306a36Sopenharmony_ci data32 = ioread32be(priv->slv->io + 187862306a36Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR); 187962306a36Sopenharmony_ci addr = (data32 & GENMASK(7, 0)) >> 1; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* 188262306a36Sopenharmony_ci * Check if the slave address received in the data descriptor register 188362306a36Sopenharmony_ci * matches any of the slave addresses registered. If there is a match, 188462306a36Sopenharmony_ci * set the slave. 188562306a36Sopenharmony_ci */ 188662306a36Sopenharmony_ci slave = mlxbf_i2c_get_slave_from_addr(priv, addr); 188762306a36Sopenharmony_ci if (!slave) { 188862306a36Sopenharmony_ci ret = -ENXIO; 188962306a36Sopenharmony_ci goto clear_csr; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* 189362306a36Sopenharmony_ci * An I2C read can consist of a WRITE bit transaction followed by 189462306a36Sopenharmony_ci * a READ bit transaction. Indeed, slave devices often expect 189562306a36Sopenharmony_ci * the slave address to be followed by the internal address. 189662306a36Sopenharmony_ci * So, write the internal address byte first, and then, send the 189762306a36Sopenharmony_ci * requested data to the master. 189862306a36Sopenharmony_ci */ 189962306a36Sopenharmony_ci if (recv_bytes > 1) { 190062306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); 190162306a36Sopenharmony_ci value = (data32 >> 8) & GENMASK(7, 0); 190262306a36Sopenharmony_ci ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, 190362306a36Sopenharmony_ci &value); 190462306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (ret < 0) 190762306a36Sopenharmony_ci goto clear_csr; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci /* 191162306a36Sopenharmony_ci * Send data to the master. Currently, the driver supports 191262306a36Sopenharmony_ci * READ_BYTE, READ_WORD and BLOCK READ protocols. The 191362306a36Sopenharmony_ci * hardware can send up to 128 bytes per transfer which is 191462306a36Sopenharmony_ci * the total size of the data registers. 191562306a36Sopenharmony_ci */ 191662306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci for (byte_cnt = 0; byte_cnt < MLXBF_I2C_SLAVE_DATA_DESC_SIZE; byte_cnt++) { 191962306a36Sopenharmony_ci data_desc[byte_cnt] = value; 192062306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value); 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* Send a stop condition to the backend. */ 192462306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci /* Set the number of bytes to write to master. */ 192762306a36Sopenharmony_ci write_size = (byte_cnt - 1) & 0x7f; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci /* Write data to Slave GW data descriptor. */ 193062306a36Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, data_desc, byte_cnt, 193162306a36Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci pec_en = 0; /* Disable PEC since it is not supported. */ 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci /* Prepare control word. */ 193662306a36Sopenharmony_ci control32 = MLXBF_I2C_SLAVE_ENABLE; 193762306a36Sopenharmony_ci control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT); 193862306a36Sopenharmony_ci control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT); 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci writel(control32, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_GW); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci /* 194362306a36Sopenharmony_ci * Wait until the transfer is completed; the driver will wait 194462306a36Sopenharmony_ci * until the GW is idle, a cause will rise on fall of GW busy. 194562306a36Sopenharmony_ci */ 194662306a36Sopenharmony_ci mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); 194762306a36Sopenharmony_ci 194862306a36Sopenharmony_ciclear_csr: 194962306a36Sopenharmony_ci /* Release the Slave GW. */ 195062306a36Sopenharmony_ci writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 195162306a36Sopenharmony_ci writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); 195262306a36Sopenharmony_ci writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return ret; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci/* 195862306a36Sopenharmony_ci * Receive bytes from 'external' smbus master. This function is executed when 195962306a36Sopenharmony_ci * an external smbus master wants to write data to the BlueField. 196062306a36Sopenharmony_ci */ 196162306a36Sopenharmony_cistatic int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) 196262306a36Sopenharmony_ci{ 196362306a36Sopenharmony_ci u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; 196462306a36Sopenharmony_ci struct i2c_client *slave; 196562306a36Sopenharmony_ci u8 value, byte, addr; 196662306a36Sopenharmony_ci int ret = 0; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* Read data from Slave GW data descriptor. */ 196962306a36Sopenharmony_ci mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes, 197062306a36Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); 197162306a36Sopenharmony_ci addr = data_desc[0] >> 1; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci /* 197462306a36Sopenharmony_ci * Check if the slave address received in the data descriptor register 197562306a36Sopenharmony_ci * matches any of the slave addresses registered. 197662306a36Sopenharmony_ci */ 197762306a36Sopenharmony_ci slave = mlxbf_i2c_get_slave_from_addr(priv, addr); 197862306a36Sopenharmony_ci if (!slave) { 197962306a36Sopenharmony_ci ret = -EINVAL; 198062306a36Sopenharmony_ci goto clear_csr; 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* 198462306a36Sopenharmony_ci * Notify the slave backend that an smbus master wants to write data 198562306a36Sopenharmony_ci * to the BlueField. 198662306a36Sopenharmony_ci */ 198762306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci /* Send the received data to the slave backend. */ 199062306a36Sopenharmony_ci for (byte = 1; byte < recv_bytes; byte++) { 199162306a36Sopenharmony_ci value = data_desc[byte]; 199262306a36Sopenharmony_ci ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, 199362306a36Sopenharmony_ci &value); 199462306a36Sopenharmony_ci if (ret < 0) 199562306a36Sopenharmony_ci break; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* 199962306a36Sopenharmony_ci * Send a stop event to the slave backend, to signal 200062306a36Sopenharmony_ci * the end of the write transactions. 200162306a36Sopenharmony_ci */ 200262306a36Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ciclear_csr: 200562306a36Sopenharmony_ci /* Release the Slave GW. */ 200662306a36Sopenharmony_ci writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 200762306a36Sopenharmony_ci writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); 200862306a36Sopenharmony_ci writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci return ret; 201162306a36Sopenharmony_ci} 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_cistatic irqreturn_t mlxbf_i2c_irq(int irq, void *ptr) 201462306a36Sopenharmony_ci{ 201562306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv = ptr; 201662306a36Sopenharmony_ci bool read, write, irq_is_set; 201762306a36Sopenharmony_ci u32 rw_bytes_reg; 201862306a36Sopenharmony_ci u8 recv_bytes; 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci /* 202162306a36Sopenharmony_ci * Read TYU interrupt register and determine the source of the 202262306a36Sopenharmony_ci * interrupt. Based on the source of the interrupt one of the 202362306a36Sopenharmony_ci * following actions are performed: 202462306a36Sopenharmony_ci * - Receive data and send response to master. 202562306a36Sopenharmony_ci * - Send data and release slave GW. 202662306a36Sopenharmony_ci * 202762306a36Sopenharmony_ci * Handle read/write transaction only. CRmaster and Iarp requests 202862306a36Sopenharmony_ci * are ignored for now. 202962306a36Sopenharmony_ci */ 203062306a36Sopenharmony_ci irq_is_set = mlxbf_i2c_has_coalesce(priv, &read, &write); 203162306a36Sopenharmony_ci if (!irq_is_set || (!read && !write)) { 203262306a36Sopenharmony_ci /* Nothing to do here, interrupt was not from this device. */ 203362306a36Sopenharmony_ci return IRQ_NONE; 203462306a36Sopenharmony_ci } 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* 203762306a36Sopenharmony_ci * The MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES includes the number of 203862306a36Sopenharmony_ci * bytes from/to master. These are defined by 8-bits each. If the lower 203962306a36Sopenharmony_ci * 8 bits are set, then the master expect to read N bytes from the 204062306a36Sopenharmony_ci * slave, if the higher 8 bits are sent then the slave expect N bytes 204162306a36Sopenharmony_ci * from the master. 204262306a36Sopenharmony_ci */ 204362306a36Sopenharmony_ci rw_bytes_reg = readl(priv->slv->io + 204462306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 204562306a36Sopenharmony_ci recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0); 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci /* 204862306a36Sopenharmony_ci * For now, the slave supports 128 bytes transfer. Discard remaining 204962306a36Sopenharmony_ci * data bytes if the master wrote more than 205062306a36Sopenharmony_ci * MLXBF_I2C_SLAVE_DATA_DESC_SIZE, i.e, the actual size of the slave 205162306a36Sopenharmony_ci * data descriptor. 205262306a36Sopenharmony_ci * 205362306a36Sopenharmony_ci * Note that we will never expect to transfer more than 128 bytes; as 205462306a36Sopenharmony_ci * specified in the SMBus standard, block transactions cannot exceed 205562306a36Sopenharmony_ci * 32 bytes. 205662306a36Sopenharmony_ci */ 205762306a36Sopenharmony_ci recv_bytes = recv_bytes > MLXBF_I2C_SLAVE_DATA_DESC_SIZE ? 205862306a36Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_SIZE : recv_bytes; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci if (read) 206162306a36Sopenharmony_ci mlxbf_i2c_irq_send(priv, recv_bytes); 206262306a36Sopenharmony_ci else 206362306a36Sopenharmony_ci mlxbf_i2c_irq_recv(priv, recv_bytes); 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci return IRQ_HANDLED; 206662306a36Sopenharmony_ci} 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci/* Return negative errno on error. */ 206962306a36Sopenharmony_cistatic s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, 207062306a36Sopenharmony_ci unsigned short flags, char read_write, 207162306a36Sopenharmony_ci u8 command, int size, 207262306a36Sopenharmony_ci union i2c_smbus_data *data) 207362306a36Sopenharmony_ci{ 207462306a36Sopenharmony_ci struct mlxbf_i2c_smbus_request request = { 0 }; 207562306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv; 207662306a36Sopenharmony_ci bool read, pec; 207762306a36Sopenharmony_ci u8 byte_cnt; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci request.slave = addr; 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci read = (read_write == I2C_SMBUS_READ); 208262306a36Sopenharmony_ci pec = flags & I2C_FUNC_SMBUS_PEC; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci switch (size) { 208562306a36Sopenharmony_ci case I2C_SMBUS_QUICK: 208662306a36Sopenharmony_ci mlxbf_i2c_smbus_quick_command(&request, read); 208762306a36Sopenharmony_ci dev_dbg(&adap->dev, "smbus quick, slave 0x%02x\n", addr); 208862306a36Sopenharmony_ci break; 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci case I2C_SMBUS_BYTE: 209162306a36Sopenharmony_ci mlxbf_i2c_smbus_byte_func(&request, 209262306a36Sopenharmony_ci read ? &data->byte : &command, read, 209362306a36Sopenharmony_ci pec); 209462306a36Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s byte, slave 0x%02x.\n", 209562306a36Sopenharmony_ci read ? "read" : "write", addr); 209662306a36Sopenharmony_ci break; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 209962306a36Sopenharmony_ci mlxbf_i2c_smbus_data_byte_func(&request, &command, &data->byte, 210062306a36Sopenharmony_ci read, pec); 210162306a36Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s byte data at 0x%02x, slave 0x%02x.\n", 210262306a36Sopenharmony_ci read ? "read" : "write", command, addr); 210362306a36Sopenharmony_ci break; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 210662306a36Sopenharmony_ci mlxbf_i2c_smbus_data_word_func(&request, &command, 210762306a36Sopenharmony_ci (u8 *)&data->word, read, pec); 210862306a36Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s word data at 0x%02x, slave 0x%02x.\n", 210962306a36Sopenharmony_ci read ? "read" : "write", command, addr); 211062306a36Sopenharmony_ci break; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 211362306a36Sopenharmony_ci byte_cnt = data->block[0]; 211462306a36Sopenharmony_ci mlxbf_i2c_smbus_i2c_block_func(&request, &command, data->block, 211562306a36Sopenharmony_ci &byte_cnt, read, pec); 211662306a36Sopenharmony_ci dev_dbg(&adap->dev, "i2c %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", 211762306a36Sopenharmony_ci read ? "read" : "write", byte_cnt, command, addr); 211862306a36Sopenharmony_ci break; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 212162306a36Sopenharmony_ci byte_cnt = read ? I2C_SMBUS_BLOCK_MAX : data->block[0]; 212262306a36Sopenharmony_ci mlxbf_i2c_smbus_block_func(&request, &command, data->block, 212362306a36Sopenharmony_ci &byte_cnt, read, pec); 212462306a36Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", 212562306a36Sopenharmony_ci read ? "read" : "write", byte_cnt, command, addr); 212662306a36Sopenharmony_ci break; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci case I2C_FUNC_SMBUS_PROC_CALL: 212962306a36Sopenharmony_ci mlxbf_i2c_smbus_process_call_func(&request, &command, 213062306a36Sopenharmony_ci (u8 *)&data->word, pec); 213162306a36Sopenharmony_ci dev_dbg(&adap->dev, "process call, wr/rd at 0x%02x, slave 0x%02x.\n", 213262306a36Sopenharmony_ci command, addr); 213362306a36Sopenharmony_ci break; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci case I2C_FUNC_SMBUS_BLOCK_PROC_CALL: 213662306a36Sopenharmony_ci byte_cnt = data->block[0]; 213762306a36Sopenharmony_ci mlxbf_i2c_smbus_blk_process_call_func(&request, &command, 213862306a36Sopenharmony_ci data->block, &byte_cnt, 213962306a36Sopenharmony_ci pec); 214062306a36Sopenharmony_ci dev_dbg(&adap->dev, "block process call, wr/rd %d bytes, slave 0x%02x.\n", 214162306a36Sopenharmony_ci byte_cnt, addr); 214262306a36Sopenharmony_ci break; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci default: 214562306a36Sopenharmony_ci dev_dbg(&adap->dev, "Unsupported I2C/SMBus command %d\n", 214662306a36Sopenharmony_ci size); 214762306a36Sopenharmony_ci return -EOPNOTSUPP; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci priv = i2c_get_adapdata(adap); 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci return mlxbf_i2c_smbus_start_transaction(priv, &request); 215362306a36Sopenharmony_ci} 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_cistatic int mlxbf_i2c_reg_slave(struct i2c_client *slave) 215662306a36Sopenharmony_ci{ 215762306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); 215862306a36Sopenharmony_ci struct device *dev = &slave->dev; 215962306a36Sopenharmony_ci int ret; 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci /* 216262306a36Sopenharmony_ci * Do not support ten bit chip address and do not use Packet Error 216362306a36Sopenharmony_ci * Checking (PEC). 216462306a36Sopenharmony_ci */ 216562306a36Sopenharmony_ci if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) { 216662306a36Sopenharmony_ci dev_err(dev, "SMBus PEC and 10 bit address not supported\n"); 216762306a36Sopenharmony_ci return -EAFNOSUPPORT; 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci ret = mlxbf_i2c_slave_enable(priv, slave); 217162306a36Sopenharmony_ci if (ret) 217262306a36Sopenharmony_ci dev_err(dev, "Surpassed max number of registered slaves allowed\n"); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci return 0; 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_cistatic int mlxbf_i2c_unreg_slave(struct i2c_client *slave) 217862306a36Sopenharmony_ci{ 217962306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); 218062306a36Sopenharmony_ci struct device *dev = &slave->dev; 218162306a36Sopenharmony_ci int ret; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci /* 218462306a36Sopenharmony_ci * Unregister slave by: 218562306a36Sopenharmony_ci * 1) Disabling the slave address in hardware 218662306a36Sopenharmony_ci * 2) Freeing priv->slave at the corresponding index 218762306a36Sopenharmony_ci */ 218862306a36Sopenharmony_ci ret = mlxbf_i2c_slave_disable(priv, slave->addr); 218962306a36Sopenharmony_ci if (ret) 219062306a36Sopenharmony_ci dev_err(dev, "Unable to find slave 0x%x\n", slave->addr); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci return ret; 219362306a36Sopenharmony_ci} 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_cistatic u32 mlxbf_i2c_functionality(struct i2c_adapter *adap) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci return MLXBF_I2C_FUNC_ALL; 219862306a36Sopenharmony_ci} 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_cistatic struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = { 220162306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 220262306a36Sopenharmony_ci .type = MLXBF_I2C_CHIP_TYPE_1, 220362306a36Sopenharmony_ci .shared_res = { 220462306a36Sopenharmony_ci [0] = &mlxbf_i2c_coalesce_res[MLXBF_I2C_CHIP_TYPE_1], 220562306a36Sopenharmony_ci [1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1], 220662306a36Sopenharmony_ci [2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1] 220762306a36Sopenharmony_ci }, 220862306a36Sopenharmony_ci .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu, 220962306a36Sopenharmony_ci .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, 221062306a36Sopenharmony_ci .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM 221162306a36Sopenharmony_ci }, 221262306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_2] = { 221362306a36Sopenharmony_ci .type = MLXBF_I2C_CHIP_TYPE_2, 221462306a36Sopenharmony_ci .shared_res = { 221562306a36Sopenharmony_ci [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2] 221662306a36Sopenharmony_ci }, 221762306a36Sopenharmony_ci .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, 221862306a36Sopenharmony_ci .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, 221962306a36Sopenharmony_ci .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM 222062306a36Sopenharmony_ci }, 222162306a36Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_3] = { 222262306a36Sopenharmony_ci .type = MLXBF_I2C_CHIP_TYPE_3, 222362306a36Sopenharmony_ci .shared_res = { 222462306a36Sopenharmony_ci [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_3] 222562306a36Sopenharmony_ci }, 222662306a36Sopenharmony_ci .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, 222762306a36Sopenharmony_ci .smbus_master_rs_bytes_off = MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES, 222862306a36Sopenharmony_ci .smbus_master_fsm_off = MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM 222962306a36Sopenharmony_ci } 223062306a36Sopenharmony_ci}; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic const struct i2c_algorithm mlxbf_i2c_algo = { 223362306a36Sopenharmony_ci .smbus_xfer = mlxbf_i2c_smbus_xfer, 223462306a36Sopenharmony_ci .functionality = mlxbf_i2c_functionality, 223562306a36Sopenharmony_ci .reg_slave = mlxbf_i2c_reg_slave, 223662306a36Sopenharmony_ci .unreg_slave = mlxbf_i2c_unreg_slave, 223762306a36Sopenharmony_ci}; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_cistatic struct i2c_adapter_quirks mlxbf_i2c_quirks = { 224062306a36Sopenharmony_ci .max_read_len = MLXBF_I2C_MASTER_DATA_R_LENGTH, 224162306a36Sopenharmony_ci .max_write_len = MLXBF_I2C_MASTER_DATA_W_LENGTH, 224262306a36Sopenharmony_ci}; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_cistatic const struct acpi_device_id mlxbf_i2c_acpi_ids[] = { 224562306a36Sopenharmony_ci { "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] }, 224662306a36Sopenharmony_ci { "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] }, 224762306a36Sopenharmony_ci { "MLNXBF31", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] }, 224862306a36Sopenharmony_ci {}, 224962306a36Sopenharmony_ci}; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, mlxbf_i2c_acpi_ids); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_cistatic int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) 225462306a36Sopenharmony_ci{ 225562306a36Sopenharmony_ci const struct acpi_device_id *aid; 225662306a36Sopenharmony_ci u64 bus_id; 225762306a36Sopenharmony_ci int ret; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci if (acpi_disabled) 226062306a36Sopenharmony_ci return -ENOENT; 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci aid = acpi_match_device(mlxbf_i2c_acpi_ids, dev); 226362306a36Sopenharmony_ci if (!aid) 226462306a36Sopenharmony_ci return -ENODEV; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci priv->chip = (struct mlxbf_i2c_chip_info *)aid->driver_data; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci ret = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &bus_id); 226962306a36Sopenharmony_ci if (ret) { 227062306a36Sopenharmony_ci dev_err(dev, "Cannot retrieve UID\n"); 227162306a36Sopenharmony_ci return ret; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci priv->bus = bus_id; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci return 0; 227762306a36Sopenharmony_ci} 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_cistatic int mlxbf_i2c_probe(struct platform_device *pdev) 228062306a36Sopenharmony_ci{ 228162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 228262306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv; 228362306a36Sopenharmony_ci struct i2c_adapter *adap; 228462306a36Sopenharmony_ci u32 resource_version; 228562306a36Sopenharmony_ci int irq, ret; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_priv), GFP_KERNEL); 228862306a36Sopenharmony_ci if (!priv) 228962306a36Sopenharmony_ci return -ENOMEM; 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci ret = mlxbf_i2c_acpi_probe(dev, priv); 229262306a36Sopenharmony_ci if (ret < 0) 229362306a36Sopenharmony_ci return ret; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* This property allows the driver to stay backward compatible with older 229662306a36Sopenharmony_ci * ACPI tables. 229762306a36Sopenharmony_ci * Starting BlueField-3 SoC, the "smbus" resource was broken down into 3 229862306a36Sopenharmony_ci * separate resources "timer", "master" and "slave". 229962306a36Sopenharmony_ci */ 230062306a36Sopenharmony_ci if (device_property_read_u32(dev, "resource_version", &resource_version)) 230162306a36Sopenharmony_ci resource_version = 0; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci priv->resource_version = resource_version; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && resource_version == 0) { 230662306a36Sopenharmony_ci priv->timer = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); 230762306a36Sopenharmony_ci if (!priv->timer) 230862306a36Sopenharmony_ci return -ENOMEM; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci priv->mst = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); 231162306a36Sopenharmony_ci if (!priv->mst) 231262306a36Sopenharmony_ci return -ENOMEM; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci priv->slv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); 231562306a36Sopenharmony_ci if (!priv->slv) 231662306a36Sopenharmony_ci return -ENOMEM; 231762306a36Sopenharmony_ci 231862306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, 231962306a36Sopenharmony_ci MLXBF_I2C_SMBUS_RES); 232062306a36Sopenharmony_ci if (ret < 0) 232162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch smbus resource info"); 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_ci priv->timer->io = priv->smbus->io; 232462306a36Sopenharmony_ci priv->mst->io = priv->smbus->io + MLXBF_I2C_MST_ADDR_OFFSET; 232562306a36Sopenharmony_ci priv->slv->io = priv->smbus->io + MLXBF_I2C_SLV_ADDR_OFFSET; 232662306a36Sopenharmony_ci } else { 232762306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->timer, 232862306a36Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_RES); 232962306a36Sopenharmony_ci if (ret < 0) 233062306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch timer resource info"); 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->mst, 233362306a36Sopenharmony_ci MLXBF_I2C_SMBUS_MST_RES); 233462306a36Sopenharmony_ci if (ret < 0) 233562306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch master resource info"); 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->slv, 233862306a36Sopenharmony_ci MLXBF_I2C_SMBUS_SLV_RES); 233962306a36Sopenharmony_ci if (ret < 0) 234062306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch slave resource info"); 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause, 234462306a36Sopenharmony_ci MLXBF_I2C_MST_CAUSE_RES); 234562306a36Sopenharmony_ci if (ret < 0) 234662306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch cause master resource info"); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->slv_cause, 234962306a36Sopenharmony_ci MLXBF_I2C_SLV_CAUSE_RES); 235062306a36Sopenharmony_ci if (ret < 0) 235162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot fetch cause slave resource info"); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci adap = &priv->adap; 235462306a36Sopenharmony_ci adap->owner = THIS_MODULE; 235562306a36Sopenharmony_ci adap->class = I2C_CLASS_HWMON; 235662306a36Sopenharmony_ci adap->algo = &mlxbf_i2c_algo; 235762306a36Sopenharmony_ci adap->quirks = &mlxbf_i2c_quirks; 235862306a36Sopenharmony_ci adap->dev.parent = dev; 235962306a36Sopenharmony_ci adap->dev.of_node = dev->of_node; 236062306a36Sopenharmony_ci adap->nr = priv->bus; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci snprintf(adap->name, sizeof(adap->name), "i2c%d", adap->nr); 236362306a36Sopenharmony_ci i2c_set_adapdata(adap, priv); 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci /* Read Core PLL frequency. */ 236662306a36Sopenharmony_ci ret = mlxbf_i2c_calculate_corepll_freq(pdev, priv); 236762306a36Sopenharmony_ci if (ret < 0) { 236862306a36Sopenharmony_ci dev_err(dev, "cannot get core clock frequency\n"); 236962306a36Sopenharmony_ci /* Set to default value. */ 237062306a36Sopenharmony_ci priv->frequency = MLXBF_I2C_COREPLL_FREQ; 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci /* 237462306a36Sopenharmony_ci * Initialize master. 237562306a36Sopenharmony_ci * Note that a physical bus might be shared among Linux and firmware 237662306a36Sopenharmony_ci * (e.g., ATF). Thus, the bus should be initialized and ready and 237762306a36Sopenharmony_ci * bus initialization would be unnecessary. This requires additional 237862306a36Sopenharmony_ci * knowledge about physical busses. But, since an extra initialization 237962306a36Sopenharmony_ci * does not really hurt, then keep the code as is. 238062306a36Sopenharmony_ci */ 238162306a36Sopenharmony_ci ret = mlxbf_i2c_init_master(pdev, priv); 238262306a36Sopenharmony_ci if (ret < 0) 238362306a36Sopenharmony_ci return dev_err_probe(dev, ret, "failed to initialize smbus master %d", 238462306a36Sopenharmony_ci priv->bus); 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci mlxbf_i2c_init_timings(pdev, priv); 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci mlxbf_i2c_init_slave(pdev, priv); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 239162306a36Sopenharmony_ci if (irq < 0) 239262306a36Sopenharmony_ci return irq; 239362306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, mlxbf_i2c_irq, 239462306a36Sopenharmony_ci IRQF_SHARED | IRQF_PROBE_SHARED, 239562306a36Sopenharmony_ci dev_name(dev), priv); 239662306a36Sopenharmony_ci if (ret < 0) 239762306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq); 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci priv->irq = irq; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci platform_set_drvdata(pdev, priv); 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci ret = i2c_add_numbered_adapter(adap); 240462306a36Sopenharmony_ci if (ret < 0) 240562306a36Sopenharmony_ci return ret; 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci mutex_lock(&mlxbf_i2c_bus_lock); 240862306a36Sopenharmony_ci mlxbf_i2c_bus_count++; 240962306a36Sopenharmony_ci mutex_unlock(&mlxbf_i2c_bus_lock); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci return 0; 241262306a36Sopenharmony_ci} 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_cistatic void mlxbf_i2c_remove(struct platform_device *pdev) 241562306a36Sopenharmony_ci{ 241662306a36Sopenharmony_ci struct mlxbf_i2c_priv *priv = platform_get_drvdata(pdev); 241762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 241862306a36Sopenharmony_ci struct resource *params; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && priv->resource_version == 0) { 242162306a36Sopenharmony_ci params = priv->smbus->params; 242262306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 242362306a36Sopenharmony_ci } else { 242462306a36Sopenharmony_ci params = priv->timer->params; 242562306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci params = priv->mst->params; 242862306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci params = priv->slv->params; 243162306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_ci params = priv->mst_cause->params; 243562306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci params = priv->slv_cause->params; 243862306a36Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci /* 244162306a36Sopenharmony_ci * Release shared resources. This should be done when releasing 244262306a36Sopenharmony_ci * the I2C controller. 244362306a36Sopenharmony_ci */ 244462306a36Sopenharmony_ci mutex_lock(&mlxbf_i2c_bus_lock); 244562306a36Sopenharmony_ci if (--mlxbf_i2c_bus_count == 0) { 244662306a36Sopenharmony_ci mlxbf_i2c_release_coalesce(pdev, priv); 244762306a36Sopenharmony_ci mlxbf_i2c_release_corepll(pdev, priv); 244862306a36Sopenharmony_ci mlxbf_i2c_release_gpio(pdev, priv); 244962306a36Sopenharmony_ci } 245062306a36Sopenharmony_ci mutex_unlock(&mlxbf_i2c_bus_lock); 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci devm_free_irq(dev, priv->irq, priv); 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_ci i2c_del_adapter(&priv->adap); 245562306a36Sopenharmony_ci} 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_cistatic struct platform_driver mlxbf_i2c_driver = { 245862306a36Sopenharmony_ci .probe = mlxbf_i2c_probe, 245962306a36Sopenharmony_ci .remove_new = mlxbf_i2c_remove, 246062306a36Sopenharmony_ci .driver = { 246162306a36Sopenharmony_ci .name = "i2c-mlxbf", 246262306a36Sopenharmony_ci .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), 246362306a36Sopenharmony_ci }, 246462306a36Sopenharmony_ci}; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_cistatic int __init mlxbf_i2c_init(void) 246762306a36Sopenharmony_ci{ 246862306a36Sopenharmony_ci mutex_init(&mlxbf_i2c_coalesce_lock); 246962306a36Sopenharmony_ci mutex_init(&mlxbf_i2c_corepll_lock); 247062306a36Sopenharmony_ci mutex_init(&mlxbf_i2c_gpio_lock); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci mutex_init(&mlxbf_i2c_bus_lock); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci return platform_driver_register(&mlxbf_i2c_driver); 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_cimodule_init(mlxbf_i2c_init); 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_cistatic void __exit mlxbf_i2c_exit(void) 247962306a36Sopenharmony_ci{ 248062306a36Sopenharmony_ci platform_driver_unregister(&mlxbf_i2c_driver); 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci mutex_destroy(&mlxbf_i2c_bus_lock); 248362306a36Sopenharmony_ci 248462306a36Sopenharmony_ci mutex_destroy(&mlxbf_i2c_gpio_lock); 248562306a36Sopenharmony_ci mutex_destroy(&mlxbf_i2c_corepll_lock); 248662306a36Sopenharmony_ci mutex_destroy(&mlxbf_i2c_coalesce_lock); 248762306a36Sopenharmony_ci} 248862306a36Sopenharmony_cimodule_exit(mlxbf_i2c_exit); 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox BlueField I2C bus driver"); 249162306a36Sopenharmony_ciMODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>"); 249262306a36Sopenharmony_ciMODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>"); 249362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2494