18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Mellanox BlueField I2C bus driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Mellanox Technologies, Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/acpi.h> 98c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/i2c.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <linux/of_device.h> 198c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 208c2ecf20Sopenharmony_ci#include <linux/string.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Defines what functionality is present. */ 238c2ecf20Sopenharmony_ci#define MLXBF_I2C_FUNC_SMBUS_BLOCK \ 248c2ecf20Sopenharmony_ci (I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define MLXBF_I2C_FUNC_SMBUS_DEFAULT \ 278c2ecf20Sopenharmony_ci (I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | \ 288c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK | \ 298c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_PROC_CALL) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define MLXBF_I2C_FUNC_ALL \ 328c2ecf20Sopenharmony_ci (MLXBF_I2C_FUNC_SMBUS_DEFAULT | MLXBF_I2C_FUNC_SMBUS_BLOCK | \ 338c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SLAVE) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MAX 3 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Shared resources info in BlueField platforms. */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define MLXBF_I2C_COALESCE_TYU_ADDR 0x02801300 408c2ecf20Sopenharmony_ci#define MLXBF_I2C_COALESCE_TYU_SIZE 0x010 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_TYU_ADDR 0x02802000 438c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_TYU_SIZE 0x100 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_TYU_ADDR 0x02800358 468c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_TYU_SIZE 0x008 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_YU_ADDR 0x02800c30 498c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_YU_SIZE 0x00c 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define MLXBF_I2C_SHARED_RES_MAX 3 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Note that the following SMBus, CAUSE, GPIO and PLL register addresses 558c2ecf20Sopenharmony_ci * refer to their respective offsets relative to the corresponding 568c2ecf20Sopenharmony_ci * memory-mapped region whose addresses are specified in either the DT or 578c2ecf20Sopenharmony_ci * the ACPI tables or above. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * SMBus Master core clock frequency. Timing configurations are 628c2ecf20Sopenharmony_ci * strongly dependent on the core clock frequency of the SMBus 638c2ecf20Sopenharmony_ci * Master. Default value is set to 400MHz. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000) 668c2ecf20Sopenharmony_ci/* Reference clock for Bluefield - 156 MHz. */ 678c2ecf20Sopenharmony_ci#define MLXBF_I2C_PLL_IN_FREQ 156250000ULL 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Constant used to determine the PLL frequency. */ 708c2ecf20Sopenharmony_ci#define MLNXBF_I2C_COREPLL_CONST 16384ULL 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000ULL 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* PLL registers. */ 758c2ecf20Sopenharmony_ci#define MLXBF_I2C_CORE_PLL_REG1 0x4 768c2ecf20Sopenharmony_ci#define MLXBF_I2C_CORE_PLL_REG2 0x8 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* OR cause register. */ 798c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_OR_EVTEN0 0x14 808c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_OR_CLEAR 0x18 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Arbiter Cause Register. */ 838c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_ARBITER 0x1c 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * Cause Status flags. Note that those bits might be considered 878c2ecf20Sopenharmony_ci * as interrupt enabled bits. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Transaction ended with STOP. */ 918c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_TRANSACTION_ENDED BIT(0) 928c2ecf20Sopenharmony_ci/* Master arbitration lost. */ 938c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_ARBITRATION_LOST BIT(1) 948c2ecf20Sopenharmony_ci/* Unexpected start detected. */ 958c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_UNEXPECTED_START BIT(2) 968c2ecf20Sopenharmony_ci/* Unexpected stop detected. */ 978c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_UNEXPECTED_STOP BIT(3) 988c2ecf20Sopenharmony_ci/* Wait for transfer continuation. */ 998c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_WAIT_FOR_FW_DATA BIT(4) 1008c2ecf20Sopenharmony_ci/* Failed to generate STOP. */ 1018c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_PUT_STOP_FAILED BIT(5) 1028c2ecf20Sopenharmony_ci/* Failed to generate START. */ 1038c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_PUT_START_FAILED BIT(6) 1048c2ecf20Sopenharmony_ci/* Clock toggle completed. */ 1058c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_CLK_TOGGLE_DONE BIT(7) 1068c2ecf20Sopenharmony_ci/* Transfer timeout occurred. */ 1078c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_FW_TIMEOUT BIT(8) 1088c2ecf20Sopenharmony_ci/* Master busy bit reset. */ 1098c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_M_GW_BUSY_FALL BIT(9) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK GENMASK(9, 0) 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_MASTER_STATUS_ERROR \ 1148c2ecf20Sopenharmony_ci (MLXBF_I2C_CAUSE_M_ARBITRATION_LOST | \ 1158c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_UNEXPECTED_START | \ 1168c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_UNEXPECTED_STOP | \ 1178c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_PUT_STOP_FAILED | \ 1188c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_PUT_START_FAILED | \ 1198c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_CLK_TOGGLE_DONE | \ 1208c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_M_FW_TIMEOUT) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* 1238c2ecf20Sopenharmony_ci * Slave cause status flags. Note that those bits might be considered 1248c2ecf20Sopenharmony_ci * as interrupt enabled bits. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* Write transaction received successfully. */ 1288c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_WRITE_SUCCESS BIT(0) 1298c2ecf20Sopenharmony_ci/* Read transaction received, waiting for response. */ 1308c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE BIT(13) 1318c2ecf20Sopenharmony_ci/* Slave busy bit reset. */ 1328c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_S_GW_BUSY_FALL BIT(18) 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_SLAVE_ARBITER_BITS_MASK GENMASK(20, 0) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* Cause coalesce registers. */ 1378c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_COALESCE_0 0x00 1388c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_COALESCE_1 0x04 1398c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_COALESCE_2 0x08 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT MLXBF_I2C_SMBUS_MAX 1428c2ecf20Sopenharmony_ci#define MLXBF_I2C_CAUSE_YU_SLAVE_BIT 1 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* Functional enable register. */ 1458c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_0_FUNC_EN_0 0x28 1468c2ecf20Sopenharmony_ci/* Force OE enable register. */ 1478c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_0_FORCE_OE_EN 0x30 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * Note that Smbus GWs are on GPIOs 30:25. Two pins are used to control 1508c2ecf20Sopenharmony_ci * SDA/SCL lines: 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * SMBUS GW0 -> bits[26:25] 1538c2ecf20Sopenharmony_ci * SMBUS GW1 -> bits[28:27] 1548c2ecf20Sopenharmony_ci * SMBUS GW2 -> bits[30:29] 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_PINS(num) (25 + ((num) << 1)) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* Note that gw_id can be 0,1 or 2. */ 1598c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_MASK(num) \ 1608c2ecf20Sopenharmony_ci (0xffffffff & (~(0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num)))) 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(num, val) \ 1638c2ecf20Sopenharmony_ci ((val) & MLXBF_I2C_GPIO_SMBUS_GW_MASK(num)) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(num, val) \ 1668c2ecf20Sopenharmony_ci ((val) | (0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num))) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* SMBus timing parameters. */ 1698c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 1708c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 1718c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 1728c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c 1738c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 1748c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 1758c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cienum { 1788c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_100KHZ = 100000, 1798c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_400KHZ = 400000, 1808c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_1000KHZ = 1000000, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * Defines SMBus operating frequency and core clock frequency. 1858c2ecf20Sopenharmony_ci * According to ADB files, default values are compliant to 100KHz SMBus 1868c2ecf20Sopenharmony_ci * @ 400MHz core clock. The driver should be able to calculate core 1878c2ecf20Sopenharmony_ci * frequency based on PLL parameters. 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_FREQ MLXBF_I2C_TYU_PLL_OUT_FREQ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* Core PLL TYU configuration. */ 1928c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(15, 3) 1938c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(19, 16) 1948c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(25, 20) 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* Core PLL YU configuration. */ 1978c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_F_YU_MASK GENMASK(25, 0) 1988c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0) 1998c2ecf20Sopenharmony_ci#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26) 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* Core PLL frequency. */ 2038c2ecf20Sopenharmony_cistatic u64 mlxbf_i2c_corepll_frequency; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* SMBus Master GW. */ 2068c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_GW 0x200 2078c2ecf20Sopenharmony_ci/* Number of bytes received and sent. */ 2088c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_RS_BYTES 0x300 2098c2ecf20Sopenharmony_ci/* Packet error check (PEC) value. */ 2108c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_PEC 0x304 2118c2ecf20Sopenharmony_ci/* Status bits (ACK/NACK/FW Timeout). */ 2128c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x308 2138c2ecf20Sopenharmony_ci/* SMbus Master Finite State Machine. */ 2148c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_FSM 0x310 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci/* 2178c2ecf20Sopenharmony_ci * When enabled, the master will issue a stop condition in case of 2188c2ecf20Sopenharmony_ci * timeout while waiting for FW response. 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_EN_FW_TIMEOUT 0x31c 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* SMBus master GW control bits offset in MLXBF_I2C_SMBUS_MASTER_GW[31:3]. */ 2238c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_LOCK_BIT BIT(31) /* Lock bit. */ 2248c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_BUSY_BIT BIT(30) /* Busy bit. */ 2258c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_START_BIT BIT(29) /* Control start. */ 2268c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_CTL_WRITE_BIT BIT(28) /* Control write phase. */ 2278c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_CTL_READ_BIT BIT(19) /* Control read phase. */ 2288c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_STOP_BIT BIT(3) /* Control stop. */ 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE \ 2318c2ecf20Sopenharmony_ci (MLXBF_I2C_MASTER_LOCK_BIT | MLXBF_I2C_MASTER_BUSY_BIT | \ 2328c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_START_BIT | MLXBF_I2C_MASTER_STOP_BIT) 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE_WRITE \ 2358c2ecf20Sopenharmony_ci (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_WRITE_BIT) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_ENABLE_READ \ 2388c2ecf20Sopenharmony_ci (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_READ_BIT) 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address shift. */ 2418c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes shift. */ 2428c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte shift. */ 2438c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Parse expected bytes shift. */ 2448c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes shift. */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* SMBus master GW Data descriptor. */ 2478c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x280 2488c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_DESC_SIZE 0x80 /* Size in bytes. */ 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* Maximum bytes to read/write per SMBus transaction. */ 2518c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_R_LENGTH MLXBF_I2C_MASTER_DATA_DESC_SIZE 2528c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASTER_DATA_W_LENGTH (MLXBF_I2C_MASTER_DATA_DESC_SIZE - 1) 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* All bytes were transmitted. */ 2558c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_BYTE_CNT_DONE BIT(0) 2568c2ecf20Sopenharmony_ci/* NACK received. */ 2578c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_NACK_RCV BIT(1) 2588c2ecf20Sopenharmony_ci/* Slave's byte count >128 bytes. */ 2598c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_READ_ERR BIT(2) 2608c2ecf20Sopenharmony_ci/* Timeout occurred. */ 2618c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_STATUS_FW_TIMEOUT BIT(3) 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS_MASK GENMASK(3, 0) 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_STATUS_ERROR \ 2668c2ecf20Sopenharmony_ci (MLXBF_I2C_SMBUS_STATUS_NACK_RCV | \ 2678c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_STATUS_READ_ERR | \ 2688c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_STATUS_FW_TIMEOUT) 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK BIT(31) 2718c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK BIT(15) 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* SMBus slave GW. */ 2748c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_GW 0x400 2758c2ecf20Sopenharmony_ci/* Number of bytes received and sent from/to master. */ 2768c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x500 2778c2ecf20Sopenharmony_ci/* Packet error check (PEC) value. */ 2788c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x504 2798c2ecf20Sopenharmony_ci/* SMBus slave Finite State Machine (FSM). */ 2808c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x510 2818c2ecf20Sopenharmony_ci/* 2828c2ecf20Sopenharmony_ci * Should be set when all raised causes handled, and cleared by HW on 2838c2ecf20Sopenharmony_ci * every new cause. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_READY 0x52c 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* SMBus slave GW control bits offset in MLXBF_I2C_SMBUS_SLAVE_GW[31:19]. */ 2888c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_BUSY_BIT BIT(30) /* Busy bit. */ 2898c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_WRITE_BIT BIT(29) /* Control write enable. */ 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_ENABLE \ 2928c2ecf20Sopenharmony_ci (MLXBF_I2C_SLAVE_BUSY_BIT | MLXBF_I2C_SLAVE_WRITE_BIT) 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT 22 /* Number of bytes to write. */ 2958c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_SEND_PEC_SHIFT 21 /* Send PEC byte shift. */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* SMBus slave GW Data descriptor. */ 2988c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x480 2998c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_DATA_DESC_SIZE 0x80 /* Size in bytes. */ 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* SMbus slave configuration registers. */ 3028c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x514 3038c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT 16 3048c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT 7 3058c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0) 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci#define MLXBF_I2C_SLAVE_ADDR_ENABLED(addr) \ 3088c2ecf20Sopenharmony_ci ((addr) & (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/* 3118c2ecf20Sopenharmony_ci * Timeout is given in microsends. Note also that timeout handling is not 3128c2ecf20Sopenharmony_ci * exact. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */ 3158c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* Encapsulates timing parameters. */ 3188c2ecf20Sopenharmony_cistruct mlxbf_i2c_timings { 3198c2ecf20Sopenharmony_ci u16 scl_high; /* Clock high period. */ 3208c2ecf20Sopenharmony_ci u16 scl_low; /* Clock low period. */ 3218c2ecf20Sopenharmony_ci u8 sda_rise; /* Data rise time. */ 3228c2ecf20Sopenharmony_ci u8 sda_fall; /* Data fall time. */ 3238c2ecf20Sopenharmony_ci u8 scl_rise; /* Clock rise time. */ 3248c2ecf20Sopenharmony_ci u8 scl_fall; /* Clock fall time. */ 3258c2ecf20Sopenharmony_ci u16 hold_start; /* Hold time after (REPEATED) START. */ 3268c2ecf20Sopenharmony_ci u16 hold_data; /* Data hold time. */ 3278c2ecf20Sopenharmony_ci u16 setup_start; /* REPEATED START condition setup time. */ 3288c2ecf20Sopenharmony_ci u16 setup_stop; /* STOP condition setup time. */ 3298c2ecf20Sopenharmony_ci u16 setup_data; /* Data setup time. */ 3308c2ecf20Sopenharmony_ci u16 pad; /* Padding. */ 3318c2ecf20Sopenharmony_ci u16 buf; /* Bus free time between STOP and START. */ 3328c2ecf20Sopenharmony_ci u16 thigh_max; /* Thigh max. */ 3338c2ecf20Sopenharmony_ci u32 timeout; /* Detect clock low timeout. */ 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cienum { 3378c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ = BIT(0), 3388c2ecf20Sopenharmony_ci MLXBF_I2C_F_WRITE = BIT(1), 3398c2ecf20Sopenharmony_ci MLXBF_I2C_F_NORESTART = BIT(3), 3408c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), 3418c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), 3428c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_PEC = BIT(6), 3438c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistruct mlxbf_i2c_smbus_operation { 3478c2ecf20Sopenharmony_ci u32 flags; 3488c2ecf20Sopenharmony_ci u32 length; /* Buffer length in bytes. */ 3498c2ecf20Sopenharmony_ci u8 *buffer; 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_1 1 3538c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_2 2 3548c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_OP_CNT_3 3 3558c2ecf20Sopenharmony_ci#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistruct mlxbf_i2c_smbus_request { 3588c2ecf20Sopenharmony_ci u8 slave; 3598c2ecf20Sopenharmony_ci u8 operation_cnt; 3608c2ecf20Sopenharmony_ci struct mlxbf_i2c_smbus_operation operation[MLXBF_I2C_SMBUS_MAX_OP_CNT]; 3618c2ecf20Sopenharmony_ci}; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistruct mlxbf_i2c_resource { 3648c2ecf20Sopenharmony_ci void __iomem *io; 3658c2ecf20Sopenharmony_ci struct resource *params; 3668c2ecf20Sopenharmony_ci struct mutex *lock; /* Mutex to protect mlxbf_i2c_resource. */ 3678c2ecf20Sopenharmony_ci u8 type; 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/* List of chip resources that are being accessed by the driver. */ 3718c2ecf20Sopenharmony_cienum { 3728c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_RES, 3738c2ecf20Sopenharmony_ci MLXBF_I2C_MST_CAUSE_RES, 3748c2ecf20Sopenharmony_ci MLXBF_I2C_SLV_CAUSE_RES, 3758c2ecf20Sopenharmony_ci MLXBF_I2C_COALESCE_RES, 3768c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_RES, 3778c2ecf20Sopenharmony_ci MLXBF_I2C_GPIO_RES, 3788c2ecf20Sopenharmony_ci MLXBF_I2C_END_RES, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci/* Helper macro to define an I2C resource parameters. */ 3828c2ecf20Sopenharmony_ci#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ 3838c2ecf20Sopenharmony_ci { \ 3848c2ecf20Sopenharmony_ci .start = (addr), \ 3858c2ecf20Sopenharmony_ci .end = (addr) + (size) - 1, \ 3868c2ecf20Sopenharmony_ci .name = (str) \ 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic struct resource mlxbf_i2c_coalesce_tyu_params = 3908c2ecf20Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COALESCE_TYU_ADDR, 3918c2ecf20Sopenharmony_ci MLXBF_I2C_COALESCE_TYU_SIZE, 3928c2ecf20Sopenharmony_ci "COALESCE_MEM"); 3938c2ecf20Sopenharmony_cistatic struct resource mlxbf_i2c_corepll_tyu_params = 3948c2ecf20Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_TYU_ADDR, 3958c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_TYU_SIZE, 3968c2ecf20Sopenharmony_ci "COREPLL_MEM"); 3978c2ecf20Sopenharmony_cistatic struct resource mlxbf_i2c_corepll_yu_params = 3988c2ecf20Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_YU_ADDR, 3998c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_YU_SIZE, 4008c2ecf20Sopenharmony_ci "COREPLL_MEM"); 4018c2ecf20Sopenharmony_cistatic struct resource mlxbf_i2c_gpio_tyu_params = 4028c2ecf20Sopenharmony_ci MLXBF_I2C_RES_PARAMS(MLXBF_I2C_GPIO_TYU_ADDR, 4038c2ecf20Sopenharmony_ci MLXBF_I2C_GPIO_TYU_SIZE, 4048c2ecf20Sopenharmony_ci "GPIO_MEM"); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic struct mutex mlxbf_i2c_coalesce_lock; 4078c2ecf20Sopenharmony_cistatic struct mutex mlxbf_i2c_corepll_lock; 4088c2ecf20Sopenharmony_cistatic struct mutex mlxbf_i2c_gpio_lock; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci/* Mellanox BlueField chip type. */ 4118c2ecf20Sopenharmony_cienum mlxbf_i2c_chip_type { 4128c2ecf20Sopenharmony_ci MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ 4138c2ecf20Sopenharmony_ci MLXBF_I2C_CHIP_TYPE_2, /* Mallanox BlueField-2 chip. */ 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistruct mlxbf_i2c_chip_info { 4178c2ecf20Sopenharmony_ci enum mlxbf_i2c_chip_type type; 4188c2ecf20Sopenharmony_ci /* Chip shared resources that are being used by the I2C controller. */ 4198c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Callback to calculate the core PLL frequency. */ 4228c2ecf20Sopenharmony_ci u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); 4238c2ecf20Sopenharmony_ci}; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistruct mlxbf_i2c_priv { 4268c2ecf20Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip; 4278c2ecf20Sopenharmony_ci struct i2c_adapter adap; 4288c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *smbus; 4298c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *mst_cause; 4308c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *slv_cause; 4318c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *coalesce; 4328c2ecf20Sopenharmony_ci u64 frequency; /* Core frequency in Hz. */ 4338c2ecf20Sopenharmony_ci int bus; /* Physical bus identifier. */ 4348c2ecf20Sopenharmony_ci int irq; 4358c2ecf20Sopenharmony_ci struct i2c_client *slave; 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = { 4398c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 4408c2ecf20Sopenharmony_ci .params = &mlxbf_i2c_coalesce_tyu_params, 4418c2ecf20Sopenharmony_ci .lock = &mlxbf_i2c_coalesce_lock, 4428c2ecf20Sopenharmony_ci .type = MLXBF_I2C_COALESCE_RES 4438c2ecf20Sopenharmony_ci }, 4448c2ecf20Sopenharmony_ci {} 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_corepll_res[] = { 4488c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 4498c2ecf20Sopenharmony_ci .params = &mlxbf_i2c_corepll_tyu_params, 4508c2ecf20Sopenharmony_ci .lock = &mlxbf_i2c_corepll_lock, 4518c2ecf20Sopenharmony_ci .type = MLXBF_I2C_COREPLL_RES 4528c2ecf20Sopenharmony_ci }, 4538c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_2] = { 4548c2ecf20Sopenharmony_ci .params = &mlxbf_i2c_corepll_yu_params, 4558c2ecf20Sopenharmony_ci .lock = &mlxbf_i2c_corepll_lock, 4568c2ecf20Sopenharmony_ci .type = MLXBF_I2C_COREPLL_RES, 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic struct mlxbf_i2c_resource mlxbf_i2c_gpio_res[] = { 4618c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 4628c2ecf20Sopenharmony_ci .params = &mlxbf_i2c_gpio_tyu_params, 4638c2ecf20Sopenharmony_ci .lock = &mlxbf_i2c_gpio_lock, 4648c2ecf20Sopenharmony_ci .type = MLXBF_I2C_GPIO_RES 4658c2ecf20Sopenharmony_ci }, 4668c2ecf20Sopenharmony_ci {} 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic u8 mlxbf_i2c_bus_count; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct mutex mlxbf_i2c_bus_lock; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* Polling frequency in microseconds. */ 4748c2ecf20Sopenharmony_ci#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci#define MLXBF_I2C_SHIFT_0 0 4778c2ecf20Sopenharmony_ci#define MLXBF_I2C_SHIFT_8 8 4788c2ecf20Sopenharmony_ci#define MLXBF_I2C_SHIFT_16 16 4798c2ecf20Sopenharmony_ci#define MLXBF_I2C_SHIFT_24 24 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASK_8 GENMASK(7, 0) 4828c2ecf20Sopenharmony_ci#define MLXBF_I2C_MASK_16 GENMASK(15, 0) 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* 4858c2ecf20Sopenharmony_ci * Function to poll a set of bits at a specific address; it checks whether 4868c2ecf20Sopenharmony_ci * the bits are equal to zero when eq_zero is set to 'true', and not equal 4878c2ecf20Sopenharmony_ci * to zero when eq_zero is set to 'false'. 4888c2ecf20Sopenharmony_ci * Note that the timeout is given in microseconds. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_cistatic u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask, 4918c2ecf20Sopenharmony_ci bool eq_zero, u32 timeout) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci u32 bits; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci do { 4988c2ecf20Sopenharmony_ci bits = readl(io + addr) & mask; 4998c2ecf20Sopenharmony_ci if (eq_zero ? bits == 0 : bits != 0) 5008c2ecf20Sopenharmony_ci return eq_zero ? 1 : bits; 5018c2ecf20Sopenharmony_ci udelay(MLXBF_I2C_POLL_FREQ_IN_USEC); 5028c2ecf20Sopenharmony_ci } while (timeout-- != 0); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/* 5088c2ecf20Sopenharmony_ci * SW must make sure that the SMBus Master GW is idle before starting 5098c2ecf20Sopenharmony_ci * a transaction. Accordingly, this function polls the Master FSM stop 5108c2ecf20Sopenharmony_ci * bit; it returns false when the bit is asserted, true if not. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic bool mlxbf_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK; 5158c2ecf20Sopenharmony_ci u32 addr = MLXBF_I2C_SMBUS_MASTER_FSM; 5168c2ecf20Sopenharmony_ci u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (mlxbf_smbus_poll(priv->smbus->io, addr, mask, true, timeout)) 5198c2ecf20Sopenharmony_ci return true; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return false; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/* 5258c2ecf20Sopenharmony_ci * wait for the lock to be released before acquiring it. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_cistatic bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci if (mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, 5308c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_LOCK_BIT, true, 5318c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT)) 5328c2ecf20Sopenharmony_ci return true; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return false; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci /* Clear the gw to clear the lock */ 5408c2ecf20Sopenharmony_ci writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic bool mlxbf_i2c_smbus_transaction_success(u32 master_status, 5448c2ecf20Sopenharmony_ci u32 cause_status) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci /* 5478c2ecf20Sopenharmony_ci * When transaction ended with STOP, all bytes were transmitted, 5488c2ecf20Sopenharmony_ci * and no NACK received, then the transaction ended successfully. 5498c2ecf20Sopenharmony_ci * On the other hand, when the GW is configured with the stop bit 5508c2ecf20Sopenharmony_ci * de-asserted then the SMBus expects the following GW configuration 5518c2ecf20Sopenharmony_ci * for transfer continuation. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci if ((cause_status & MLXBF_I2C_CAUSE_WAIT_FOR_FW_DATA) || 5548c2ecf20Sopenharmony_ci ((cause_status & MLXBF_I2C_CAUSE_TRANSACTION_ENDED) && 5558c2ecf20Sopenharmony_ci (master_status & MLXBF_I2C_SMBUS_STATUS_BYTE_CNT_DONE) && 5568c2ecf20Sopenharmony_ci !(master_status & MLXBF_I2C_SMBUS_STATUS_NACK_RCV))) 5578c2ecf20Sopenharmony_ci return true; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return false; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci/* 5638c2ecf20Sopenharmony_ci * Poll SMBus master status and return transaction status, 5648c2ecf20Sopenharmony_ci * i.e. whether succeeded or failed. I2C and SMBus fault codes 5658c2ecf20Sopenharmony_ci * are returned as negative numbers from most calls, with zero 5668c2ecf20Sopenharmony_ci * or some positive number indicating a non-fault return. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_cistatic int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci u32 master_status_bits; 5718c2ecf20Sopenharmony_ci u32 cause_status_bits; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * GW busy bit is raised by the driver and cleared by the HW 5758c2ecf20Sopenharmony_ci * when the transaction is completed. The busy bit is a good 5768c2ecf20Sopenharmony_ci * indicator of transaction status. So poll the busy bit, and 5778c2ecf20Sopenharmony_ci * then read the cause and master status bits to determine if 5788c2ecf20Sopenharmony_ci * errors occurred during the transaction. 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci mlxbf_smbus_poll(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, 5818c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_BUSY_BIT, true, 5828c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_TIMEOUT); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* Read cause status bits. */ 5858c2ecf20Sopenharmony_ci cause_status_bits = readl(priv->mst_cause->io + 5868c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_ARBITER); 5878c2ecf20Sopenharmony_ci cause_status_bits &= MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * Parse both Cause and Master GW bits, then return transaction status. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci master_status_bits = readl(priv->smbus->io + 5948c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_MASTER_STATUS); 5958c2ecf20Sopenharmony_ci master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (mlxbf_i2c_smbus_transaction_success(master_status_bits, 5988c2ecf20Sopenharmony_ci cause_status_bits)) 5998c2ecf20Sopenharmony_ci return 0; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* 6028c2ecf20Sopenharmony_ci * In case of timeout on GW busy, the ISR will clear busy bit but 6038c2ecf20Sopenharmony_ci * transaction ended bits cause will not be set so the transaction 6048c2ecf20Sopenharmony_ci * fails. Then, we must check Master GW status bits. 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci if ((master_status_bits & MLXBF_I2C_SMBUS_MASTER_STATUS_ERROR) && 6078c2ecf20Sopenharmony_ci (cause_status_bits & (MLXBF_I2C_CAUSE_TRANSACTION_ENDED | 6088c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_M_GW_BUSY_FALL))) 6098c2ecf20Sopenharmony_ci return -EIO; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (cause_status_bits & MLXBF_I2C_CAUSE_MASTER_STATUS_ERROR) 6128c2ecf20Sopenharmony_ci return -EAGAIN; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, 6188c2ecf20Sopenharmony_ci const u8 *data, u8 length, u32 addr) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci u8 offset, aligned_length; 6218c2ecf20Sopenharmony_ci u32 data32; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci aligned_length = round_up(length, 4); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci /* 6268c2ecf20Sopenharmony_ci * Copy data bytes from 4-byte aligned source buffer. 6278c2ecf20Sopenharmony_ci * Data copied to the Master GW Data Descriptor MUST be shifted 6288c2ecf20Sopenharmony_ci * left so the data starts at the MSB of the descriptor registers 6298c2ecf20Sopenharmony_ci * as required by the underlying hardware. Enable byte swapping 6308c2ecf20Sopenharmony_ci * when writing data bytes to the 32 * 32-bit HW Data registers 6318c2ecf20Sopenharmony_ci * a.k.a Master GW Data Descriptor. 6328c2ecf20Sopenharmony_ci */ 6338c2ecf20Sopenharmony_ci for (offset = 0; offset < aligned_length; offset += sizeof(u32)) { 6348c2ecf20Sopenharmony_ci data32 = *((u32 *)(data + offset)); 6358c2ecf20Sopenharmony_ci iowrite32be(data32, priv->smbus->io + addr + offset); 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, 6408c2ecf20Sopenharmony_ci u8 *data, u8 length, u32 addr) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci u32 data32, mask; 6438c2ecf20Sopenharmony_ci u8 byte, offset; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci mask = sizeof(u32) - 1; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* 6488c2ecf20Sopenharmony_ci * Data bytes in the Master GW Data Descriptor are shifted left 6498c2ecf20Sopenharmony_ci * so the data starts at the MSB of the descriptor registers as 6508c2ecf20Sopenharmony_ci * set by the underlying hardware. Enable byte swapping while 6518c2ecf20Sopenharmony_ci * reading data bytes from the 32 * 32-bit HW Data registers 6528c2ecf20Sopenharmony_ci * a.k.a Master GW Data Descriptor. 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) { 6568c2ecf20Sopenharmony_ci data32 = ioread32be(priv->smbus->io + addr + offset); 6578c2ecf20Sopenharmony_ci *((u32 *)(data + offset)) = data32; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (!(length & mask)) 6618c2ecf20Sopenharmony_ci return; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci data32 = ioread32be(priv->smbus->io + addr + offset); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci for (byte = 0; byte < (length & mask); byte++) { 6668c2ecf20Sopenharmony_ci data[offset + byte] = data32 & GENMASK(7, 0); 6678c2ecf20Sopenharmony_ci data32 = ror32(data32, MLXBF_I2C_SHIFT_8); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, 6728c2ecf20Sopenharmony_ci u8 len, u8 block_en, u8 pec_en, bool read) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci u32 command; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* Set Master GW control word. */ 6778c2ecf20Sopenharmony_ci if (read) { 6788c2ecf20Sopenharmony_ci command = MLXBF_I2C_MASTER_ENABLE_READ; 6798c2ecf20Sopenharmony_ci command |= rol32(len, MLXBF_I2C_MASTER_READ_SHIFT); 6808c2ecf20Sopenharmony_ci } else { 6818c2ecf20Sopenharmony_ci command = MLXBF_I2C_MASTER_ENABLE_WRITE; 6828c2ecf20Sopenharmony_ci command |= rol32(len, MLXBF_I2C_MASTER_WRITE_SHIFT); 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci command |= rol32(slave, MLXBF_I2C_MASTER_SLV_ADDR_SHIFT); 6858c2ecf20Sopenharmony_ci command |= rol32(block_en, MLXBF_I2C_MASTER_PARSE_EXP_SHIFT); 6868c2ecf20Sopenharmony_ci command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* Clear status bits. */ 6898c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS); 6908c2ecf20Sopenharmony_ci /* Set the cause data. */ 6918c2ecf20Sopenharmony_ci writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 6928c2ecf20Sopenharmony_ci /* Zero PEC byte. */ 6938c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC); 6948c2ecf20Sopenharmony_ci /* Zero byte count. */ 6958c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* GW activation. */ 6988c2ecf20Sopenharmony_ci writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* 7018c2ecf20Sopenharmony_ci * Poll master status and check status bits. An ACK is sent when 7028c2ecf20Sopenharmony_ci * completing writing data to the bus (Master 'byte_count_done' bit 7038c2ecf20Sopenharmony_ci * is set to 1). 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci return mlxbf_i2c_smbus_check_status(priv); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic int 7098c2ecf20Sopenharmony_cimlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, 7108c2ecf20Sopenharmony_ci struct mlxbf_i2c_smbus_request *request) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci u8 data_desc[MLXBF_I2C_MASTER_DATA_DESC_SIZE] = { 0 }; 7138c2ecf20Sopenharmony_ci u8 op_idx, data_idx, data_len, write_len, read_len; 7148c2ecf20Sopenharmony_ci struct mlxbf_i2c_smbus_operation *operation; 7158c2ecf20Sopenharmony_ci u8 read_en, write_en, block_en, pec_en; 7168c2ecf20Sopenharmony_ci u8 slave, flags, addr; 7178c2ecf20Sopenharmony_ci u8 *read_buf; 7188c2ecf20Sopenharmony_ci int ret = 0; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (request->operation_cnt > MLXBF_I2C_SMBUS_MAX_OP_CNT) 7218c2ecf20Sopenharmony_ci return -EINVAL; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci read_buf = NULL; 7248c2ecf20Sopenharmony_ci data_idx = 0; 7258c2ecf20Sopenharmony_ci read_en = 0; 7268c2ecf20Sopenharmony_ci write_en = 0; 7278c2ecf20Sopenharmony_ci write_len = 0; 7288c2ecf20Sopenharmony_ci read_len = 0; 7298c2ecf20Sopenharmony_ci block_en = 0; 7308c2ecf20Sopenharmony_ci pec_en = 0; 7318c2ecf20Sopenharmony_ci slave = request->slave & GENMASK(6, 0); 7328c2ecf20Sopenharmony_ci addr = slave << 1; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * Try to acquire the smbus gw lock before any reads of the GW register since 7368c2ecf20Sopenharmony_ci * a read sets the lock. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv))) 7398c2ecf20Sopenharmony_ci return -EBUSY; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Check whether the HW is idle */ 7428c2ecf20Sopenharmony_ci if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) { 7438c2ecf20Sopenharmony_ci ret = -EBUSY; 7448c2ecf20Sopenharmony_ci goto out_unlock; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Set first byte. */ 7488c2ecf20Sopenharmony_ci data_desc[data_idx++] = addr; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci for (op_idx = 0; op_idx < request->operation_cnt; op_idx++) { 7518c2ecf20Sopenharmony_ci operation = &request->operation[op_idx]; 7528c2ecf20Sopenharmony_ci flags = operation->flags; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* 7558c2ecf20Sopenharmony_ci * Note that read and write operations might be handled by a 7568c2ecf20Sopenharmony_ci * single command. If the MLXBF_I2C_F_SMBUS_OPERATION is set 7578c2ecf20Sopenharmony_ci * then write command byte and set the optional SMBus specific 7588c2ecf20Sopenharmony_ci * bits such as block_en and pec_en. These bits MUST be 7598c2ecf20Sopenharmony_ci * submitted by the first operation only. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci if (op_idx == 0 && flags & MLXBF_I2C_F_SMBUS_OPERATION) { 7628c2ecf20Sopenharmony_ci block_en = flags & MLXBF_I2C_F_SMBUS_BLOCK; 7638c2ecf20Sopenharmony_ci pec_en = flags & MLXBF_I2C_F_SMBUS_PEC; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (flags & MLXBF_I2C_F_WRITE) { 7678c2ecf20Sopenharmony_ci write_en = 1; 7688c2ecf20Sopenharmony_ci write_len += operation->length; 7698c2ecf20Sopenharmony_ci if (data_idx + operation->length > 7708c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_SIZE) { 7718c2ecf20Sopenharmony_ci ret = -ENOBUFS; 7728c2ecf20Sopenharmony_ci goto out_unlock; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci memcpy(data_desc + data_idx, 7758c2ecf20Sopenharmony_ci operation->buffer, operation->length); 7768c2ecf20Sopenharmony_ci data_idx += operation->length; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci /* 7798c2ecf20Sopenharmony_ci * We assume that read operations are performed only once per 7808c2ecf20Sopenharmony_ci * SMBus transaction. *TBD* protect this statement so it won't 7818c2ecf20Sopenharmony_ci * be executed twice? or return an error if we try to read more 7828c2ecf20Sopenharmony_ci * than once? 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_ci if (flags & MLXBF_I2C_F_READ) { 7858c2ecf20Sopenharmony_ci read_en = 1; 7868c2ecf20Sopenharmony_ci /* Subtract 1 as required by HW. */ 7878c2ecf20Sopenharmony_ci read_len = operation->length - 1; 7888c2ecf20Sopenharmony_ci read_buf = operation->buffer; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* Set Master GW data descriptor. */ 7938c2ecf20Sopenharmony_ci data_len = write_len + 1; /* Add one byte of the slave address. */ 7948c2ecf20Sopenharmony_ci /* 7958c2ecf20Sopenharmony_ci * Note that data_len cannot be 0. Indeed, the slave address byte 7968c2ecf20Sopenharmony_ci * must be written to the data registers. 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, (const u8 *)data_desc, data_len, 7998c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (write_en) { 8028c2ecf20Sopenharmony_ci ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en, 8038c2ecf20Sopenharmony_ci pec_en, 0); 8048c2ecf20Sopenharmony_ci if (ret) 8058c2ecf20Sopenharmony_ci goto out_unlock; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci if (read_en) { 8098c2ecf20Sopenharmony_ci /* Write slave address to Master GW data descriptor. */ 8108c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1, 8118c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR); 8128c2ecf20Sopenharmony_ci ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en, 8138c2ecf20Sopenharmony_ci pec_en, 1); 8148c2ecf20Sopenharmony_ci if (!ret) { 8158c2ecf20Sopenharmony_ci /* Get Master GW data descriptor. */ 8168c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1, 8178c2ecf20Sopenharmony_ci MLXBF_I2C_MASTER_DATA_DESC_ADDR); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Get data from Master GW data descriptor. */ 8208c2ecf20Sopenharmony_ci memcpy(read_buf, data_desc, read_len + 1); 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* 8248c2ecf20Sopenharmony_ci * After a read operation the SMBus FSM ps (present state) 8258c2ecf20Sopenharmony_ci * needs to be 'manually' reset. This should be removed in 8268c2ecf20Sopenharmony_ci * next tag integration. 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK, 8298c2ecf20Sopenharmony_ci priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ciout_unlock: 8338c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_master_unlock(priv); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci return ret; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/* I2C SMBus protocols. */ 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic void 8418c2ecf20Sopenharmony_cimlxbf_i2c_smbus_quick_command(struct mlxbf_i2c_smbus_request *request, 8428c2ecf20Sopenharmony_ci u8 read) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_1; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci request->operation[0].length = 0; 8478c2ecf20Sopenharmony_ci request->operation[0].flags = MLXBF_I2C_F_WRITE; 8488c2ecf20Sopenharmony_ci request->operation[0].flags |= read ? MLXBF_I2C_F_READ : 0; 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic void mlxbf_i2c_smbus_byte_func(struct mlxbf_i2c_smbus_request *request, 8528c2ecf20Sopenharmony_ci u8 *data, bool read, bool pec_check) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_1; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci request->operation[0].length = 1; 8578c2ecf20Sopenharmony_ci request->operation[0].length += pec_check; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci request->operation[0].flags = MLXBF_I2C_F_SMBUS_OPERATION; 8608c2ecf20Sopenharmony_ci request->operation[0].flags |= read ? 8618c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 8628c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci request->operation[0].buffer = data; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic void 8688c2ecf20Sopenharmony_cimlxbf_i2c_smbus_data_byte_func(struct mlxbf_i2c_smbus_request *request, 8698c2ecf20Sopenharmony_ci u8 *command, u8 *data, bool read, bool pec_check) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci request->operation[0].length = 1; 8748c2ecf20Sopenharmony_ci request->operation[0].flags = 8758c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 8768c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 8778c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci request->operation[1].length = 1; 8808c2ecf20Sopenharmony_ci request->operation[1].length += pec_check; 8818c2ecf20Sopenharmony_ci request->operation[1].flags = read ? 8828c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 8838c2ecf20Sopenharmony_ci request->operation[1].buffer = data; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void 8878c2ecf20Sopenharmony_cimlxbf_i2c_smbus_data_word_func(struct mlxbf_i2c_smbus_request *request, 8888c2ecf20Sopenharmony_ci u8 *command, u8 *data, bool read, bool pec_check) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci request->operation[0].length = 1; 8938c2ecf20Sopenharmony_ci request->operation[0].flags = 8948c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 8958c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 8968c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci request->operation[1].length = 2; 8998c2ecf20Sopenharmony_ci request->operation[1].length += pec_check; 9008c2ecf20Sopenharmony_ci request->operation[1].flags = read ? 9018c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 9028c2ecf20Sopenharmony_ci request->operation[1].buffer = data; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void 9068c2ecf20Sopenharmony_cimlxbf_i2c_smbus_i2c_block_func(struct mlxbf_i2c_smbus_request *request, 9078c2ecf20Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, bool read, 9088c2ecf20Sopenharmony_ci bool pec_check) 9098c2ecf20Sopenharmony_ci{ 9108c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci request->operation[0].length = 1; 9138c2ecf20Sopenharmony_ci request->operation[0].flags = 9148c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 9158c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 9168c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* 9198c2ecf20Sopenharmony_ci * As specified in the standard, the max number of bytes to read/write 9208c2ecf20Sopenharmony_ci * per block operation is 32 bytes. In Golan code, the controller can 9218c2ecf20Sopenharmony_ci * read up to 128 bytes and write up to 127 bytes. 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci request->operation[1].length = 9248c2ecf20Sopenharmony_ci (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 9258c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 9268c2ecf20Sopenharmony_ci request->operation[1].flags = read ? 9278c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 9288c2ecf20Sopenharmony_ci /* 9298c2ecf20Sopenharmony_ci * Skip the first data byte, which corresponds to the number of bytes 9308c2ecf20Sopenharmony_ci * to read/write. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci request->operation[1].buffer = data + 1; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci *data_len = request->operation[1].length; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* Set the number of byte to read. This will be used by userspace. */ 9378c2ecf20Sopenharmony_ci if (read) 9388c2ecf20Sopenharmony_ci data[0] = *data_len; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_cistatic void mlxbf_i2c_smbus_block_func(struct mlxbf_i2c_smbus_request *request, 9428c2ecf20Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, 9438c2ecf20Sopenharmony_ci bool read, bool pec_check) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_2; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci request->operation[0].length = 1; 9488c2ecf20Sopenharmony_ci request->operation[0].flags = 9498c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 9508c2ecf20Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 9518c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 9528c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci request->operation[1].length = 9558c2ecf20Sopenharmony_ci (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 9568c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 9578c2ecf20Sopenharmony_ci request->operation[1].flags = read ? 9588c2ecf20Sopenharmony_ci MLXBF_I2C_F_READ : MLXBF_I2C_F_WRITE; 9598c2ecf20Sopenharmony_ci request->operation[1].buffer = data + 1; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci *data_len = request->operation[1].length; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* Set the number of bytes to read. This will be used by userspace. */ 9648c2ecf20Sopenharmony_ci if (read) 9658c2ecf20Sopenharmony_ci data[0] = *data_len; 9668c2ecf20Sopenharmony_ci} 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic void 9698c2ecf20Sopenharmony_cimlxbf_i2c_smbus_process_call_func(struct mlxbf_i2c_smbus_request *request, 9708c2ecf20Sopenharmony_ci u8 *command, u8 *data, bool pec_check) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_3; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci request->operation[0].length = 1; 9758c2ecf20Sopenharmony_ci request->operation[0].flags = 9768c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 9778c2ecf20Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 9788c2ecf20Sopenharmony_ci request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; 9798c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci request->operation[1].length = 2; 9828c2ecf20Sopenharmony_ci request->operation[1].flags = MLXBF_I2C_F_WRITE; 9838c2ecf20Sopenharmony_ci request->operation[1].buffer = data; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci request->operation[2].length = 3; 9868c2ecf20Sopenharmony_ci request->operation[2].flags = MLXBF_I2C_F_READ; 9878c2ecf20Sopenharmony_ci request->operation[2].buffer = data; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic void 9918c2ecf20Sopenharmony_cimlxbf_i2c_smbus_blk_process_call_func(struct mlxbf_i2c_smbus_request *request, 9928c2ecf20Sopenharmony_ci u8 *command, u8 *data, u8 *data_len, 9938c2ecf20Sopenharmony_ci bool pec_check) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci u32 length; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci request->operation_cnt = MLXBF_I2C_SMBUS_OP_CNT_3; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci request->operation[0].length = 1; 10008c2ecf20Sopenharmony_ci request->operation[0].flags = 10018c2ecf20Sopenharmony_ci MLXBF_I2C_F_SMBUS_OPERATION | MLXBF_I2C_F_WRITE; 10028c2ecf20Sopenharmony_ci request->operation[0].flags |= MLXBF_I2C_F_SMBUS_BLOCK; 10038c2ecf20Sopenharmony_ci request->operation[0].flags |= (pec_check) ? MLXBF_I2C_F_SMBUS_PEC : 0; 10048c2ecf20Sopenharmony_ci request->operation[0].buffer = command; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci length = (*data_len + pec_check > I2C_SMBUS_BLOCK_MAX) ? 10078c2ecf20Sopenharmony_ci I2C_SMBUS_BLOCK_MAX : *data_len + pec_check; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci request->operation[1].length = length - pec_check; 10108c2ecf20Sopenharmony_ci request->operation[1].flags = MLXBF_I2C_F_WRITE; 10118c2ecf20Sopenharmony_ci request->operation[1].buffer = data; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci request->operation[2].length = length; 10148c2ecf20Sopenharmony_ci request->operation[2].flags = MLXBF_I2C_F_READ; 10158c2ecf20Sopenharmony_ci request->operation[2].buffer = data; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci *data_len = length; /* including PEC byte. */ 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci/* Initialization functions. */ 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic bool mlxbf_i2c_has_chip_type(struct mlxbf_i2c_priv *priv, u8 type) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci return priv->chip->type == type; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic struct mlxbf_i2c_resource * 10288c2ecf20Sopenharmony_cimlxbf_i2c_get_shared_resource(struct mlxbf_i2c_priv *priv, u8 type) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 10318c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *res; 10328c2ecf20Sopenharmony_ci u8 res_idx = 0; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci for (res_idx = 0; res_idx < MLXBF_I2C_SHARED_RES_MAX; res_idx++) { 10358c2ecf20Sopenharmony_ci res = chip->shared_res[res_idx]; 10368c2ecf20Sopenharmony_ci if (res && res->type == type) 10378c2ecf20Sopenharmony_ci return res; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci return NULL; 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic int mlxbf_i2c_init_resource(struct platform_device *pdev, 10448c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource **res, 10458c2ecf20Sopenharmony_ci u8 type) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *tmp_res; 10488c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (!res || *res || type >= MLXBF_I2C_END_RES) 10518c2ecf20Sopenharmony_ci return -EINVAL; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci tmp_res = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), 10548c2ecf20Sopenharmony_ci GFP_KERNEL); 10558c2ecf20Sopenharmony_ci if (!tmp_res) 10568c2ecf20Sopenharmony_ci return -ENOMEM; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci tmp_res->params = platform_get_resource(pdev, IORESOURCE_MEM, type); 10598c2ecf20Sopenharmony_ci if (!tmp_res->params) { 10608c2ecf20Sopenharmony_ci devm_kfree(dev, tmp_res); 10618c2ecf20Sopenharmony_ci return -EIO; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci tmp_res->io = devm_ioremap_resource(dev, tmp_res->params); 10658c2ecf20Sopenharmony_ci if (IS_ERR(tmp_res->io)) { 10668c2ecf20Sopenharmony_ci devm_kfree(dev, tmp_res); 10678c2ecf20Sopenharmony_ci return PTR_ERR(tmp_res->io); 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci tmp_res->type = type; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci *res = tmp_res; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci return 0; 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic u32 mlxbf_i2c_get_ticks(struct mlxbf_i2c_priv *priv, u64 nanoseconds, 10788c2ecf20Sopenharmony_ci bool minimum) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci u64 frequency; 10818c2ecf20Sopenharmony_ci u32 ticks; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* 10848c2ecf20Sopenharmony_ci * Compute ticks as follow: 10858c2ecf20Sopenharmony_ci * 10868c2ecf20Sopenharmony_ci * Ticks 10878c2ecf20Sopenharmony_ci * Time = --------- x 10^9 => Ticks = Time x Frequency x 10^-9 10888c2ecf20Sopenharmony_ci * Frequency 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_ci frequency = priv->frequency; 10918c2ecf20Sopenharmony_ci ticks = (nanoseconds * frequency) / MLXBF_I2C_FREQUENCY_1GHZ; 10928c2ecf20Sopenharmony_ci /* 10938c2ecf20Sopenharmony_ci * The number of ticks is rounded down and if minimum is equal to 1 10948c2ecf20Sopenharmony_ci * then add one tick. 10958c2ecf20Sopenharmony_ci */ 10968c2ecf20Sopenharmony_ci if (minimum) 10978c2ecf20Sopenharmony_ci ticks++; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return ticks; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic u32 mlxbf_i2c_set_timer(struct mlxbf_i2c_priv *priv, u64 nsec, bool opt, 11038c2ecf20Sopenharmony_ci u32 mask, u8 shift) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci u32 val = (mlxbf_i2c_get_ticks(priv, nsec, opt) & mask) << shift; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return val; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, 11118c2ecf20Sopenharmony_ci const struct mlxbf_i2c_timings *timings) 11128c2ecf20Sopenharmony_ci{ 11138c2ecf20Sopenharmony_ci u32 timer; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->scl_high, 11168c2ecf20Sopenharmony_ci false, MLXBF_I2C_MASK_16, 11178c2ecf20Sopenharmony_ci MLXBF_I2C_SHIFT_0); 11188c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_low, 11198c2ecf20Sopenharmony_ci false, MLXBF_I2C_MASK_16, 11208c2ecf20Sopenharmony_ci MLXBF_I2C_SHIFT_16); 11218c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + 11228c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false, 11258c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_0); 11268c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->sda_fall, false, 11278c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_8); 11288c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_rise, false, 11298c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16); 11308c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false, 11318c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24); 11328c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + 11338c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true, 11368c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 11378c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true, 11388c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 11398c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true, 11428c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 11438c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true, 11448c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 11458c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + 11468c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true, 11498c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 11508c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci timer = mlxbf_i2c_set_timer(priv, timings->buf, false, 11538c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); 11548c2ecf20Sopenharmony_ci timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false, 11558c2ecf20Sopenharmony_ci MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); 11568c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci timer = timings->timeout; 11598c2ecf20Sopenharmony_ci writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT); 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_cienum mlxbf_i2c_timings_config { 11638c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_100KHZ, 11648c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_400KHZ, 11658c2ecf20Sopenharmony_ci MLXBF_I2C_TIMING_CONFIG_1000KHZ, 11668c2ecf20Sopenharmony_ci}; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci/* 11698c2ecf20Sopenharmony_ci * Note that the mlxbf_i2c_timings->timeout value is not related to the 11708c2ecf20Sopenharmony_ci * bus frequency, it is impacted by the time it takes the driver to 11718c2ecf20Sopenharmony_ci * complete data transmission before transaction abort. 11728c2ecf20Sopenharmony_ci */ 11738c2ecf20Sopenharmony_cistatic const struct mlxbf_i2c_timings mlxbf_i2c_timings[] = { 11748c2ecf20Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_100KHZ] = { 11758c2ecf20Sopenharmony_ci .scl_high = 4810, 11768c2ecf20Sopenharmony_ci .scl_low = 5000, 11778c2ecf20Sopenharmony_ci .hold_start = 4000, 11788c2ecf20Sopenharmony_ci .setup_start = 4800, 11798c2ecf20Sopenharmony_ci .setup_stop = 4000, 11808c2ecf20Sopenharmony_ci .setup_data = 250, 11818c2ecf20Sopenharmony_ci .sda_rise = 50, 11828c2ecf20Sopenharmony_ci .sda_fall = 50, 11838c2ecf20Sopenharmony_ci .scl_rise = 50, 11848c2ecf20Sopenharmony_ci .scl_fall = 50, 11858c2ecf20Sopenharmony_ci .hold_data = 300, 11868c2ecf20Sopenharmony_ci .buf = 20000, 11878c2ecf20Sopenharmony_ci .thigh_max = 5000, 11888c2ecf20Sopenharmony_ci .timeout = 106500 11898c2ecf20Sopenharmony_ci }, 11908c2ecf20Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_400KHZ] = { 11918c2ecf20Sopenharmony_ci .scl_high = 1011, 11928c2ecf20Sopenharmony_ci .scl_low = 1300, 11938c2ecf20Sopenharmony_ci .hold_start = 600, 11948c2ecf20Sopenharmony_ci .setup_start = 700, 11958c2ecf20Sopenharmony_ci .setup_stop = 600, 11968c2ecf20Sopenharmony_ci .setup_data = 100, 11978c2ecf20Sopenharmony_ci .sda_rise = 50, 11988c2ecf20Sopenharmony_ci .sda_fall = 50, 11998c2ecf20Sopenharmony_ci .scl_rise = 50, 12008c2ecf20Sopenharmony_ci .scl_fall = 50, 12018c2ecf20Sopenharmony_ci .hold_data = 300, 12028c2ecf20Sopenharmony_ci .buf = 20000, 12038c2ecf20Sopenharmony_ci .thigh_max = 5000, 12048c2ecf20Sopenharmony_ci .timeout = 106500 12058c2ecf20Sopenharmony_ci }, 12068c2ecf20Sopenharmony_ci [MLXBF_I2C_TIMING_CONFIG_1000KHZ] = { 12078c2ecf20Sopenharmony_ci .scl_high = 600, 12088c2ecf20Sopenharmony_ci .scl_low = 1300, 12098c2ecf20Sopenharmony_ci .hold_start = 600, 12108c2ecf20Sopenharmony_ci .setup_start = 600, 12118c2ecf20Sopenharmony_ci .setup_stop = 600, 12128c2ecf20Sopenharmony_ci .setup_data = 100, 12138c2ecf20Sopenharmony_ci .sda_rise = 50, 12148c2ecf20Sopenharmony_ci .sda_fall = 50, 12158c2ecf20Sopenharmony_ci .scl_rise = 50, 12168c2ecf20Sopenharmony_ci .scl_fall = 50, 12178c2ecf20Sopenharmony_ci .hold_data = 300, 12188c2ecf20Sopenharmony_ci .buf = 20000, 12198c2ecf20Sopenharmony_ci .thigh_max = 5000, 12208c2ecf20Sopenharmony_ci .timeout = 106500 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci}; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic int mlxbf_i2c_init_timings(struct platform_device *pdev, 12258c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci enum mlxbf_i2c_timings_config config_idx; 12288c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12298c2ecf20Sopenharmony_ci u32 config_khz; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci int ret; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "clock-frequency", &config_khz); 12348c2ecf20Sopenharmony_ci if (ret < 0) 12358c2ecf20Sopenharmony_ci config_khz = MLXBF_I2C_TIMING_100KHZ; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci switch (config_khz) { 12388c2ecf20Sopenharmony_ci default: 12398c2ecf20Sopenharmony_ci /* Default settings is 100 KHz. */ 12408c2ecf20Sopenharmony_ci pr_warn("Illegal value %d: defaulting to 100 KHz\n", 12418c2ecf20Sopenharmony_ci config_khz); 12428c2ecf20Sopenharmony_ci fallthrough; 12438c2ecf20Sopenharmony_ci case MLXBF_I2C_TIMING_100KHZ: 12448c2ecf20Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_100KHZ; 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci case MLXBF_I2C_TIMING_400KHZ: 12488c2ecf20Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_400KHZ; 12498c2ecf20Sopenharmony_ci break; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci case MLXBF_I2C_TIMING_1000KHZ: 12528c2ecf20Sopenharmony_ci config_idx = MLXBF_I2C_TIMING_CONFIG_1000KHZ; 12538c2ecf20Sopenharmony_ci break; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci mlxbf_i2c_set_timings(priv, &mlxbf_i2c_timings[config_idx]); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci return 0; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic int mlxbf_i2c_get_gpio(struct platform_device *pdev, 12628c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 12658c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12668c2ecf20Sopenharmony_ci struct resource *params; 12678c2ecf20Sopenharmony_ci resource_size_t size; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 12708c2ecf20Sopenharmony_ci if (!gpio_res) 12718c2ecf20Sopenharmony_ci return -EPERM; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* 12748c2ecf20Sopenharmony_ci * The GPIO region in TYU space is shared among I2C busses. 12758c2ecf20Sopenharmony_ci * This function MUST be serialized to avoid racing when 12768c2ecf20Sopenharmony_ci * claiming the memory region and/or setting up the GPIO. 12778c2ecf20Sopenharmony_ci */ 12788c2ecf20Sopenharmony_ci lockdep_assert_held(gpio_res->lock); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* Check whether the memory map exist. */ 12818c2ecf20Sopenharmony_ci if (gpio_res->io) 12828c2ecf20Sopenharmony_ci return 0; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci params = gpio_res->params; 12858c2ecf20Sopenharmony_ci size = resource_size(params); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (!devm_request_mem_region(dev, params->start, size, params->name)) 12888c2ecf20Sopenharmony_ci return -EFAULT; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci gpio_res->io = devm_ioremap(dev, params->start, size); 12918c2ecf20Sopenharmony_ci if (!gpio_res->io) { 12928c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 12938c2ecf20Sopenharmony_ci return -ENOMEM; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return 0; 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_cistatic int mlxbf_i2c_release_gpio(struct platform_device *pdev, 13008c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 13038c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 13048c2ecf20Sopenharmony_ci struct resource *params; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 13078c2ecf20Sopenharmony_ci if (!gpio_res) 13088c2ecf20Sopenharmony_ci return 0; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci mutex_lock(gpio_res->lock); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (gpio_res->io) { 13138c2ecf20Sopenharmony_ci /* Release the GPIO resource. */ 13148c2ecf20Sopenharmony_ci params = gpio_res->params; 13158c2ecf20Sopenharmony_ci devm_iounmap(dev, gpio_res->io); 13168c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, 13178c2ecf20Sopenharmony_ci resource_size(params)); 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci mutex_unlock(gpio_res->lock); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return 0; 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int mlxbf_i2c_get_corepll(struct platform_device *pdev, 13268c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 13298c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 13308c2ecf20Sopenharmony_ci struct resource *params; 13318c2ecf20Sopenharmony_ci resource_size_t size; 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 13348c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 13358c2ecf20Sopenharmony_ci if (!corepll_res) 13368c2ecf20Sopenharmony_ci return -EPERM; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci * The COREPLL region in TYU space is shared among I2C busses. 13408c2ecf20Sopenharmony_ci * This function MUST be serialized to avoid racing when 13418c2ecf20Sopenharmony_ci * claiming the memory region. 13428c2ecf20Sopenharmony_ci */ 13438c2ecf20Sopenharmony_ci lockdep_assert_held(corepll_res->lock); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Check whether the memory map exist. */ 13468c2ecf20Sopenharmony_ci if (corepll_res->io) 13478c2ecf20Sopenharmony_ci return 0; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci params = corepll_res->params; 13508c2ecf20Sopenharmony_ci size = resource_size(params); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (!devm_request_mem_region(dev, params->start, size, params->name)) 13538c2ecf20Sopenharmony_ci return -EFAULT; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci corepll_res->io = devm_ioremap(dev, params->start, size); 13568c2ecf20Sopenharmony_ci if (!corepll_res->io) { 13578c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 13588c2ecf20Sopenharmony_ci return -ENOMEM; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci return 0; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic int mlxbf_i2c_release_corepll(struct platform_device *pdev, 13658c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 13668c2ecf20Sopenharmony_ci{ 13678c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 13688c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 13698c2ecf20Sopenharmony_ci struct resource *params; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 13728c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci mutex_lock(corepll_res->lock); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci if (corepll_res->io) { 13778c2ecf20Sopenharmony_ci /* Release the CorePLL resource. */ 13788c2ecf20Sopenharmony_ci params = corepll_res->params; 13798c2ecf20Sopenharmony_ci devm_iounmap(dev, corepll_res->io); 13808c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, 13818c2ecf20Sopenharmony_ci resource_size(params)); 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci mutex_unlock(corepll_res->lock); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci return 0; 13878c2ecf20Sopenharmony_ci} 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int mlxbf_i2c_init_master(struct platform_device *pdev, 13908c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *gpio_res; 13938c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 13948c2ecf20Sopenharmony_ci u32 config_reg; 13958c2ecf20Sopenharmony_ci int ret; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* This configuration is only needed for BlueField 1. */ 13988c2ecf20Sopenharmony_ci if (!mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) 13998c2ecf20Sopenharmony_ci return 0; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci gpio_res = mlxbf_i2c_get_shared_resource(priv, MLXBF_I2C_GPIO_RES); 14028c2ecf20Sopenharmony_ci if (!gpio_res) 14038c2ecf20Sopenharmony_ci return -EPERM; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* 14068c2ecf20Sopenharmony_ci * The GPIO region in TYU space is shared among I2C busses. 14078c2ecf20Sopenharmony_ci * This function MUST be serialized to avoid racing when 14088c2ecf20Sopenharmony_ci * claiming the memory region and/or setting up the GPIO. 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci mutex_lock(gpio_res->lock); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci ret = mlxbf_i2c_get_gpio(pdev, priv); 14148c2ecf20Sopenharmony_ci if (ret < 0) { 14158c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get gpio resource"); 14168c2ecf20Sopenharmony_ci mutex_unlock(gpio_res->lock); 14178c2ecf20Sopenharmony_ci return ret; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * TYU - Configuration for GPIO pins. Those pins must be asserted in 14228c2ecf20Sopenharmony_ci * MLXBF_I2C_GPIO_0_FUNC_EN_0, i.e. GPIO 0 is controlled by HW, and must 14238c2ecf20Sopenharmony_ci * be reset in MLXBF_I2C_GPIO_0_FORCE_OE_EN, i.e. GPIO_OE will be driven 14248c2ecf20Sopenharmony_ci * instead of HW_OE. 14258c2ecf20Sopenharmony_ci * For now, we do not reset the GPIO state when the driver is removed. 14268c2ecf20Sopenharmony_ci * First, it is not necessary to disable the bus since we are using 14278c2ecf20Sopenharmony_ci * the same busses. Then, some busses might be shared among Linux and 14288c2ecf20Sopenharmony_ci * platform firmware; disabling the bus might compromise the system 14298c2ecf20Sopenharmony_ci * functionality. 14308c2ecf20Sopenharmony_ci */ 14318c2ecf20Sopenharmony_ci config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0); 14328c2ecf20Sopenharmony_ci config_reg = MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(priv->bus, 14338c2ecf20Sopenharmony_ci config_reg); 14348c2ecf20Sopenharmony_ci writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN); 14378c2ecf20Sopenharmony_ci config_reg = MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(priv->bus, 14388c2ecf20Sopenharmony_ci config_reg); 14398c2ecf20Sopenharmony_ci writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci mutex_unlock(gpio_res->lock); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return 0; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic u64 mlxbf_i2c_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci u64 core_frequency; 14498c2ecf20Sopenharmony_ci u8 core_od, core_r; 14508c2ecf20Sopenharmony_ci u32 corepll_val; 14518c2ecf20Sopenharmony_ci u16 core_f; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci /* Get Core PLL configuration bits. */ 14568c2ecf20Sopenharmony_ci core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_TYU_MASK, corepll_val); 14578c2ecf20Sopenharmony_ci core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK, corepll_val); 14588c2ecf20Sopenharmony_ci core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_TYU_MASK, corepll_val); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * Compute PLL output frequency as follow: 14628c2ecf20Sopenharmony_ci * 14638c2ecf20Sopenharmony_ci * CORE_F + 1 14648c2ecf20Sopenharmony_ci * PLL_OUT_FREQ = PLL_IN_FREQ * ---------------------------- 14658c2ecf20Sopenharmony_ci * (CORE_R + 1) * (CORE_OD + 1) 14668c2ecf20Sopenharmony_ci * 14678c2ecf20Sopenharmony_ci * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency 14688c2ecf20Sopenharmony_ci * and PadFrequency, respectively. 14698c2ecf20Sopenharmony_ci */ 14708c2ecf20Sopenharmony_ci core_frequency = MLXBF_I2C_PLL_IN_FREQ * (++core_f); 14718c2ecf20Sopenharmony_ci core_frequency /= (++core_r) * (++core_od); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci return core_frequency; 14748c2ecf20Sopenharmony_ci} 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci u32 corepll_reg1_val, corepll_reg2_val; 14798c2ecf20Sopenharmony_ci u64 corepll_frequency; 14808c2ecf20Sopenharmony_ci u8 core_od, core_r; 14818c2ecf20Sopenharmony_ci u32 core_f; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); 14848c2ecf20Sopenharmony_ci corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* Get Core PLL configuration bits */ 14878c2ecf20Sopenharmony_ci core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_YU_MASK, corepll_reg1_val); 14888c2ecf20Sopenharmony_ci core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_YU_MASK, corepll_reg1_val); 14898c2ecf20Sopenharmony_ci core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_YU_MASK, corepll_reg2_val); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* 14928c2ecf20Sopenharmony_ci * Compute PLL output frequency as follow: 14938c2ecf20Sopenharmony_ci * 14948c2ecf20Sopenharmony_ci * CORE_F / 16384 14958c2ecf20Sopenharmony_ci * PLL_OUT_FREQ = PLL_IN_FREQ * ---------------------------- 14968c2ecf20Sopenharmony_ci * (CORE_R + 1) * (CORE_OD + 1) 14978c2ecf20Sopenharmony_ci * 14988c2ecf20Sopenharmony_ci * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency 14998c2ecf20Sopenharmony_ci * and PadFrequency, respectively. 15008c2ecf20Sopenharmony_ci */ 15018c2ecf20Sopenharmony_ci corepll_frequency = (MLXBF_I2C_PLL_IN_FREQ * core_f) / MLNXBF_I2C_COREPLL_CONST; 15028c2ecf20Sopenharmony_ci corepll_frequency /= (++core_r) * (++core_od); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return corepll_frequency; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, 15088c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 15118c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *corepll_res; 15128c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 15138c2ecf20Sopenharmony_ci u64 *freq = &priv->frequency; 15148c2ecf20Sopenharmony_ci int ret; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci corepll_res = mlxbf_i2c_get_shared_resource(priv, 15178c2ecf20Sopenharmony_ci MLXBF_I2C_COREPLL_RES); 15188c2ecf20Sopenharmony_ci if (!corepll_res) 15198c2ecf20Sopenharmony_ci return -EPERM; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci /* 15228c2ecf20Sopenharmony_ci * First, check whether the TYU core Clock frequency is set. 15238c2ecf20Sopenharmony_ci * The TYU core frequency is the same for all I2C busses; when 15248c2ecf20Sopenharmony_ci * the first device gets probed the frequency is determined and 15258c2ecf20Sopenharmony_ci * stored into a globally visible variable. So, first of all, 15268c2ecf20Sopenharmony_ci * check whether the frequency is already set. Here, we assume 15278c2ecf20Sopenharmony_ci * that the frequency is expected to be greater than 0. 15288c2ecf20Sopenharmony_ci */ 15298c2ecf20Sopenharmony_ci mutex_lock(corepll_res->lock); 15308c2ecf20Sopenharmony_ci if (!mlxbf_i2c_corepll_frequency) { 15318c2ecf20Sopenharmony_ci if (!chip->calculate_freq) { 15328c2ecf20Sopenharmony_ci mutex_unlock(corepll_res->lock); 15338c2ecf20Sopenharmony_ci return -EPERM; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci ret = mlxbf_i2c_get_corepll(pdev, priv); 15378c2ecf20Sopenharmony_ci if (ret < 0) { 15388c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get corePLL resource"); 15398c2ecf20Sopenharmony_ci mutex_unlock(corepll_res->lock); 15408c2ecf20Sopenharmony_ci return ret; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci mlxbf_i2c_corepll_frequency = chip->calculate_freq(corepll_res); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci mutex_unlock(corepll_res->lock); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci *freq = mlxbf_i2c_corepll_frequency; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci return 0; 15508c2ecf20Sopenharmony_ci} 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_cistatic int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci u32 slave_reg, slave_reg_tmp, slave_reg_avail, slave_addr_mask; 15558c2ecf20Sopenharmony_ci u8 reg, reg_cnt, byte, addr_tmp, reg_avail, byte_avail; 15568c2ecf20Sopenharmony_ci bool avail, disabled; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci disabled = false; 15598c2ecf20Sopenharmony_ci avail = false; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci if (!priv) 15628c2ecf20Sopenharmony_ci return -EPERM; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; 15658c2ecf20Sopenharmony_ci slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* 15688c2ecf20Sopenharmony_ci * Read the slave registers. There are 4 * 32-bit slave registers. 15698c2ecf20Sopenharmony_ci * Each slave register can hold up to 4 * 8-bit slave configuration 15708c2ecf20Sopenharmony_ci * (7-bit address, 1 status bit (1 if enabled, 0 if not)). 15718c2ecf20Sopenharmony_ci */ 15728c2ecf20Sopenharmony_ci for (reg = 0; reg < reg_cnt; reg++) { 15738c2ecf20Sopenharmony_ci slave_reg = readl(priv->smbus->io + 15748c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); 15758c2ecf20Sopenharmony_ci /* 15768c2ecf20Sopenharmony_ci * Each register holds 4 slave addresses. So, we have to keep 15778c2ecf20Sopenharmony_ci * the byte order consistent with the value read in order to 15788c2ecf20Sopenharmony_ci * update the register correctly, if needed. 15798c2ecf20Sopenharmony_ci */ 15808c2ecf20Sopenharmony_ci slave_reg_tmp = slave_reg; 15818c2ecf20Sopenharmony_ci for (byte = 0; byte < 4; byte++) { 15828c2ecf20Sopenharmony_ci addr_tmp = slave_reg_tmp & GENMASK(7, 0); 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* 15858c2ecf20Sopenharmony_ci * Mark the first available slave address slot, i.e. its 15868c2ecf20Sopenharmony_ci * enabled bit should be unset. This slot might be used 15878c2ecf20Sopenharmony_ci * later on to register our slave. 15888c2ecf20Sopenharmony_ci */ 15898c2ecf20Sopenharmony_ci if (!avail && !MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) { 15908c2ecf20Sopenharmony_ci avail = true; 15918c2ecf20Sopenharmony_ci reg_avail = reg; 15928c2ecf20Sopenharmony_ci byte_avail = byte; 15938c2ecf20Sopenharmony_ci slave_reg_avail = slave_reg; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci /* 15978c2ecf20Sopenharmony_ci * Parse slave address bytes and check whether the 15988c2ecf20Sopenharmony_ci * slave address already exists and it's enabled, 15998c2ecf20Sopenharmony_ci * i.e. most significant bit is set. 16008c2ecf20Sopenharmony_ci */ 16018c2ecf20Sopenharmony_ci if ((addr_tmp & slave_addr_mask) == addr) { 16028c2ecf20Sopenharmony_ci if (MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) 16038c2ecf20Sopenharmony_ci return 0; 16048c2ecf20Sopenharmony_ci disabled = true; 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci /* Parse next byte. */ 16098c2ecf20Sopenharmony_ci slave_reg_tmp >>= 8; 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* Exit the loop if the slave address is found. */ 16138c2ecf20Sopenharmony_ci if (disabled) 16148c2ecf20Sopenharmony_ci break; 16158c2ecf20Sopenharmony_ci } 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci if (!avail && !disabled) 16188c2ecf20Sopenharmony_ci return -EINVAL; /* No room for a new slave address. */ 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (avail && !disabled) { 16218c2ecf20Sopenharmony_ci reg = reg_avail; 16228c2ecf20Sopenharmony_ci byte = byte_avail; 16238c2ecf20Sopenharmony_ci /* Set the slave address. */ 16248c2ecf20Sopenharmony_ci slave_reg_avail &= ~(slave_addr_mask << (byte * 8)); 16258c2ecf20Sopenharmony_ci slave_reg_avail |= addr << (byte * 8); 16268c2ecf20Sopenharmony_ci slave_reg = slave_reg_avail; 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Enable the slave address and update the register. */ 16308c2ecf20Sopenharmony_ci slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8); 16318c2ecf20Sopenharmony_ci writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + 16328c2ecf20Sopenharmony_ci reg * 0x4); 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci return 0; 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_cistatic int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv) 16388c2ecf20Sopenharmony_ci{ 16398c2ecf20Sopenharmony_ci u32 slave_reg, slave_reg_tmp, slave_addr_mask; 16408c2ecf20Sopenharmony_ci u8 addr, addr_tmp, reg, reg_cnt, slave_byte; 16418c2ecf20Sopenharmony_ci struct i2c_client *client = priv->slave; 16428c2ecf20Sopenharmony_ci bool exist; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci exist = false; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci addr = client->addr; 16478c2ecf20Sopenharmony_ci reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; 16488c2ecf20Sopenharmony_ci slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci /* 16518c2ecf20Sopenharmony_ci * Read the slave registers. There are 4 * 32-bit slave registers. 16528c2ecf20Sopenharmony_ci * Each slave register can hold up to 4 * 8-bit slave configuration 16538c2ecf20Sopenharmony_ci * (7-bit address, 1 status bit (1 if enabled, 0 if not)). 16548c2ecf20Sopenharmony_ci */ 16558c2ecf20Sopenharmony_ci for (reg = 0; reg < reg_cnt; reg++) { 16568c2ecf20Sopenharmony_ci slave_reg = readl(priv->smbus->io + 16578c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* Check whether the address slots are empty. */ 16608c2ecf20Sopenharmony_ci if (slave_reg == 0) 16618c2ecf20Sopenharmony_ci continue; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci /* 16648c2ecf20Sopenharmony_ci * Each register holds 4 slave addresses. So, we have to keep 16658c2ecf20Sopenharmony_ci * the byte order consistent with the value read in order to 16668c2ecf20Sopenharmony_ci * update the register correctly, if needed. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci slave_reg_tmp = slave_reg; 16698c2ecf20Sopenharmony_ci slave_byte = 0; 16708c2ecf20Sopenharmony_ci while (slave_reg_tmp != 0) { 16718c2ecf20Sopenharmony_ci addr_tmp = slave_reg_tmp & slave_addr_mask; 16728c2ecf20Sopenharmony_ci /* 16738c2ecf20Sopenharmony_ci * Parse slave address bytes and check whether the 16748c2ecf20Sopenharmony_ci * slave address already exists. 16758c2ecf20Sopenharmony_ci */ 16768c2ecf20Sopenharmony_ci if (addr_tmp == addr) { 16778c2ecf20Sopenharmony_ci exist = true; 16788c2ecf20Sopenharmony_ci break; 16798c2ecf20Sopenharmony_ci } 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* Parse next byte. */ 16828c2ecf20Sopenharmony_ci slave_reg_tmp >>= 8; 16838c2ecf20Sopenharmony_ci slave_byte += 1; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* Exit the loop if the slave address is found. */ 16878c2ecf20Sopenharmony_ci if (exist) 16888c2ecf20Sopenharmony_ci break; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (!exist) 16928c2ecf20Sopenharmony_ci return 0; /* Slave is not registered, nothing to do. */ 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci /* Cleanup the slave address slot. */ 16958c2ecf20Sopenharmony_ci slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8)); 16968c2ecf20Sopenharmony_ci writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + 16978c2ecf20Sopenharmony_ci reg * 0x4); 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic int mlxbf_i2c_init_coalesce(struct platform_device *pdev, 17038c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 17048c2ecf20Sopenharmony_ci{ 17058c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *coalesce_res; 17068c2ecf20Sopenharmony_ci struct resource *params; 17078c2ecf20Sopenharmony_ci resource_size_t size; 17088c2ecf20Sopenharmony_ci int ret = 0; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* 17118c2ecf20Sopenharmony_ci * Unlike BlueField-1 platform, the coalesce registers is a dedicated 17128c2ecf20Sopenharmony_ci * resource in the next generations of BlueField. 17138c2ecf20Sopenharmony_ci */ 17148c2ecf20Sopenharmony_ci if (mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) { 17158c2ecf20Sopenharmony_ci coalesce_res = mlxbf_i2c_get_shared_resource(priv, 17168c2ecf20Sopenharmony_ci MLXBF_I2C_COALESCE_RES); 17178c2ecf20Sopenharmony_ci if (!coalesce_res) 17188c2ecf20Sopenharmony_ci return -EPERM; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci /* 17218c2ecf20Sopenharmony_ci * The Cause Coalesce group in TYU space is shared among 17228c2ecf20Sopenharmony_ci * I2C busses. This function MUST be serialized to avoid 17238c2ecf20Sopenharmony_ci * racing when claiming the memory region. 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_ci lockdep_assert_held(mlxbf_i2c_gpio_res->lock); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci /* Check whether the memory map exist. */ 17288c2ecf20Sopenharmony_ci if (coalesce_res->io) { 17298c2ecf20Sopenharmony_ci priv->coalesce = coalesce_res; 17308c2ecf20Sopenharmony_ci return 0; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci params = coalesce_res->params; 17348c2ecf20Sopenharmony_ci size = resource_size(params); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (!request_mem_region(params->start, size, params->name)) 17378c2ecf20Sopenharmony_ci return -EFAULT; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci coalesce_res->io = ioremap(params->start, size); 17408c2ecf20Sopenharmony_ci if (!coalesce_res->io) { 17418c2ecf20Sopenharmony_ci release_mem_region(params->start, size); 17428c2ecf20Sopenharmony_ci return -ENOMEM; 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci priv->coalesce = coalesce_res; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci } else { 17488c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->coalesce, 17498c2ecf20Sopenharmony_ci MLXBF_I2C_COALESCE_RES); 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return ret; 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_cistatic int mlxbf_i2c_release_coalesce(struct platform_device *pdev, 17568c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 17578c2ecf20Sopenharmony_ci{ 17588c2ecf20Sopenharmony_ci struct mlxbf_i2c_resource *coalesce_res; 17598c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 17608c2ecf20Sopenharmony_ci struct resource *params; 17618c2ecf20Sopenharmony_ci resource_size_t size; 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci coalesce_res = priv->coalesce; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (coalesce_res->io) { 17668c2ecf20Sopenharmony_ci params = coalesce_res->params; 17678c2ecf20Sopenharmony_ci size = resource_size(params); 17688c2ecf20Sopenharmony_ci if (mlxbf_i2c_has_chip_type(priv, MLXBF_I2C_CHIP_TYPE_1)) { 17698c2ecf20Sopenharmony_ci mutex_lock(coalesce_res->lock); 17708c2ecf20Sopenharmony_ci iounmap(coalesce_res->io); 17718c2ecf20Sopenharmony_ci release_mem_region(params->start, size); 17728c2ecf20Sopenharmony_ci mutex_unlock(coalesce_res->lock); 17738c2ecf20Sopenharmony_ci } else { 17748c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, size); 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_cistatic int mlxbf_i2c_init_slave(struct platform_device *pdev, 17828c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv) 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 17858c2ecf20Sopenharmony_ci u32 int_reg; 17868c2ecf20Sopenharmony_ci int ret; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Reset FSM. */ 17898c2ecf20Sopenharmony_ci writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM); 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* 17928c2ecf20Sopenharmony_ci * Enable slave cause interrupt bits. Drive 17938c2ecf20Sopenharmony_ci * MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE and 17948c2ecf20Sopenharmony_ci * MLXBF_I2C_CAUSE_WRITE_SUCCESS, these are enabled when an external 17958c2ecf20Sopenharmony_ci * masters issue a Read and Write, respectively. But, clear all 17968c2ecf20Sopenharmony_ci * interrupts first. 17978c2ecf20Sopenharmony_ci */ 17988c2ecf20Sopenharmony_ci writel(~0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 17998c2ecf20Sopenharmony_ci int_reg = MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE; 18008c2ecf20Sopenharmony_ci int_reg |= MLXBF_I2C_CAUSE_WRITE_SUCCESS; 18018c2ecf20Sopenharmony_ci writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0); 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci /* Finally, set the 'ready' bit to start handling transactions. */ 18048c2ecf20Sopenharmony_ci writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci /* Initialize the cause coalesce resource. */ 18078c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_coalesce(pdev, priv); 18088c2ecf20Sopenharmony_ci if (ret < 0) { 18098c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize cause coalesce\n"); 18108c2ecf20Sopenharmony_ci return ret; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci return 0; 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_cistatic bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read, 18178c2ecf20Sopenharmony_ci bool *write) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci const struct mlxbf_i2c_chip_info *chip = priv->chip; 18208c2ecf20Sopenharmony_ci u32 coalesce0_reg, cause_reg; 18218c2ecf20Sopenharmony_ci u8 slave_shift, is_set; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci *write = false; 18248c2ecf20Sopenharmony_ci *read = false; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci slave_shift = chip->type != MLXBF_I2C_CHIP_TYPE_1 ? 18278c2ecf20Sopenharmony_ci MLXBF_I2C_CAUSE_YU_SLAVE_BIT : 18288c2ecf20Sopenharmony_ci priv->bus + MLXBF_I2C_CAUSE_TYU_SLAVE_BIT; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci coalesce0_reg = readl(priv->coalesce->io + MLXBF_I2C_CAUSE_COALESCE_0); 18318c2ecf20Sopenharmony_ci is_set = coalesce0_reg & (1 << slave_shift); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci if (!is_set) 18348c2ecf20Sopenharmony_ci return false; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* Check the source of the interrupt, i.e. whether a Read or Write. */ 18378c2ecf20Sopenharmony_ci cause_reg = readl(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER); 18388c2ecf20Sopenharmony_ci if (cause_reg & MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE) 18398c2ecf20Sopenharmony_ci *read = true; 18408c2ecf20Sopenharmony_ci else if (cause_reg & MLXBF_I2C_CAUSE_WRITE_SUCCESS) 18418c2ecf20Sopenharmony_ci *write = true; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci /* Clear cause bits. */ 18448c2ecf20Sopenharmony_ci writel(~0x0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci return true; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic bool mlxbf_smbus_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, 18508c2ecf20Sopenharmony_ci u32 timeout) 18518c2ecf20Sopenharmony_ci{ 18528c2ecf20Sopenharmony_ci u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL; 18538c2ecf20Sopenharmony_ci u32 addr = MLXBF_I2C_CAUSE_ARBITER; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci if (mlxbf_smbus_poll(priv->slv_cause->io, addr, mask, false, timeout)) 18568c2ecf20Sopenharmony_ci return true; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci return false; 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci/* Send byte to 'external' smbus master. */ 18628c2ecf20Sopenharmony_cistatic int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; 18658c2ecf20Sopenharmony_ci u8 write_size, pec_en, addr, byte, value, byte_cnt, desc_size; 18668c2ecf20Sopenharmony_ci struct i2c_client *slave = priv->slave; 18678c2ecf20Sopenharmony_ci u32 control32, data32; 18688c2ecf20Sopenharmony_ci int ret; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (!slave) 18718c2ecf20Sopenharmony_ci return -EINVAL; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci addr = 0; 18748c2ecf20Sopenharmony_ci byte = 0; 18758c2ecf20Sopenharmony_ci desc_size = MLXBF_I2C_SLAVE_DATA_DESC_SIZE; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* 18788c2ecf20Sopenharmony_ci * Read bytes received from the external master. These bytes should 18798c2ecf20Sopenharmony_ci * be located in the first data descriptor register of the slave GW. 18808c2ecf20Sopenharmony_ci * These bytes are the slave address byte and the internal register 18818c2ecf20Sopenharmony_ci * address, if supplied. 18828c2ecf20Sopenharmony_ci */ 18838c2ecf20Sopenharmony_ci if (recv_bytes > 0) { 18848c2ecf20Sopenharmony_ci data32 = ioread32be(priv->smbus->io + 18858c2ecf20Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Parse the received bytes. */ 18888c2ecf20Sopenharmony_ci switch (recv_bytes) { 18898c2ecf20Sopenharmony_ci case 2: 18908c2ecf20Sopenharmony_ci byte = (data32 >> 8) & GENMASK(7, 0); 18918c2ecf20Sopenharmony_ci fallthrough; 18928c2ecf20Sopenharmony_ci case 1: 18938c2ecf20Sopenharmony_ci addr = (data32 & GENMASK(7, 0)) >> 1; 18948c2ecf20Sopenharmony_ci } 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci /* Check whether it's our slave address. */ 18978c2ecf20Sopenharmony_ci if (slave->addr != addr) 18988c2ecf20Sopenharmony_ci return -EINVAL; 18998c2ecf20Sopenharmony_ci } 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* 19028c2ecf20Sopenharmony_ci * I2C read transactions may start by a WRITE followed by a READ. 19038c2ecf20Sopenharmony_ci * Indeed, most slave devices would expect the internal address 19048c2ecf20Sopenharmony_ci * following the slave address byte. So, write that byte first, 19058c2ecf20Sopenharmony_ci * and then, send the requested data bytes to the master. 19068c2ecf20Sopenharmony_ci */ 19078c2ecf20Sopenharmony_ci if (recv_bytes > 1) { 19088c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); 19098c2ecf20Sopenharmony_ci value = byte; 19108c2ecf20Sopenharmony_ci ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, 19118c2ecf20Sopenharmony_ci &value); 19128c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (ret < 0) 19158c2ecf20Sopenharmony_ci return ret; 19168c2ecf20Sopenharmony_ci } 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci /* 19198c2ecf20Sopenharmony_ci * Now, send data to the master; currently, the driver supports 19208c2ecf20Sopenharmony_ci * READ_BYTE, READ_WORD and BLOCK READ protocols. Note that the 19218c2ecf20Sopenharmony_ci * hardware can send up to 128 bytes per transfer. That is the 19228c2ecf20Sopenharmony_ci * size of its data registers. 19238c2ecf20Sopenharmony_ci */ 19248c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci for (byte_cnt = 0; byte_cnt < desc_size; byte_cnt++) { 19278c2ecf20Sopenharmony_ci data_desc[byte_cnt] = value; 19288c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value); 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* Send a stop condition to the backend. */ 19328c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci /* Handle the actual transfer. */ 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* Set the number of bytes to write to master. */ 19378c2ecf20Sopenharmony_ci write_size = (byte_cnt - 1) & 0x7f; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci /* Write data to Slave GW data descriptor. */ 19408c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_write_data(priv, data_desc, byte_cnt, 19418c2ecf20Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci pec_en = 0; /* Disable PEC since it is not supported. */ 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* Prepare control word. */ 19468c2ecf20Sopenharmony_ci control32 = MLXBF_I2C_SLAVE_ENABLE; 19478c2ecf20Sopenharmony_ci control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT); 19488c2ecf20Sopenharmony_ci control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci /* 19538c2ecf20Sopenharmony_ci * Wait until the transfer is completed; the driver will wait 19548c2ecf20Sopenharmony_ci * until the GW is idle, a cause will rise on fall of GW busy. 19558c2ecf20Sopenharmony_ci */ 19568c2ecf20Sopenharmony_ci mlxbf_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* Release the Slave GW. */ 19598c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 19608c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); 19618c2ecf20Sopenharmony_ci writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci return 0; 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci/* Receive bytes from 'external' smbus master. */ 19678c2ecf20Sopenharmony_cistatic int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) 19688c2ecf20Sopenharmony_ci{ 19698c2ecf20Sopenharmony_ci u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; 19708c2ecf20Sopenharmony_ci struct i2c_client *slave = priv->slave; 19718c2ecf20Sopenharmony_ci u8 value, byte, addr; 19728c2ecf20Sopenharmony_ci int ret = 0; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (!slave) 19758c2ecf20Sopenharmony_ci return -EINVAL; 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci /* Read data from Slave GW data descriptor. */ 19788c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes, 19798c2ecf20Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_ADDR); 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci /* Check whether its our slave address. */ 19828c2ecf20Sopenharmony_ci addr = data_desc[0] >> 1; 19838c2ecf20Sopenharmony_ci if (slave->addr != addr) 19848c2ecf20Sopenharmony_ci return -EINVAL; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci /* 19878c2ecf20Sopenharmony_ci * Notify the slave backend; another I2C master wants to write data 19888c2ecf20Sopenharmony_ci * to us. This event is sent once the slave address and the write bit 19898c2ecf20Sopenharmony_ci * is detected. 19908c2ecf20Sopenharmony_ci */ 19918c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Send the received data to the slave backend. */ 19948c2ecf20Sopenharmony_ci for (byte = 1; byte < recv_bytes; byte++) { 19958c2ecf20Sopenharmony_ci value = data_desc[byte]; 19968c2ecf20Sopenharmony_ci ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, 19978c2ecf20Sopenharmony_ci &value); 19988c2ecf20Sopenharmony_ci if (ret < 0) 19998c2ecf20Sopenharmony_ci break; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* Send a stop condition to the backend. */ 20038c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_STOP, &value); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci /* Release the Slave GW. */ 20068c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 20078c2ecf20Sopenharmony_ci writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); 20088c2ecf20Sopenharmony_ci writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci return ret; 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_cistatic irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv = ptr; 20168c2ecf20Sopenharmony_ci bool read, write, irq_is_set; 20178c2ecf20Sopenharmony_ci u32 rw_bytes_reg; 20188c2ecf20Sopenharmony_ci u8 recv_bytes; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* 20218c2ecf20Sopenharmony_ci * Read TYU interrupt register and determine the source of the 20228c2ecf20Sopenharmony_ci * interrupt. Based on the source of the interrupt one of the 20238c2ecf20Sopenharmony_ci * following actions are performed: 20248c2ecf20Sopenharmony_ci * - Receive data and send response to master. 20258c2ecf20Sopenharmony_ci * - Send data and release slave GW. 20268c2ecf20Sopenharmony_ci * 20278c2ecf20Sopenharmony_ci * Handle read/write transaction only. CRmaster and Iarp requests 20288c2ecf20Sopenharmony_ci * are ignored for now. 20298c2ecf20Sopenharmony_ci */ 20308c2ecf20Sopenharmony_ci irq_is_set = mlxbf_i2c_has_coalesce(priv, &read, &write); 20318c2ecf20Sopenharmony_ci if (!irq_is_set || (!read && !write)) { 20328c2ecf20Sopenharmony_ci /* Nothing to do here, interrupt was not from this device. */ 20338c2ecf20Sopenharmony_ci return IRQ_NONE; 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci /* 20378c2ecf20Sopenharmony_ci * The MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES includes the number of 20388c2ecf20Sopenharmony_ci * bytes from/to master. These are defined by 8-bits each. If the lower 20398c2ecf20Sopenharmony_ci * 8 bits are set, then the master expect to read N bytes from the 20408c2ecf20Sopenharmony_ci * slave, if the higher 8 bits are sent then the slave expect N bytes 20418c2ecf20Sopenharmony_ci * from the master. 20428c2ecf20Sopenharmony_ci */ 20438c2ecf20Sopenharmony_ci rw_bytes_reg = readl(priv->smbus->io + 20448c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); 20458c2ecf20Sopenharmony_ci recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci /* 20488c2ecf20Sopenharmony_ci * For now, the slave supports 128 bytes transfer. Discard remaining 20498c2ecf20Sopenharmony_ci * data bytes if the master wrote more than 20508c2ecf20Sopenharmony_ci * MLXBF_I2C_SLAVE_DATA_DESC_SIZE, i.e, the actual size of the slave 20518c2ecf20Sopenharmony_ci * data descriptor. 20528c2ecf20Sopenharmony_ci * 20538c2ecf20Sopenharmony_ci * Note that we will never expect to transfer more than 128 bytes; as 20548c2ecf20Sopenharmony_ci * specified in the SMBus standard, block transactions cannot exceed 20558c2ecf20Sopenharmony_ci * 32 bytes. 20568c2ecf20Sopenharmony_ci */ 20578c2ecf20Sopenharmony_ci recv_bytes = recv_bytes > MLXBF_I2C_SLAVE_DATA_DESC_SIZE ? 20588c2ecf20Sopenharmony_ci MLXBF_I2C_SLAVE_DATA_DESC_SIZE : recv_bytes; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci if (read) 20618c2ecf20Sopenharmony_ci mlxbf_smbus_irq_send(priv, recv_bytes); 20628c2ecf20Sopenharmony_ci else 20638c2ecf20Sopenharmony_ci mlxbf_smbus_irq_recv(priv, recv_bytes); 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci return IRQ_HANDLED; 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci/* Return negative errno on error. */ 20698c2ecf20Sopenharmony_cistatic s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, 20708c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 20718c2ecf20Sopenharmony_ci u8 command, int size, 20728c2ecf20Sopenharmony_ci union i2c_smbus_data *data) 20738c2ecf20Sopenharmony_ci{ 20748c2ecf20Sopenharmony_ci struct mlxbf_i2c_smbus_request request = { 0 }; 20758c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv; 20768c2ecf20Sopenharmony_ci bool read, pec; 20778c2ecf20Sopenharmony_ci u8 byte_cnt; 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci request.slave = addr; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci read = (read_write == I2C_SMBUS_READ); 20828c2ecf20Sopenharmony_ci pec = flags & I2C_FUNC_SMBUS_PEC; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci switch (size) { 20858c2ecf20Sopenharmony_ci case I2C_SMBUS_QUICK: 20868c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_quick_command(&request, read); 20878c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "smbus quick, slave 0x%02x\n", addr); 20888c2ecf20Sopenharmony_ci break; 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 20918c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_byte_func(&request, 20928c2ecf20Sopenharmony_ci read ? &data->byte : &command, read, 20938c2ecf20Sopenharmony_ci pec); 20948c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s byte, slave 0x%02x.\n", 20958c2ecf20Sopenharmony_ci read ? "read" : "write", addr); 20968c2ecf20Sopenharmony_ci break; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 20998c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_data_byte_func(&request, &command, &data->byte, 21008c2ecf20Sopenharmony_ci read, pec); 21018c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s byte data at 0x%02x, slave 0x%02x.\n", 21028c2ecf20Sopenharmony_ci read ? "read" : "write", command, addr); 21038c2ecf20Sopenharmony_ci break; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 21068c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_data_word_func(&request, &command, 21078c2ecf20Sopenharmony_ci (u8 *)&data->word, read, pec); 21088c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s word data at 0x%02x, slave 0x%02x.\n", 21098c2ecf20Sopenharmony_ci read ? "read" : "write", command, addr); 21108c2ecf20Sopenharmony_ci break; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 21138c2ecf20Sopenharmony_ci byte_cnt = data->block[0]; 21148c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_i2c_block_func(&request, &command, data->block, 21158c2ecf20Sopenharmony_ci &byte_cnt, read, pec); 21168c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "i2c %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", 21178c2ecf20Sopenharmony_ci read ? "read" : "write", byte_cnt, command, addr); 21188c2ecf20Sopenharmony_ci break; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 21218c2ecf20Sopenharmony_ci byte_cnt = read ? I2C_SMBUS_BLOCK_MAX : data->block[0]; 21228c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_block_func(&request, &command, data->block, 21238c2ecf20Sopenharmony_ci &byte_cnt, read, pec); 21248c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "smbus %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", 21258c2ecf20Sopenharmony_ci read ? "read" : "write", byte_cnt, command, addr); 21268c2ecf20Sopenharmony_ci break; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci case I2C_FUNC_SMBUS_PROC_CALL: 21298c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_process_call_func(&request, &command, 21308c2ecf20Sopenharmony_ci (u8 *)&data->word, pec); 21318c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "process call, wr/rd at 0x%02x, slave 0x%02x.\n", 21328c2ecf20Sopenharmony_ci command, addr); 21338c2ecf20Sopenharmony_ci break; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci case I2C_FUNC_SMBUS_BLOCK_PROC_CALL: 21368c2ecf20Sopenharmony_ci byte_cnt = data->block[0]; 21378c2ecf20Sopenharmony_ci mlxbf_i2c_smbus_blk_process_call_func(&request, &command, 21388c2ecf20Sopenharmony_ci data->block, &byte_cnt, 21398c2ecf20Sopenharmony_ci pec); 21408c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "block process call, wr/rd %d bytes, slave 0x%02x.\n", 21418c2ecf20Sopenharmony_ci byte_cnt, addr); 21428c2ecf20Sopenharmony_ci break; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci default: 21458c2ecf20Sopenharmony_ci dev_dbg(&adap->dev, "Unsupported I2C/SMBus command %d\n", 21468c2ecf20Sopenharmony_ci size); 21478c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci priv = i2c_get_adapdata(adap); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci return mlxbf_i2c_smbus_start_transaction(priv, &request); 21538c2ecf20Sopenharmony_ci} 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic int mlxbf_i2c_reg_slave(struct i2c_client *slave) 21568c2ecf20Sopenharmony_ci{ 21578c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); 21588c2ecf20Sopenharmony_ci int ret; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci if (priv->slave) 21618c2ecf20Sopenharmony_ci return -EBUSY; 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci /* 21648c2ecf20Sopenharmony_ci * Do not support ten bit chip address and do not use Packet Error 21658c2ecf20Sopenharmony_ci * Checking (PEC). 21668c2ecf20Sopenharmony_ci */ 21678c2ecf20Sopenharmony_ci if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) 21688c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci ret = mlxbf_slave_enable(priv, slave->addr); 21718c2ecf20Sopenharmony_ci if (ret < 0) 21728c2ecf20Sopenharmony_ci return ret; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci priv->slave = slave; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci return 0; 21778c2ecf20Sopenharmony_ci} 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_cistatic int mlxbf_i2c_unreg_slave(struct i2c_client *slave) 21808c2ecf20Sopenharmony_ci{ 21818c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); 21828c2ecf20Sopenharmony_ci int ret; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci WARN_ON(!priv->slave); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci /* Unregister slave, i.e. disable the slave address in hardware. */ 21878c2ecf20Sopenharmony_ci ret = mlxbf_slave_disable(priv); 21888c2ecf20Sopenharmony_ci if (ret < 0) 21898c2ecf20Sopenharmony_ci return ret; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci priv->slave = NULL; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci return 0; 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_cistatic u32 mlxbf_i2c_functionality(struct i2c_adapter *adap) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci return MLXBF_I2C_FUNC_ALL; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = { 22028c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_1] = { 22038c2ecf20Sopenharmony_ci .type = MLXBF_I2C_CHIP_TYPE_1, 22048c2ecf20Sopenharmony_ci .shared_res = { 22058c2ecf20Sopenharmony_ci [0] = &mlxbf_i2c_coalesce_res[MLXBF_I2C_CHIP_TYPE_1], 22068c2ecf20Sopenharmony_ci [1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1], 22078c2ecf20Sopenharmony_ci [2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1] 22088c2ecf20Sopenharmony_ci }, 22098c2ecf20Sopenharmony_ci .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu 22108c2ecf20Sopenharmony_ci }, 22118c2ecf20Sopenharmony_ci [MLXBF_I2C_CHIP_TYPE_2] = { 22128c2ecf20Sopenharmony_ci .type = MLXBF_I2C_CHIP_TYPE_2, 22138c2ecf20Sopenharmony_ci .shared_res = { 22148c2ecf20Sopenharmony_ci [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2] 22158c2ecf20Sopenharmony_ci }, 22168c2ecf20Sopenharmony_ci .calculate_freq = mlxbf_i2c_calculate_freq_from_yu 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci}; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_cistatic const struct i2c_algorithm mlxbf_i2c_algo = { 22218c2ecf20Sopenharmony_ci .smbus_xfer = mlxbf_i2c_smbus_xfer, 22228c2ecf20Sopenharmony_ci .functionality = mlxbf_i2c_functionality, 22238c2ecf20Sopenharmony_ci .reg_slave = mlxbf_i2c_reg_slave, 22248c2ecf20Sopenharmony_ci .unreg_slave = mlxbf_i2c_unreg_slave, 22258c2ecf20Sopenharmony_ci}; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_cistatic struct i2c_adapter_quirks mlxbf_i2c_quirks = { 22288c2ecf20Sopenharmony_ci .max_read_len = MLXBF_I2C_MASTER_DATA_R_LENGTH, 22298c2ecf20Sopenharmony_ci .max_write_len = MLXBF_I2C_MASTER_DATA_W_LENGTH, 22308c2ecf20Sopenharmony_ci}; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_cistatic const struct of_device_id mlxbf_i2c_dt_ids[] = { 22338c2ecf20Sopenharmony_ci { 22348c2ecf20Sopenharmony_ci .compatible = "mellanox,i2c-mlxbf1", 22358c2ecf20Sopenharmony_ci .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] 22368c2ecf20Sopenharmony_ci }, 22378c2ecf20Sopenharmony_ci { 22388c2ecf20Sopenharmony_ci .compatible = "mellanox,i2c-mlxbf2", 22398c2ecf20Sopenharmony_ci .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] 22408c2ecf20Sopenharmony_ci }, 22418c2ecf20Sopenharmony_ci {}, 22428c2ecf20Sopenharmony_ci}; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 22478c2ecf20Sopenharmony_cistatic const struct acpi_device_id mlxbf_i2c_acpi_ids[] = { 22488c2ecf20Sopenharmony_ci { "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] }, 22498c2ecf20Sopenharmony_ci { "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] }, 22508c2ecf20Sopenharmony_ci {}, 22518c2ecf20Sopenharmony_ci}; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, mlxbf_i2c_acpi_ids); 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_cistatic int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) 22568c2ecf20Sopenharmony_ci{ 22578c2ecf20Sopenharmony_ci const struct acpi_device_id *aid; 22588c2ecf20Sopenharmony_ci struct acpi_device *adev; 22598c2ecf20Sopenharmony_ci unsigned long bus_id = 0; 22608c2ecf20Sopenharmony_ci const char *uid; 22618c2ecf20Sopenharmony_ci int ret; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci if (acpi_disabled) 22648c2ecf20Sopenharmony_ci return -ENOENT; 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci adev = ACPI_COMPANION(dev); 22678c2ecf20Sopenharmony_ci if (!adev) 22688c2ecf20Sopenharmony_ci return -ENXIO; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci aid = acpi_match_device(mlxbf_i2c_acpi_ids, dev); 22718c2ecf20Sopenharmony_ci if (!aid) 22728c2ecf20Sopenharmony_ci return -ENODEV; 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci priv->chip = (struct mlxbf_i2c_chip_info *)aid->driver_data; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci uid = acpi_device_uid(adev); 22778c2ecf20Sopenharmony_ci if (!uid || !(*uid)) { 22788c2ecf20Sopenharmony_ci dev_err(dev, "Cannot retrieve UID\n"); 22798c2ecf20Sopenharmony_ci return -ENODEV; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci ret = kstrtoul(uid, 0, &bus_id); 22838c2ecf20Sopenharmony_ci if (!ret) 22848c2ecf20Sopenharmony_ci priv->bus = bus_id; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci return ret; 22878c2ecf20Sopenharmony_ci} 22888c2ecf20Sopenharmony_ci#else 22898c2ecf20Sopenharmony_cistatic int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci return -ENOENT; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_cistatic int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv) 22968c2ecf20Sopenharmony_ci{ 22978c2ecf20Sopenharmony_ci const struct of_device_id *oid; 22988c2ecf20Sopenharmony_ci int bus_id = -1; 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && dev->of_node) { 23018c2ecf20Sopenharmony_ci oid = of_match_node(mlxbf_i2c_dt_ids, dev->of_node); 23028c2ecf20Sopenharmony_ci if (!oid) 23038c2ecf20Sopenharmony_ci return -ENODEV; 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci priv->chip = oid->data; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci bus_id = of_alias_get_id(dev->of_node, "i2c"); 23088c2ecf20Sopenharmony_ci if (bus_id >= 0) 23098c2ecf20Sopenharmony_ci priv->bus = bus_id; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (bus_id < 0) { 23138c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get bus id"); 23148c2ecf20Sopenharmony_ci return bus_id; 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci return 0; 23188c2ecf20Sopenharmony_ci} 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_cistatic int mlxbf_i2c_probe(struct platform_device *pdev) 23218c2ecf20Sopenharmony_ci{ 23228c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 23238c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv; 23248c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 23258c2ecf20Sopenharmony_ci int irq, ret; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_priv), GFP_KERNEL); 23288c2ecf20Sopenharmony_ci if (!priv) 23298c2ecf20Sopenharmony_ci return -ENOMEM; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci ret = mlxbf_i2c_acpi_probe(dev, priv); 23328c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ENOENT && ret != -ENXIO) 23338c2ecf20Sopenharmony_ci ret = mlxbf_i2c_of_probe(dev, priv); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (ret < 0) 23368c2ecf20Sopenharmony_ci return ret; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, 23398c2ecf20Sopenharmony_ci MLXBF_I2C_SMBUS_RES); 23408c2ecf20Sopenharmony_ci if (ret < 0) { 23418c2ecf20Sopenharmony_ci dev_err(dev, "Cannot fetch smbus resource info"); 23428c2ecf20Sopenharmony_ci return ret; 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause, 23468c2ecf20Sopenharmony_ci MLXBF_I2C_MST_CAUSE_RES); 23478c2ecf20Sopenharmony_ci if (ret < 0) { 23488c2ecf20Sopenharmony_ci dev_err(dev, "Cannot fetch cause master resource info"); 23498c2ecf20Sopenharmony_ci return ret; 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_resource(pdev, &priv->slv_cause, 23538c2ecf20Sopenharmony_ci MLXBF_I2C_SLV_CAUSE_RES); 23548c2ecf20Sopenharmony_ci if (ret < 0) { 23558c2ecf20Sopenharmony_ci dev_err(dev, "Cannot fetch cause slave resource info"); 23568c2ecf20Sopenharmony_ci return ret; 23578c2ecf20Sopenharmony_ci } 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci adap = &priv->adap; 23608c2ecf20Sopenharmony_ci adap->owner = THIS_MODULE; 23618c2ecf20Sopenharmony_ci adap->class = I2C_CLASS_HWMON; 23628c2ecf20Sopenharmony_ci adap->algo = &mlxbf_i2c_algo; 23638c2ecf20Sopenharmony_ci adap->quirks = &mlxbf_i2c_quirks; 23648c2ecf20Sopenharmony_ci adap->dev.parent = dev; 23658c2ecf20Sopenharmony_ci adap->dev.of_node = dev->of_node; 23668c2ecf20Sopenharmony_ci adap->nr = priv->bus; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci snprintf(adap->name, sizeof(adap->name), "i2c%d", adap->nr); 23698c2ecf20Sopenharmony_ci i2c_set_adapdata(adap, priv); 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci /* Read Core PLL frequency. */ 23728c2ecf20Sopenharmony_ci ret = mlxbf_i2c_calculate_corepll_freq(pdev, priv); 23738c2ecf20Sopenharmony_ci if (ret < 0) { 23748c2ecf20Sopenharmony_ci dev_err(dev, "cannot get core clock frequency\n"); 23758c2ecf20Sopenharmony_ci /* Set to default value. */ 23768c2ecf20Sopenharmony_ci priv->frequency = MLXBF_I2C_COREPLL_FREQ; 23778c2ecf20Sopenharmony_ci } 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci /* 23808c2ecf20Sopenharmony_ci * Initialize master. 23818c2ecf20Sopenharmony_ci * Note that a physical bus might be shared among Linux and firmware 23828c2ecf20Sopenharmony_ci * (e.g., ATF). Thus, the bus should be initialized and ready and 23838c2ecf20Sopenharmony_ci * bus initialization would be unnecessary. This requires additional 23848c2ecf20Sopenharmony_ci * knowledge about physical busses. But, since an extra initialization 23858c2ecf20Sopenharmony_ci * does not really hurt, then keep the code as is. 23868c2ecf20Sopenharmony_ci */ 23878c2ecf20Sopenharmony_ci ret = mlxbf_i2c_init_master(pdev, priv); 23888c2ecf20Sopenharmony_ci if (ret < 0) { 23898c2ecf20Sopenharmony_ci dev_err(dev, "failed to initialize smbus master %d", 23908c2ecf20Sopenharmony_ci priv->bus); 23918c2ecf20Sopenharmony_ci return ret; 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci mlxbf_i2c_init_timings(pdev, priv); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci mlxbf_i2c_init_slave(pdev, priv); 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 23998c2ecf20Sopenharmony_ci if (irq < 0) 24008c2ecf20Sopenharmony_ci return irq; 24018c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, mlxbf_smbus_irq, 24028c2ecf20Sopenharmony_ci IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED, 24038c2ecf20Sopenharmony_ci dev_name(dev), priv); 24048c2ecf20Sopenharmony_ci if (ret < 0) { 24058c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get irq %d\n", irq); 24068c2ecf20Sopenharmony_ci return ret; 24078c2ecf20Sopenharmony_ci } 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci priv->irq = irq; 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci ret = i2c_add_numbered_adapter(adap); 24148c2ecf20Sopenharmony_ci if (ret < 0) 24158c2ecf20Sopenharmony_ci return ret; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci mutex_lock(&mlxbf_i2c_bus_lock); 24188c2ecf20Sopenharmony_ci mlxbf_i2c_bus_count++; 24198c2ecf20Sopenharmony_ci mutex_unlock(&mlxbf_i2c_bus_lock); 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci return 0; 24228c2ecf20Sopenharmony_ci} 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_cistatic int mlxbf_i2c_remove(struct platform_device *pdev) 24258c2ecf20Sopenharmony_ci{ 24268c2ecf20Sopenharmony_ci struct mlxbf_i2c_priv *priv = platform_get_drvdata(pdev); 24278c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 24288c2ecf20Sopenharmony_ci struct resource *params; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci params = priv->smbus->params; 24318c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci params = priv->mst_cause->params; 24348c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci params = priv->slv_cause->params; 24378c2ecf20Sopenharmony_ci devm_release_mem_region(dev, params->start, resource_size(params)); 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci /* 24408c2ecf20Sopenharmony_ci * Release shared resources. This should be done when releasing 24418c2ecf20Sopenharmony_ci * the I2C controller. 24428c2ecf20Sopenharmony_ci */ 24438c2ecf20Sopenharmony_ci mutex_lock(&mlxbf_i2c_bus_lock); 24448c2ecf20Sopenharmony_ci if (--mlxbf_i2c_bus_count == 0) { 24458c2ecf20Sopenharmony_ci mlxbf_i2c_release_coalesce(pdev, priv); 24468c2ecf20Sopenharmony_ci mlxbf_i2c_release_corepll(pdev, priv); 24478c2ecf20Sopenharmony_ci mlxbf_i2c_release_gpio(pdev, priv); 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci mutex_unlock(&mlxbf_i2c_bus_lock); 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci devm_free_irq(dev, priv->irq, priv); 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci i2c_del_adapter(&priv->adap); 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ci return 0; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cistatic struct platform_driver mlxbf_i2c_driver = { 24598c2ecf20Sopenharmony_ci .probe = mlxbf_i2c_probe, 24608c2ecf20Sopenharmony_ci .remove = mlxbf_i2c_remove, 24618c2ecf20Sopenharmony_ci .driver = { 24628c2ecf20Sopenharmony_ci .name = "i2c-mlxbf", 24638c2ecf20Sopenharmony_ci .of_match_table = mlxbf_i2c_dt_ids, 24648c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 24658c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), 24668c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */ 24678c2ecf20Sopenharmony_ci }, 24688c2ecf20Sopenharmony_ci}; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_cistatic int __init mlxbf_i2c_init(void) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci mutex_init(&mlxbf_i2c_coalesce_lock); 24738c2ecf20Sopenharmony_ci mutex_init(&mlxbf_i2c_corepll_lock); 24748c2ecf20Sopenharmony_ci mutex_init(&mlxbf_i2c_gpio_lock); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci mutex_init(&mlxbf_i2c_bus_lock); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci return platform_driver_register(&mlxbf_i2c_driver); 24798c2ecf20Sopenharmony_ci} 24808c2ecf20Sopenharmony_cimodule_init(mlxbf_i2c_init); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_cistatic void __exit mlxbf_i2c_exit(void) 24838c2ecf20Sopenharmony_ci{ 24848c2ecf20Sopenharmony_ci platform_driver_unregister(&mlxbf_i2c_driver); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci mutex_destroy(&mlxbf_i2c_bus_lock); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci mutex_destroy(&mlxbf_i2c_gpio_lock); 24898c2ecf20Sopenharmony_ci mutex_destroy(&mlxbf_i2c_corepll_lock); 24908c2ecf20Sopenharmony_ci mutex_destroy(&mlxbf_i2c_coalesce_lock); 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_cimodule_exit(mlxbf_i2c_exit); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Mellanox BlueField I2C bus driver"); 24958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>"); 24968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2497