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