forked from Minki/linux
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c fixes from Wolfram Sang: "Driver bugfixes for I2C. Most of them are for the new mlxbf driver which got more exposure after rc1. The sh_mobile patch should already have reached you during the merge window, but I accidently dropped it. However, since it fixes a problem with rebooting, it is still fine for rc3" * 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: i2c: designware: slave should do WRITE_REQUESTED before WRITE_RECEIVED i2c: designware: call i2c_dw_read_clear_intrbits_slave() once i2c: mlxbf: I2C_MLXBF should depend on MELLANOX_PLATFORM i2c: mlxbf: Update author and maintainer email info i2c: mlxbf: Update reference clock frequency i2c: mlxbf: Remove unecessary wrapper functions i2c: mlxbf: Fix resrticted cast warning of sparse i2c: mlxbf: Add CONFIG_ACPI to guard ACPI function call i2c: sh_mobile: implement atomic transfers i2c: mediatek: move dma reset before i2c reset
This commit is contained in:
commit
af6e7de0c7
@ -11163,7 +11163,7 @@ F: Documentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt
|
||||
F: drivers/input/touchscreen/melfas_mip4.c
|
||||
|
||||
MELLANOX BLUEFIELD I2C DRIVER
|
||||
M: Khalil Blaiech <kblaiech@mellanox.com>
|
||||
M: Khalil Blaiech <kblaiech@nvidia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/i2c/busses/i2c-mlxbf.c
|
||||
|
@ -733,7 +733,7 @@ config I2C_LPC2K
|
||||
|
||||
config I2C_MLXBF
|
||||
tristate "Mellanox BlueField I2C controller"
|
||||
depends on ARM64
|
||||
depends on MELLANOX_PLATFORM && ARM64
|
||||
help
|
||||
Enabling this option will add I2C SMBus support for Mellanox BlueField
|
||||
system.
|
||||
|
@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
||||
u32 raw_stat, stat, enabled, tmp;
|
||||
u8 val = 0, slave_activity;
|
||||
|
||||
regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
|
||||
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
|
||||
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
|
||||
regmap_read(dev->map, DW_IC_STATUS, &tmp);
|
||||
@ -168,32 +167,30 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
||||
if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
|
||||
return 0;
|
||||
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
dev_dbg(dev->dev,
|
||||
"%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
|
||||
enabled, slave_activity, raw_stat, stat);
|
||||
|
||||
if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
if (dev->status != STATUS_WRITE_IN_PROGRESS) {
|
||||
dev->status = STATUS_WRITE_IN_PROGRESS;
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED,
|
||||
&val);
|
||||
}
|
||||
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val))
|
||||
dev_vdbg(dev->dev, "Byte %X acked!", val);
|
||||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RD_REQ) {
|
||||
if (slave_activity) {
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val)) {
|
||||
dev_vdbg(dev->dev, "Byte %X acked!",
|
||||
val);
|
||||
}
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
} else {
|
||||
regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp);
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_UNDER, &tmp);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
}
|
||||
dev->status = STATUS_READ_IN_PROGRESS;
|
||||
if (!i2c_slave_event(dev->slave,
|
||||
I2C_SLAVE_READ_REQUESTED,
|
||||
&val))
|
||||
@ -205,21 +202,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
|
||||
&val))
|
||||
regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp);
|
||||
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (stat & DW_IC_INTR_RX_FULL) {
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
val = tmp;
|
||||
if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
|
||||
&val))
|
||||
dev_vdbg(dev->dev, "Byte %X acked!", val);
|
||||
} else {
|
||||
if (stat & DW_IC_INTR_STOP_DET) {
|
||||
dev->status = STATUS_IDLE;
|
||||
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
|
||||
stat = i2c_dw_read_clear_intrbits_slave(dev);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -230,7 +217,6 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
|
||||
struct dw_i2c_dev *dev = dev_id;
|
||||
int ret;
|
||||
|
||||
i2c_dw_read_clear_intrbits_slave(dev);
|
||||
ret = i2c_dw_irq_handler_slave(dev);
|
||||
if (ret > 0)
|
||||
complete(&dev->cmd_complete);
|
||||
|
@ -62,10 +62,8 @@
|
||||
* Master. Default value is set to 400MHz.
|
||||
*/
|
||||
#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000)
|
||||
/* Reference clock for Bluefield 1 - 156 MHz. */
|
||||
#define MLXBF_I2C_TYU_PLL_IN_FREQ (156 * 1000 * 1000)
|
||||
/* Reference clock for BlueField 2 - 200 MHz. */
|
||||
#define MLXBF_I2C_YU_PLL_IN_FREQ (200 * 1000 * 1000)
|
||||
/* Reference clock for Bluefield - 156 MHz. */
|
||||
#define MLXBF_I2C_PLL_IN_FREQ (156 * 1000 * 1000)
|
||||
|
||||
/* Constant used to determine the PLL frequency. */
|
||||
#define MLNXBF_I2C_COREPLL_CONST 16384
|
||||
@ -489,44 +487,6 @@ static struct mutex mlxbf_i2c_bus_lock;
|
||||
|
||||
#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000
|
||||
|
||||
static void mlxbf_i2c_write(void __iomem *io, int reg, u32 val)
|
||||
{
|
||||
writel(val, io + reg);
|
||||
}
|
||||
|
||||
static u32 mlxbf_i2c_read(void __iomem *io, int reg)
|
||||
{
|
||||
return readl(io + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to read data from Master GW Data Descriptor.
|
||||
* Data bytes in the Master GW Data Descriptor are shifted left so the
|
||||
* data starts at the MSB of the descriptor registers as set by the
|
||||
* underlying hardware. TYU_READ_DATA enables byte swapping while
|
||||
* reading data bytes, and MUST be called by the SMBus read routines
|
||||
* to copy data from the 32 * 32-bit HW Data registers a.k.a Master GW
|
||||
* Data Descriptor.
|
||||
*/
|
||||
static u32 mlxbf_i2c_read_data(void __iomem *io, int reg)
|
||||
{
|
||||
return (u32)be32_to_cpu(mlxbf_i2c_read(io, reg));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to write data to the Master GW Data Descriptor.
|
||||
* Data copied to the Master GW Data Descriptor MUST be shifted left so
|
||||
* the data starts at the MSB of the descriptor registers as required by
|
||||
* the underlying hardware. TYU_WRITE_DATA enables byte swapping when
|
||||
* writing data bytes, and MUST be called by the SMBus write routines to
|
||||
* copy data to the 32 * 32-bit HW Data registers a.k.a Master GW Data
|
||||
* Descriptor.
|
||||
*/
|
||||
static void mlxbf_i2c_write_data(void __iomem *io, int reg, u32 val)
|
||||
{
|
||||
mlxbf_i2c_write(io, reg, (u32)cpu_to_be32(val));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to poll a set of bits at a specific address; it checks whether
|
||||
* the bits are equal to zero when eq_zero is set to 'true', and not equal
|
||||
@ -541,7 +501,7 @@ static u32 mlxbf_smbus_poll(void __iomem *io, u32 addr, u32 mask,
|
||||
timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1;
|
||||
|
||||
do {
|
||||
bits = mlxbf_i2c_read(io, addr) & mask;
|
||||
bits = readl(io + addr) & mask;
|
||||
if (eq_zero ? bits == 0 : bits != 0)
|
||||
return eq_zero ? 1 : bits;
|
||||
udelay(MLXBF_I2C_POLL_FREQ_IN_USEC);
|
||||
@ -609,16 +569,16 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv)
|
||||
MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
/* Read cause status bits. */
|
||||
cause_status_bits = mlxbf_i2c_read(priv->mst_cause->io,
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_status_bits = readl(priv->mst_cause->io +
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_status_bits &= MLXBF_I2C_CAUSE_MASTER_ARBITER_BITS_MASK;
|
||||
|
||||
/*
|
||||
* Parse both Cause and Master GW bits, then return transaction status.
|
||||
*/
|
||||
|
||||
master_status_bits = mlxbf_i2c_read(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
master_status_bits = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK;
|
||||
|
||||
if (mlxbf_i2c_smbus_transaction_success(master_status_bits,
|
||||
@ -649,10 +609,17 @@ static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv,
|
||||
|
||||
aligned_length = round_up(length, 4);
|
||||
|
||||
/* Copy data bytes from 4-byte aligned source buffer. */
|
||||
/*
|
||||
* Copy data bytes from 4-byte aligned source buffer.
|
||||
* Data copied to the Master GW Data Descriptor MUST be shifted
|
||||
* left so the data starts at the MSB of the descriptor registers
|
||||
* as required by the underlying hardware. Enable byte swapping
|
||||
* when writing data bytes to the 32 * 32-bit HW Data registers
|
||||
* a.k.a Master GW Data Descriptor.
|
||||
*/
|
||||
for (offset = 0; offset < aligned_length; offset += sizeof(u32)) {
|
||||
data32 = *((u32 *)(data + offset));
|
||||
mlxbf_i2c_write_data(priv->smbus->io, addr + offset, data32);
|
||||
iowrite32be(data32, priv->smbus->io + addr + offset);
|
||||
}
|
||||
}
|
||||
|
||||
@ -664,15 +631,23 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv,
|
||||
|
||||
mask = sizeof(u32) - 1;
|
||||
|
||||
/*
|
||||
* Data bytes in the Master GW Data Descriptor are shifted left
|
||||
* so the data starts at the MSB of the descriptor registers as
|
||||
* set by the underlying hardware. Enable byte swapping while
|
||||
* reading data bytes from the 32 * 32-bit HW Data registers
|
||||
* a.k.a Master GW Data Descriptor.
|
||||
*/
|
||||
|
||||
for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) {
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io, addr + offset);
|
||||
data32 = ioread32be(priv->smbus->io + addr + offset);
|
||||
*((u32 *)(data + offset)) = data32;
|
||||
}
|
||||
|
||||
if (!(length & mask))
|
||||
return;
|
||||
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io, addr + offset);
|
||||
data32 = ioread32be(priv->smbus->io + addr + offset);
|
||||
|
||||
for (byte = 0; byte < (length & mask); byte++) {
|
||||
data[offset + byte] = data32 & GENMASK(7, 0);
|
||||
@ -698,16 +673,16 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave,
|
||||
command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT);
|
||||
|
||||
/* Clear status bits. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_STATUS, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS);
|
||||
/* Set the cause data. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_CAUSE_OR_CLEAR, ~0x0);
|
||||
writel(~0x0, priv->smbus->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
/* Zero PEC byte. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_PEC, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC);
|
||||
/* Zero byte count. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_RS_BYTES, 0x0);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES);
|
||||
|
||||
/* GW activation. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_GW, command);
|
||||
writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW);
|
||||
|
||||
/*
|
||||
* Poll master status and check status bits. An ACK is sent when
|
||||
@ -823,8 +798,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv,
|
||||
* needs to be 'manually' reset. This should be removed in
|
||||
* next tag integration.
|
||||
*/
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_MASTER_FSM,
|
||||
MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK);
|
||||
writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK,
|
||||
priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1113,8 +1088,8 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->scl_low,
|
||||
false, MLXBF_I2C_MASK_16,
|
||||
MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false,
|
||||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_0);
|
||||
@ -1124,37 +1099,34 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv,
|
||||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false,
|
||||
MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_THOLD, timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP, timer);
|
||||
writel(timer, priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA);
|
||||
|
||||
timer = mlxbf_i2c_set_timer(priv, timings->buf, false,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0);
|
||||
timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false,
|
||||
MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_THIGH_MAX_TBUF,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF);
|
||||
|
||||
timer = timings->timeout;
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT,
|
||||
timer);
|
||||
writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT);
|
||||
}
|
||||
|
||||
enum mlxbf_i2c_timings_config {
|
||||
@ -1426,19 +1398,15 @@ static int mlxbf_i2c_init_master(struct platform_device *pdev,
|
||||
* platform firmware; disabling the bus might compromise the system
|
||||
* functionality.
|
||||
*/
|
||||
config_reg = mlxbf_i2c_read(gpio_res->io,
|
||||
MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
config_reg = MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(priv->bus,
|
||||
config_reg);
|
||||
mlxbf_i2c_write(gpio_res->io, MLXBF_I2C_GPIO_0_FUNC_EN_0,
|
||||
config_reg);
|
||||
writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FUNC_EN_0);
|
||||
|
||||
config_reg = mlxbf_i2c_read(gpio_res->io,
|
||||
MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
config_reg = readl(gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
config_reg = MLXBF_I2C_GPIO_SMBUS_GW_RESET_PINS(priv->bus,
|
||||
config_reg);
|
||||
mlxbf_i2c_write(gpio_res->io, MLXBF_I2C_GPIO_0_FORCE_OE_EN,
|
||||
config_reg);
|
||||
writel(config_reg, gpio_res->io + MLXBF_I2C_GPIO_0_FORCE_OE_EN);
|
||||
|
||||
mutex_unlock(gpio_res->lock);
|
||||
|
||||
@ -1452,10 +1420,9 @@ static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res)
|
||||
u32 corepll_val;
|
||||
u16 core_f;
|
||||
|
||||
pad_frequency = MLXBF_I2C_TYU_PLL_IN_FREQ;
|
||||
pad_frequency = MLXBF_I2C_PLL_IN_FREQ;
|
||||
|
||||
corepll_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1);
|
||||
|
||||
/* Get Core PLL configuration bits. */
|
||||
core_f = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT) &
|
||||
@ -1488,12 +1455,10 @@ static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res)
|
||||
u8 core_od, core_r;
|
||||
u32 core_f;
|
||||
|
||||
pad_frequency = MLXBF_I2C_YU_PLL_IN_FREQ;
|
||||
pad_frequency = MLXBF_I2C_PLL_IN_FREQ;
|
||||
|
||||
corepll_reg1_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_reg2_val = mlxbf_i2c_read(corepll_res->io,
|
||||
MLXBF_I2C_CORE_PLL_REG2);
|
||||
corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1);
|
||||
corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2);
|
||||
|
||||
/* Get Core PLL configuration bits */
|
||||
core_f = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT) &
|
||||
@ -1585,7 +1550,7 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
|
||||
* (7-bit address, 1 status bit (1 if enabled, 0 if not)).
|
||||
*/
|
||||
for (reg = 0; reg < reg_cnt; reg++) {
|
||||
slave_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
slave_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
|
||||
/*
|
||||
* Each register holds 4 slave addresses. So, we have to keep
|
||||
@ -1643,8 +1608,8 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr)
|
||||
|
||||
/* Enable the slave address and update the register. */
|
||||
slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8);
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4, slave_reg);
|
||||
writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
|
||||
reg * 0x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1668,7 +1633,7 @@ static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv)
|
||||
* (7-bit address, 1 status bit (1 if enabled, 0 if not)).
|
||||
*/
|
||||
for (reg = 0; reg < reg_cnt; reg++) {
|
||||
slave_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
slave_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4);
|
||||
|
||||
/* Check whether the address slots are empty. */
|
||||
@ -1708,8 +1673,8 @@ static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv)
|
||||
|
||||
/* Cleanup the slave address slot. */
|
||||
slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8));
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4, slave_reg);
|
||||
writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG +
|
||||
reg * 0x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1801,7 +1766,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
|
||||
int ret;
|
||||
|
||||
/* Reset FSM. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_FSM, 0);
|
||||
writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM);
|
||||
|
||||
/*
|
||||
* Enable slave cause interrupt bits. Drive
|
||||
@ -1810,15 +1775,13 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev,
|
||||
* masters issue a Read and Write, respectively. But, clear all
|
||||
* interrupts first.
|
||||
*/
|
||||
mlxbf_i2c_write(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_OR_CLEAR, ~0);
|
||||
writel(~0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
int_reg = MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE;
|
||||
int_reg |= MLXBF_I2C_CAUSE_WRITE_SUCCESS;
|
||||
mlxbf_i2c_write(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_OR_EVTEN0, int_reg);
|
||||
writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0);
|
||||
|
||||
/* Finally, set the 'ready' bit to start handling transactions. */
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
/* Initialize the cause coalesce resource. */
|
||||
ret = mlxbf_i2c_init_coalesce(pdev, priv);
|
||||
@ -1844,23 +1807,21 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read,
|
||||
MLXBF_I2C_CAUSE_YU_SLAVE_BIT :
|
||||
priv->bus + MLXBF_I2C_CAUSE_TYU_SLAVE_BIT;
|
||||
|
||||
coalesce0_reg = mlxbf_i2c_read(priv->coalesce->io,
|
||||
MLXBF_I2C_CAUSE_COALESCE_0);
|
||||
coalesce0_reg = readl(priv->coalesce->io + MLXBF_I2C_CAUSE_COALESCE_0);
|
||||
is_set = coalesce0_reg & (1 << slave_shift);
|
||||
|
||||
if (!is_set)
|
||||
return false;
|
||||
|
||||
/* Check the source of the interrupt, i.e. whether a Read or Write. */
|
||||
cause_reg = mlxbf_i2c_read(priv->slv_cause->io,
|
||||
MLXBF_I2C_CAUSE_ARBITER);
|
||||
cause_reg = readl(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER);
|
||||
if (cause_reg & MLXBF_I2C_CAUSE_READ_WAIT_FW_RESPONSE)
|
||||
*read = true;
|
||||
else if (cause_reg & MLXBF_I2C_CAUSE_WRITE_SUCCESS)
|
||||
*write = true;
|
||||
|
||||
/* Clear cause bits. */
|
||||
mlxbf_i2c_write(priv->slv_cause->io, MLXBF_I2C_CAUSE_OR_CLEAR, ~0x0);
|
||||
writel(~0x0, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1900,8 +1861,8 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
||||
* address, if supplied.
|
||||
*/
|
||||
if (recv_bytes > 0) {
|
||||
data32 = mlxbf_i2c_read_data(priv->smbus->io,
|
||||
MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
|
||||
data32 = ioread32be(priv->smbus->io +
|
||||
MLXBF_I2C_SLAVE_DATA_DESC_ADDR);
|
||||
|
||||
/* Parse the received bytes. */
|
||||
switch (recv_bytes) {
|
||||
@ -1966,7 +1927,7 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
||||
control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT);
|
||||
control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT);
|
||||
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_GW, control32);
|
||||
writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW);
|
||||
|
||||
/*
|
||||
* Wait until the transfer is completed; the driver will wait
|
||||
@ -1975,10 +1936,9 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
||||
mlxbf_smbus_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT);
|
||||
|
||||
/* Release the Slave GW. */
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_PEC, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2023,10 +1983,9 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes)
|
||||
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
|
||||
|
||||
/* Release the Slave GW. */
|
||||
mlxbf_i2c_write(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_PEC, 0x0);
|
||||
mlxbf_i2c_write(priv->smbus->io, MLXBF_I2C_SMBUS_SLAVE_READY, 0x1);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC);
|
||||
writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2061,8 +2020,8 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr)
|
||||
* slave, if the higher 8 bits are sent then the slave expect N bytes
|
||||
* from the master.
|
||||
*/
|
||||
rw_bytes_reg = mlxbf_i2c_read(priv->smbus->io,
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
rw_bytes_reg = readl(priv->smbus->io +
|
||||
MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES);
|
||||
recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0);
|
||||
|
||||
/*
|
||||
@ -2264,6 +2223,7 @@ static const struct of_device_id mlxbf_i2c_dt_ids[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = {
|
||||
{ "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] },
|
||||
{ "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] },
|
||||
@ -2305,6 +2265,12 @@ static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv)
|
||||
{
|
||||
@ -2473,7 +2439,9 @@ static struct platform_driver mlxbf_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-mlxbf",
|
||||
.of_match_table = mlxbf_i2c_dt_ids,
|
||||
#ifdef CONFIG_ACPI
|
||||
.acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids),
|
||||
#endif /* CONFIG_ACPI */
|
||||
},
|
||||
};
|
||||
|
||||
@ -2502,5 +2470,5 @@ static void __exit mlxbf_i2c_exit(void)
|
||||
module_exit(mlxbf_i2c_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver");
|
||||
MODULE_AUTHOR("Khalil Blaiech <kblaiech@mellanox.com>");
|
||||
MODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -475,6 +475,10 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
||||
{
|
||||
u16 control_reg;
|
||||
|
||||
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
|
||||
udelay(50);
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
|
||||
|
||||
mtk_i2c_writew(i2c, I2C_SOFT_RST, OFFSET_SOFTRESET);
|
||||
|
||||
/* Set ioconfig */
|
||||
@ -529,10 +533,6 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c)
|
||||
|
||||
mtk_i2c_writew(i2c, control_reg, OFFSET_CONTROL);
|
||||
mtk_i2c_writew(i2c, I2C_DELAY_LEN, OFFSET_DELAY_LEN);
|
||||
|
||||
writel(I2C_DMA_HARD_RST, i2c->pdmabase + OFFSET_RST);
|
||||
udelay(50);
|
||||
writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST);
|
||||
}
|
||||
|
||||
static const struct i2c_spec_values *mtk_i2c_get_spec(unsigned int speed)
|
||||
|
@ -129,6 +129,7 @@ struct sh_mobile_i2c_data {
|
||||
int sr;
|
||||
bool send_stop;
|
||||
bool stop_after_dma;
|
||||
bool atomic_xfer;
|
||||
|
||||
struct resource *res;
|
||||
struct dma_chan *dma_tx;
|
||||
@ -330,13 +331,15 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op
|
||||
ret = iic_rd(pd, ICDR);
|
||||
break;
|
||||
case OP_RX_STOP: /* enable DTE interrupt, issue stop */
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
if (!pd->atomic_xfer)
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
|
||||
break;
|
||||
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
if (!pd->atomic_xfer)
|
||||
iic_wr(pd, ICIC,
|
||||
ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
|
||||
ret = iic_rd(pd, ICDR);
|
||||
iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
|
||||
break;
|
||||
@ -429,7 +432,8 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
|
||||
|
||||
if (wakeup) {
|
||||
pd->sr |= SW_DONE;
|
||||
wake_up(&pd->wait);
|
||||
if (!pd->atomic_xfer)
|
||||
wake_up(&pd->wait);
|
||||
}
|
||||
|
||||
/* defeat write posting to avoid spurious WAIT interrupts */
|
||||
@ -581,6 +585,9 @@ static void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
|
||||
pd->pos = -1;
|
||||
pd->sr = 0;
|
||||
|
||||
if (pd->atomic_xfer)
|
||||
return;
|
||||
|
||||
pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
|
||||
if (pd->dma_buf)
|
||||
sh_mobile_i2c_xfer_dma(pd);
|
||||
@ -637,15 +644,13 @@ static int poll_busy(struct sh_mobile_i2c_data *pd)
|
||||
return i ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *msg;
|
||||
int err = 0;
|
||||
int i;
|
||||
long timeout;
|
||||
long time_left;
|
||||
|
||||
/* Wake up device and enable clock */
|
||||
pm_runtime_get_sync(pd->dev);
|
||||
@ -662,15 +667,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
if (do_start)
|
||||
i2c_op(pd, OP_START);
|
||||
|
||||
/* The interrupt handler takes care of the rest... */
|
||||
timeout = wait_event_timeout(pd->wait,
|
||||
pd->sr & (ICSR_TACK | SW_DONE),
|
||||
adapter->timeout);
|
||||
if (pd->atomic_xfer) {
|
||||
unsigned long j = jiffies + pd->adap.timeout;
|
||||
|
||||
/* 'stop_after_dma' tells if DMA transfer was complete */
|
||||
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg, pd->stop_after_dma);
|
||||
time_left = time_before_eq(jiffies, j);
|
||||
while (time_left &&
|
||||
!(pd->sr & (ICSR_TACK | SW_DONE))) {
|
||||
unsigned char sr = iic_rd(pd, ICSR);
|
||||
|
||||
if (!timeout) {
|
||||
if (sr & (ICSR_AL | ICSR_TACK |
|
||||
ICSR_WAIT | ICSR_DTE)) {
|
||||
sh_mobile_i2c_isr(0, pd);
|
||||
udelay(150);
|
||||
} else {
|
||||
cpu_relax();
|
||||
}
|
||||
time_left = time_before_eq(jiffies, j);
|
||||
}
|
||||
} else {
|
||||
/* The interrupt handler takes care of the rest... */
|
||||
time_left = wait_event_timeout(pd->wait,
|
||||
pd->sr & (ICSR_TACK | SW_DONE),
|
||||
pd->adap.timeout);
|
||||
|
||||
/* 'stop_after_dma' tells if DMA xfer was complete */
|
||||
i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
|
||||
pd->stop_after_dma);
|
||||
}
|
||||
|
||||
if (!time_left) {
|
||||
dev_err(pd->dev, "Transfer request timed out\n");
|
||||
if (pd->dma_direction != DMA_NONE)
|
||||
sh_mobile_i2c_cleanup_dma(pd);
|
||||
@ -696,14 +721,35 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
return err ?: num;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
|
||||
pd->atomic_xfer = false;
|
||||
return sh_mobile_xfer(pd, msgs, num);
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
|
||||
|
||||
pd->atomic_xfer = true;
|
||||
return sh_mobile_xfer(pd, msgs, num);
|
||||
}
|
||||
|
||||
static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.master_xfer = sh_mobile_i2c_xfer,
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.master_xfer = sh_mobile_i2c_xfer,
|
||||
.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
|
||||
|
Loading…
Reference in New Issue
Block a user