mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Merge tag 'i2c-host-6.20' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-mergewindow
i2c-host for v6.20 - amd-mp2, designware, mlxbf, rtl9300, spacemit, tegra: cleanups - designware: use a dedicated algorithm for AMD Navi - designware: replace magic numbers with named constants - designware: replace min_t() with min() to avoid u8 truncation - designware: refactor core to enable mode switching - imx-lpi2c: add runtime PM support for IRQ and clock handling - lan9691-i2c: add new driver - rtl9300: use OF helpers directly and avoid fwnode handling - spacemit: add bus reset support - units: add HZ_PER_GHZ and use it in several i2c drivers
This commit is contained in:
@@ -26,6 +26,7 @@ properties:
|
||||
- microchip,sam9x60-i2c
|
||||
- items:
|
||||
- enum:
|
||||
- microchip,lan9691-i2c
|
||||
- microchip,sama7d65-i2c
|
||||
- microchip,sama7g5-i2c
|
||||
- microchip,sam9x7-i2c
|
||||
|
||||
@@ -41,6 +41,9 @@ properties:
|
||||
default: 400000
|
||||
maximum: 3300000
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -569,24 +569,17 @@ config I2C_DESIGNWARE_CORE
|
||||
help
|
||||
This option enables support for the Synopsys DesignWare I2C adapter.
|
||||
This driver includes support for the I2C host on the Synopsys
|
||||
Designware I2C adapter.
|
||||
Designware I2C adapter, and the I2C slave when enabled (select
|
||||
I2C_SLAVE).
|
||||
|
||||
To compile the driver as a module, choose M here: the module will be
|
||||
called i2c-designware-core.
|
||||
|
||||
if I2C_DESIGNWARE_CORE
|
||||
|
||||
config I2C_DESIGNWARE_SLAVE
|
||||
bool "Synopsys DesignWare Slave"
|
||||
select I2C_SLAVE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
Synopsys DesignWare I2C slave adapter.
|
||||
|
||||
config I2C_DESIGNWARE_PLATFORM
|
||||
tristate "Synopsys DesignWare Platform driver"
|
||||
depends on (ACPI && COMMON_CLK) || !ACPI
|
||||
select MFD_SYSCON if MIPS_BAIKAL_T1
|
||||
default I2C_DESIGNWARE_CORE
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
|
||||
@@ -53,7 +53,7 @@ obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
|
||||
i2c-designware-core-y := i2c-designware-common.o
|
||||
i2c-designware-core-y += i2c-designware-master.o
|
||||
i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o
|
||||
i2c-designware-core-$(CONFIG_I2C_SLAVE) += i2c-designware-slave.o
|
||||
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
|
||||
i2c-designware-platform-y := i2c-designware-platdrv.o
|
||||
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_AMDPSP) += i2c-designware-amdpsp.o
|
||||
|
||||
@@ -456,18 +456,20 @@ module_pci_driver(amd_mp2_pci_driver);
|
||||
|
||||
struct amd_mp2_dev *amd_mp2_find_device(void)
|
||||
{
|
||||
struct amd_mp2_dev *privdata;
|
||||
struct device *dev;
|
||||
struct pci_dev *pci_dev;
|
||||
struct amd_mp2_dev *mp2_dev;
|
||||
|
||||
dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
pci_dev = to_pci_dev(dev);
|
||||
mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev);
|
||||
privdata = pci_get_drvdata(pci_dev);
|
||||
|
||||
put_device(dev);
|
||||
return mp2_dev;
|
||||
|
||||
return privdata;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_mp2_find_device);
|
||||
|
||||
|
||||
@@ -163,8 +163,8 @@ static int amd_isp_dw_i2c_plat_runtime_resume(struct device *dev)
|
||||
|
||||
if (!i_dev->shared_with_punit)
|
||||
i2c_dw_prepare_clk(i_dev, true);
|
||||
if (i_dev->init)
|
||||
i_dev->init(i_dev);
|
||||
|
||||
i2c_dw_init(i_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW_COMMON"
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
@@ -34,6 +35,10 @@
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
#define DW_IC_DEFAULT_BUS_CAPACITANCE_pF 100
|
||||
#define DW_IC_ABORT_TIMEOUT_US 10
|
||||
#define DW_IC_BUSY_POLL_TIMEOUT_US (1 * USEC_PER_MSEC)
|
||||
|
||||
static const char *const abort_sources[] = {
|
||||
[ABRT_7B_ADDR_NOACK] =
|
||||
"slave address not acknowledged (7bit mode)",
|
||||
@@ -106,7 +111,7 @@ static int dw_reg_read_word(void *context, unsigned int reg, unsigned int *val)
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
*val = readw(dev->base + reg) |
|
||||
(readw(dev->base + reg + 2) << 16);
|
||||
(readw(dev->base + reg + DW_IC_REG_STEP_BYTES) << DW_IC_REG_WORD_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -116,7 +121,7 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
|
||||
struct dw_i2c_dev *dev = context;
|
||||
|
||||
writew(val, dev->base + reg);
|
||||
writew(val >> 16, dev->base + reg + 2);
|
||||
writew(val >> DW_IC_REG_WORD_SHIFT, dev->base + reg + DW_IC_REG_STEP_BYTES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -131,7 +136,7 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
|
||||
*
|
||||
* Return: 0 on success, or negative errno otherwise.
|
||||
*/
|
||||
int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
|
||||
static int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct regmap_config map_cfg = {
|
||||
.reg_bits = 32,
|
||||
@@ -165,7 +170,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
|
||||
if (reg == swab32(DW_IC_COMP_TYPE_VALUE)) {
|
||||
map_cfg.reg_read = dw_reg_read_swab;
|
||||
map_cfg.reg_write = dw_reg_write_swab;
|
||||
} else if (reg == (DW_IC_COMP_TYPE_VALUE & 0x0000ffff)) {
|
||||
} else if (reg == lower_16_bits(DW_IC_COMP_TYPE_VALUE)) {
|
||||
map_cfg.reg_read = dw_reg_read_word;
|
||||
map_cfg.reg_write = dw_reg_write_word;
|
||||
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
|
||||
@@ -238,14 +243,10 @@ static void i2c_dw_of_configure(struct device *device)
|
||||
struct platform_device *pdev = to_platform_device(device);
|
||||
struct dw_i2c_dev *dev = dev_get_drvdata(device);
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_MSCC_OCELOT:
|
||||
if (device_is_compatible(dev->dev, "mscc,ocelot-i2c")) {
|
||||
dev->ext = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (!IS_ERR(dev->ext))
|
||||
dev->set_sda_hold_time = mscc_twi_set_sda_hold_time;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,6 +359,109 @@ static inline u32 i2c_dw_acpi_round_bus_speed(struct device *device) { return 0;
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static void i2c_dw_configure_mode(struct dw_i2c_dev *dev, int mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case DW_IC_MASTER:
|
||||
regmap_write(dev->map, DW_IC_TX_TL, dev->tx_fifo_depth / 2);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
|
||||
break;
|
||||
case DW_IC_SLAVE:
|
||||
dev->status = 0;
|
||||
regmap_write(dev->map, DW_IC_TX_TL, 0);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
regmap_write(dev->map, DW_IC_CON, dev->slave_cfg);
|
||||
regmap_write(dev->map, DW_IC_SAR, dev->slave->addr);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_SLAVE_MASK);
|
||||
__i2c_dw_enable(dev);
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Invalid mode %d\n", mode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_dw_write_timings(struct dw_i2c_dev *dev)
|
||||
{
|
||||
/* Write standard speed timing parameters */
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt);
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);
|
||||
|
||||
/* Write fast mode/fast mode plus timing parameters */
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_HCNT, dev->fs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_LCNT, dev->fs_lcnt);
|
||||
|
||||
/* Write high speed timing parameters */
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_HCNT, dev->hs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_LCNT, dev->hs_lcnt);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dw_set_mode() - Select the controller mode of operation - master or slave
|
||||
* @dev: device private data
|
||||
* @mode: I2C mode of operation
|
||||
*
|
||||
* Configures the controller to operate in @mode. This function needs to be
|
||||
* called when ever a mode swap is required.
|
||||
*
|
||||
* Setting the slave mode does not have an effect before a slave device is
|
||||
* registered. So before the slave device is registered, the controller is kept
|
||||
* in master mode regardless of @mode.
|
||||
*
|
||||
* The controller must be disabled before this function is called.
|
||||
*/
|
||||
void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode)
|
||||
{
|
||||
if (mode == DW_IC_SLAVE && !dev->slave)
|
||||
mode = DW_IC_MASTER;
|
||||
if (dev->mode == mode)
|
||||
return;
|
||||
|
||||
i2c_dw_configure_mode(dev, mode);
|
||||
dev->mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dw_init() - Initialize the DesignWare I2C hardware
|
||||
* @dev: device private data
|
||||
*
|
||||
* This functions configures and enables the DesigWare I2C hardware.
|
||||
*
|
||||
* Return: 0 on success, or negative errno otherwise.
|
||||
*/
|
||||
int i2c_dw_init(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the adapter */
|
||||
__i2c_dw_disable(dev);
|
||||
|
||||
/*
|
||||
* Mask SMBus interrupts to block storms from broken
|
||||
* firmware that leaves IC_SMBUS=1; the handler never
|
||||
* services them.
|
||||
*/
|
||||
regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0);
|
||||
|
||||
i2c_dw_write_timings(dev);
|
||||
|
||||
/* Write SDA hold time if supported */
|
||||
if (dev->sda_hold_time)
|
||||
regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
|
||||
|
||||
i2c_dw_configure_mode(dev, dev->mode);
|
||||
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_init);
|
||||
|
||||
static void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev);
|
||||
@@ -384,7 +488,7 @@ int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev)
|
||||
i2c_parse_fw_timings(device, t, false);
|
||||
|
||||
if (device_property_read_u32(device, "snps,bus-capacitance-pf", &dev->bus_capacitance_pF))
|
||||
dev->bus_capacitance_pF = 100;
|
||||
dev->bus_capacitance_pF = DW_IC_DEFAULT_BUS_CAPACITANCE_pF;
|
||||
|
||||
dev->clk_freq_optimized = device_property_read_bool(device, "snps,clk-freq-optimized");
|
||||
|
||||
@@ -457,7 +561,7 @@ u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
|
||||
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset;
|
||||
}
|
||||
|
||||
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
|
||||
static int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
|
||||
{
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
@@ -539,8 +643,9 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
|
||||
regmap_write(dev->map, DW_IC_ENABLE, enable | DW_IC_ENABLE_ABORT);
|
||||
ret = regmap_read_poll_timeout(dev->map, DW_IC_ENABLE, enable,
|
||||
!(enable & DW_IC_ENABLE_ABORT), 10,
|
||||
100);
|
||||
!(enable & DW_IC_ENABLE_ABORT),
|
||||
DW_IC_ABORT_TIMEOUT_US,
|
||||
10 * DW_IC_ABORT_TIMEOUT_US);
|
||||
if (ret)
|
||||
dev_err(dev->dev, "timeout while trying to abort current transfer\n");
|
||||
}
|
||||
@@ -552,7 +657,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
* in that case this test reads zero and exits the loop.
|
||||
*/
|
||||
regmap_read(dev->map, DW_IC_ENABLE_STATUS, &status);
|
||||
if ((status & 1) == 0)
|
||||
if (!(status & 1))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -635,7 +740,8 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev)
|
||||
|
||||
ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status,
|
||||
!(status & DW_IC_STATUS_ACTIVITY),
|
||||
1100, 20000);
|
||||
DW_IC_BUSY_POLL_TIMEOUT_US,
|
||||
20 * DW_IC_BUSY_POLL_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||
|
||||
@@ -672,7 +778,7 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
||||
static int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
||||
{
|
||||
u32 tx_fifo_depth, rx_fifo_depth;
|
||||
unsigned int param;
|
||||
@@ -699,12 +805,12 @@ int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tx_fifo_depth = ((param >> 16) & 0xff) + 1;
|
||||
rx_fifo_depth = ((param >> 8) & 0xff) + 1;
|
||||
tx_fifo_depth = FIELD_GET(DW_IC_FIFO_TX_FIELD, param) + 1;
|
||||
rx_fifo_depth = FIELD_GET(DW_IC_FIFO_RX_FIELD, param) + 1;
|
||||
if (!dev->tx_fifo_depth) {
|
||||
dev->tx_fifo_depth = tx_fifo_depth;
|
||||
dev->rx_fifo_depth = rx_fifo_depth;
|
||||
} else if (tx_fifo_depth >= 2) {
|
||||
} else if (tx_fifo_depth >= DW_IC_FIFO_MIN_DEPTH) {
|
||||
dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth,
|
||||
tx_fifo_depth);
|
||||
dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth,
|
||||
@@ -741,19 +847,103 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_disable);
|
||||
|
||||
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_id;
|
||||
|
||||
if (dev->mode == DW_IC_SLAVE)
|
||||
return i2c_dw_isr_slave(dev);
|
||||
|
||||
return i2c_dw_isr_master(dev);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.xfer = i2c_dw_xfer,
|
||||
.functionality = i2c_dw_func,
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
.reg_slave = i2c_dw_reg_slave,
|
||||
.unreg_slave = i2c_dw_unreg_slave,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks i2c_dw_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
};
|
||||
|
||||
int i2c_dw_probe(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
unsigned long irq_flags;
|
||||
int ret;
|
||||
|
||||
device_set_node(&dev->adapter.dev, dev_fwnode(dev->dev));
|
||||
|
||||
switch (dev->mode) {
|
||||
case DW_IC_SLAVE:
|
||||
return i2c_dw_probe_slave(dev);
|
||||
case DW_IC_MASTER:
|
||||
return i2c_dw_probe_master(dev);
|
||||
default:
|
||||
dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode);
|
||||
return -EINVAL;
|
||||
ret = i2c_dw_init_regmap(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_sda_hold(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_fifo_size(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_probe_master(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!adap->name[0])
|
||||
strscpy(adap->name, "Synopsys DesignWare I2C adapter");
|
||||
|
||||
adap->retries = 3;
|
||||
adap->algo = &i2c_dw_algo;
|
||||
adap->quirks = &i2c_dw_quirks;
|
||||
adap->dev.parent = dev->dev;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
/*
|
||||
* REVISIT: The mode check may not be necessary.
|
||||
* For now keeping the flags as they were originally.
|
||||
*/
|
||||
if (dev->mode == DW_IC_SLAVE)
|
||||
irq_flags = IRQF_SHARED;
|
||||
else if (dev->flags & ACCESS_NO_IRQ_SUSPEND)
|
||||
irq_flags = IRQF_NO_SUSPEND;
|
||||
else
|
||||
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
__i2c_dw_write_intr_mask(dev, 0);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
if (!(dev->flags & ACCESS_POLLING)) {
|
||||
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
|
||||
irq_flags, dev_name(dev->dev), dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment PM usage count during adapter registration in order to
|
||||
* avoid possible spurious runtime suspend when adapter device is
|
||||
* registered to the device core and immediate resume in case bus has
|
||||
* registered I2C slaves that do I2C transfers in their probe.
|
||||
*/
|
||||
ACQUIRE(pm_runtime_noresume, pm)(dev->dev);
|
||||
ret = ACQUIRE_ERR(pm_runtime_noresume, &pm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return i2c_add_numbered_adapter(adap);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_probe);
|
||||
|
||||
@@ -797,7 +987,7 @@ static int i2c_dw_runtime_resume(struct device *device)
|
||||
if (!dev->shared_with_punit)
|
||||
i2c_dw_prepare_clk(dev, true);
|
||||
|
||||
dev->init(dev);
|
||||
i2c_dw_init(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
@@ -41,6 +42,19 @@
|
||||
#define DW_IC_DATA_CMD_DAT GENMASK(7, 0)
|
||||
#define DW_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11)
|
||||
|
||||
/*
|
||||
* Register access parameters
|
||||
*/
|
||||
#define DW_IC_REG_STEP_BYTES 2
|
||||
#define DW_IC_REG_WORD_SHIFT 16
|
||||
|
||||
/*
|
||||
* FIFO depth configuration
|
||||
*/
|
||||
#define DW_IC_FIFO_TX_FIELD GENMASK(23, 16)
|
||||
#define DW_IC_FIFO_RX_FIELD GENMASK(15, 8)
|
||||
#define DW_IC_FIFO_MIN_DEPTH 2
|
||||
|
||||
/*
|
||||
* Registers offset
|
||||
*/
|
||||
@@ -239,7 +253,6 @@ struct reset_control;
|
||||
* @semaphore_idx: Index of table with semaphore type attached to the bus. It's
|
||||
* -1 if there is no semaphore.
|
||||
* @shared_with_punit: true if this bus is shared with the SoC's PUNIT
|
||||
* @init: function to initialize the I2C hardware
|
||||
* @set_sda_hold_time: callback to retrieve IP specific SDA hold timing
|
||||
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
|
||||
* @rinfo: I²C GPIO recovery information
|
||||
@@ -300,7 +313,6 @@ struct dw_i2c_dev {
|
||||
void (*release_lock)(void);
|
||||
int semaphore_idx;
|
||||
bool shared_with_punit;
|
||||
int (*init)(struct dw_i2c_dev *dev);
|
||||
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
|
||||
int mode;
|
||||
struct i2c_bus_recovery_info rinfo;
|
||||
@@ -313,8 +325,6 @@ struct dw_i2c_dev {
|
||||
#define ARBITRATION_SEMAPHORE BIT(2)
|
||||
#define ACCESS_POLLING BIT(3)
|
||||
|
||||
#define MODEL_MSCC_OCELOT BIT(8)
|
||||
#define MODEL_BAIKAL_BT1 BIT(9)
|
||||
#define MODEL_AMD_NAVI_GPU BIT(10)
|
||||
#define MODEL_WANGXUN_SP BIT(11)
|
||||
#define MODEL_MASK GENMASK(11, 8)
|
||||
@@ -333,20 +343,18 @@ struct i2c_dw_semaphore_callbacks {
|
||||
int (*probe)(struct dw_i2c_dev *dev);
|
||||
};
|
||||
|
||||
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
|
||||
u32 tSYMBOL, u32 tf, int offset);
|
||||
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
|
||||
u32 tLOW, u32 tf, int offset);
|
||||
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
|
||||
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_func(struct i2c_adapter *adap);
|
||||
irqreturn_t i2c_dw_isr_master(struct dw_i2c_dev *dev);
|
||||
|
||||
extern const struct dev_pm_ops i2c_dw_dev_pm_ops;
|
||||
|
||||
@@ -386,23 +394,27 @@ void i2c_dw_disable(struct dw_i2c_dev *dev);
|
||||
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
|
||||
extern int i2c_dw_probe_master(struct dw_i2c_dev *dev);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_SLAVE)
|
||||
int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||
extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev);
|
||||
extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
|
||||
irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_reg_slave(struct i2c_client *client);
|
||||
int i2c_dw_unreg_slave(struct i2c_client *client);
|
||||
#else
|
||||
static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { }
|
||||
static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
|
||||
static inline irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev) { return IRQ_NONE; }
|
||||
#endif
|
||||
|
||||
static inline void i2c_dw_configure(struct dw_i2c_dev *dev)
|
||||
{
|
||||
if (i2c_detect_slave_mode(dev->dev))
|
||||
i2c_dw_configure_slave(dev);
|
||||
else
|
||||
i2c_dw_configure_master(dev);
|
||||
i2c_dw_configure_slave(dev);
|
||||
i2c_dw_configure_master(dev);
|
||||
}
|
||||
|
||||
int i2c_dw_probe(struct dw_i2c_dev *dev);
|
||||
int i2c_dw_init(struct dw_i2c_dev *dev);
|
||||
void i2c_dw_set_mode(struct dw_i2c_dev *dev, int mode);
|
||||
|
||||
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
|
||||
int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev);
|
||||
|
||||
@@ -31,16 +31,6 @@
|
||||
#define AMD_TIMEOUT_MAX_US 250
|
||||
#define AMD_MASTERCFG_MASK GENMASK(15, 0)
|
||||
|
||||
static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
/* Configure Tx/Rx FIFO threshold levels */
|
||||
regmap_write(dev->map, DW_IC_TX_TL, dev->tx_fifo_depth / 2);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
|
||||
/* Configure the I2C master */
|
||||
regmap_write(dev->map, DW_IC_CON, dev->master_cfg);
|
||||
}
|
||||
|
||||
static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
unsigned int comp_param1;
|
||||
@@ -191,66 +181,10 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
|
||||
dev->hs_hcnt, dev->hs_lcnt);
|
||||
}
|
||||
|
||||
ret = i2c_dw_set_sda_hold(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev->dev, "Bus speed: %s\n", i2c_freq_mode_string(t->bus_freq_hz));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dw_init_master() - Initialize the DesignWare I2C master hardware
|
||||
* @dev: device private data
|
||||
*
|
||||
* This functions configures and enables the I2C master.
|
||||
* This function is called during I2C init function, and in case of timeout at
|
||||
* run time.
|
||||
*
|
||||
* Return: 0 on success, or negative errno otherwise.
|
||||
*/
|
||||
static int i2c_dw_init_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the adapter */
|
||||
__i2c_dw_disable(dev);
|
||||
|
||||
/*
|
||||
* Mask SMBus interrupts to block storms from broken
|
||||
* firmware that leaves IC_SMBUS=1; the handler never
|
||||
* services them.
|
||||
*/
|
||||
regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0);
|
||||
|
||||
/* Write standard speed timing parameters */
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt);
|
||||
regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);
|
||||
|
||||
/* Write fast mode/fast mode plus timing parameters */
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_HCNT, dev->fs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_FS_SCL_LCNT, dev->fs_lcnt);
|
||||
|
||||
/* Write high speed timing parameters if supported */
|
||||
if (dev->hs_hcnt && dev->hs_lcnt) {
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_HCNT, dev->hs_hcnt);
|
||||
regmap_write(dev->map, DW_IC_HS_SCL_LCNT, dev->hs_lcnt);
|
||||
}
|
||||
|
||||
/* Write SDA hold time if supported */
|
||||
if (dev->sda_hold_time)
|
||||
regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
|
||||
|
||||
i2c_dw_configure_fifo_master(dev);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_msg *msgs = dev->msgs;
|
||||
@@ -260,6 +194,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
|
||||
/* Disable the adapter */
|
||||
__i2c_dw_disable(dev);
|
||||
|
||||
i2c_dw_set_mode(dev, DW_IC_MASTER);
|
||||
|
||||
/* If the slave address is ten bit address, enable 10BITADDR */
|
||||
if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) {
|
||||
ic_con = DW_IC_CON_10BITADDR_MASTER;
|
||||
@@ -353,14 +289,17 @@ static int i2c_dw_status(struct dw_i2c_dev *dev)
|
||||
* Initiate and continue master read/write transaction with polling
|
||||
* based transfer routine afterward write messages into the Tx buffer.
|
||||
*/
|
||||
static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, int num_msgs)
|
||||
static int amd_i2c_dw_xfer_quirk(struct dw_i2c_dev *dev, struct i2c_msg *msgs, int num_msgs)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
|
||||
int cmd = 0, status;
|
||||
u8 *tx_buf;
|
||||
unsigned int val;
|
||||
|
||||
ACQUIRE(pm_runtime_active_auto_try, pm)(dev->dev);
|
||||
if (ACQUIRE_ERR(pm_runtime_active_auto_try, &pm))
|
||||
return -ENXIO;
|
||||
|
||||
/*
|
||||
* In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card,
|
||||
* it is mandatory to set the right value in specific register
|
||||
@@ -571,7 +510,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
|
||||
* after receiving the first byte.
|
||||
*/
|
||||
len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
|
||||
dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
|
||||
dev->tx_buf_len = len - min(len, dev->rx_outstanding);
|
||||
msgs[dev->msg_read_idx].len = len;
|
||||
msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
|
||||
|
||||
@@ -593,11 +532,12 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
||||
unsigned int rx_valid;
|
||||
|
||||
for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) {
|
||||
u32 flags = msgs[dev->msg_read_idx].flags;
|
||||
unsigned int tmp;
|
||||
u32 len;
|
||||
u8 *buf;
|
||||
|
||||
if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD))
|
||||
if (!(flags & I2C_M_RD))
|
||||
continue;
|
||||
|
||||
if (!(dev->status & STATUS_READ_IN_PROGRESS)) {
|
||||
@@ -611,8 +551,6 @@ i2c_dw_read(struct dw_i2c_dev *dev)
|
||||
regmap_read(dev->map, DW_IC_RXFLR, &rx_valid);
|
||||
|
||||
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
|
||||
u32 flags = msgs[dev->msg_read_idx].flags;
|
||||
|
||||
regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
|
||||
tmp &= DW_IC_DATA_CMD_DAT;
|
||||
/* Ensure length byte is a valid value */
|
||||
@@ -749,9 +687,8 @@ tx_aborted:
|
||||
* Interrupt service routine. This gets called whenever an I2C master interrupt
|
||||
* occurs.
|
||||
*/
|
||||
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
|
||||
irqreturn_t i2c_dw_isr_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_id;
|
||||
unsigned int stat, enabled;
|
||||
|
||||
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
|
||||
@@ -812,23 +749,14 @@ static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev)
|
||||
* Prepare controller for a transaction and call i2c_dw_xfer_msg.
|
||||
*/
|
||||
static int
|
||||
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
int ret;
|
||||
|
||||
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
|
||||
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_AMD_NAVI_GPU:
|
||||
ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
|
||||
goto done_nolock;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reinit_completion(&dev->cmd_complete);
|
||||
dev->msgs = msgs;
|
||||
dev->msgs_num = num;
|
||||
@@ -855,9 +783,9 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
ret = i2c_dw_wait_transfer(dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "controller timed out\n");
|
||||
/* i2c_dw_init_master() implicitly disables the adapter */
|
||||
/* i2c_dw_init() implicitly disables the adapter */
|
||||
i2c_recover_bus(&dev->adapter);
|
||||
i2c_dw_init_master(dev);
|
||||
i2c_dw_init(dev);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -905,6 +833,8 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||
ret = -EIO;
|
||||
|
||||
done:
|
||||
i2c_dw_set_mode(dev, DW_IC_SLAVE);
|
||||
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
done_nolock:
|
||||
@@ -913,20 +843,21 @@ done_nolock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.xfer = i2c_dw_xfer,
|
||||
.functionality = i2c_dw_func,
|
||||
};
|
||||
int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||
|
||||
static const struct i2c_adapter_quirks i2c_dw_quirks = {
|
||||
.flags = I2C_AQ_NO_ZERO_LEN,
|
||||
};
|
||||
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
|
||||
return amd_i2c_dw_xfer_quirk(dev, msgs, num);
|
||||
|
||||
return i2c_dw_xfer_common(dev, msgs, num);
|
||||
}
|
||||
|
||||
void i2c_dw_configure_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_timings *t = &dev->timings;
|
||||
|
||||
dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
dev->functionality |= I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
|
||||
|
||||
dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
|
||||
DW_IC_CON_RESTART_EN;
|
||||
@@ -961,7 +892,7 @@ static void i2c_dw_unprepare_recovery(struct i2c_adapter *adap)
|
||||
|
||||
i2c_dw_prepare_clk(dev, true);
|
||||
reset_control_deassert(dev->rst);
|
||||
i2c_dw_init_master(dev);
|
||||
i2c_dw_init(dev);
|
||||
}
|
||||
|
||||
static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
|
||||
@@ -1005,27 +936,15 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
|
||||
|
||||
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
unsigned long irq_flags;
|
||||
unsigned int ic_con;
|
||||
int ret;
|
||||
|
||||
init_completion(&dev->cmd_complete);
|
||||
|
||||
dev->init = i2c_dw_init_master;
|
||||
|
||||
ret = i2c_dw_init_regmap(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_timings_master(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_fifo_size(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Lock the bus for accessing DW_IC_CON */
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
@@ -1045,60 +964,8 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
|
||||
if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL)
|
||||
dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL;
|
||||
|
||||
ret = dev->init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!adap->name[0])
|
||||
scnprintf(adap->name, sizeof(adap->name),
|
||||
"Synopsys DesignWare I2C adapter");
|
||||
adap->retries = 3;
|
||||
adap->algo = &i2c_dw_algo;
|
||||
adap->quirks = &i2c_dw_quirks;
|
||||
adap->dev.parent = dev->dev;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
|
||||
irq_flags = IRQF_NO_SUSPEND;
|
||||
} else {
|
||||
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
|
||||
}
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
__i2c_dw_write_intr_mask(dev, 0);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
if (!(dev->flags & ACCESS_POLLING)) {
|
||||
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
|
||||
irq_flags, dev_name(dev->dev), dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev->dev, ret,
|
||||
"failure requesting irq %i: %d\n",
|
||||
dev->irq, ret);
|
||||
}
|
||||
|
||||
ret = i2c_dw_init_recovery_info(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Increment PM usage count during adapter registration in order to
|
||||
* avoid possible spurious runtime suspend when adapter device is
|
||||
* registered to the device core and immediate resume in case bus has
|
||||
* registered I2C slaves that do I2C transfers in their probe.
|
||||
*/
|
||||
pm_runtime_get_noresume(dev->dev);
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret)
|
||||
dev_err(dev->dev, "failure adding adapter: %d\n", ret);
|
||||
pm_runtime_put_noidle(dev->dev);
|
||||
|
||||
return ret;
|
||||
return i2c_dw_init_recovery_info(dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_probe_master);
|
||||
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -37,70 +37,6 @@ static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
|
||||
return clk_get_rate(dev->clk) / HZ_PER_KHZ;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
#define BT1_I2C_CTL 0x100
|
||||
#define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0)
|
||||
#define BT1_I2C_CTL_WR BIT(8)
|
||||
#define BT1_I2C_CTL_GO BIT(31)
|
||||
#define BT1_I2C_DI 0x104
|
||||
#define BT1_I2C_DO 0x108
|
||||
|
||||
static int bt1_i2c_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note these methods shouldn't ever fail because the system controller
|
||||
* registers are memory mapped. We check the return value just in case.
|
||||
*/
|
||||
ret = regmap_write(dev->sysmap, BT1_I2C_CTL,
|
||||
BT1_I2C_CTL_GO | (reg & BT1_I2C_CTL_ADDR_MASK));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_read(dev->sysmap, BT1_I2C_DO, val);
|
||||
}
|
||||
|
||||
static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct dw_i2c_dev *dev = context;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(dev->sysmap, BT1_I2C_DI, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return regmap_write(dev->sysmap, BT1_I2C_CTL,
|
||||
BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK));
|
||||
}
|
||||
|
||||
static const struct regmap_config bt1_i2c_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.fast_io = true,
|
||||
.reg_read = bt1_i2c_read,
|
||||
.reg_write = bt1_i2c_write,
|
||||
.max_register = DW_IC_COMP_TYPE,
|
||||
};
|
||||
|
||||
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->sysmap = syscon_node_to_regmap(dev->dev->of_node->parent);
|
||||
if (IS_ERR(dev->sysmap))
|
||||
return PTR_ERR(dev->sysmap);
|
||||
|
||||
dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg);
|
||||
return PTR_ERR_OR_ZERO(dev->map);
|
||||
}
|
||||
#else
|
||||
static int bt1_i2c_request_regs(struct dw_i2c_dev *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dw_i2c_get_parent_regmap(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->map = dev_get_regmap(dev->dev->parent, NULL);
|
||||
@@ -127,9 +63,6 @@ static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
|
||||
return dw_i2c_get_parent_regmap(dev);
|
||||
|
||||
switch (dev->flags & MODEL_MASK) {
|
||||
case MODEL_BAIKAL_BT1:
|
||||
ret = bt1_i2c_request_regs(dev);
|
||||
break;
|
||||
case MODEL_WANGXUN_SP:
|
||||
ret = dw_i2c_get_parent_regmap(dev);
|
||||
break;
|
||||
@@ -334,9 +267,8 @@ static void dw_i2c_plat_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id dw_i2c_of_match[] = {
|
||||
{ .compatible = "snps,designware-i2c", },
|
||||
{ .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT },
|
||||
{ .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 },
|
||||
{ .compatible = "mscc,ocelot-i2c" },
|
||||
{ .compatible = "snps,designware-i2c" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
|
||||
|
||||
@@ -21,74 +21,33 @@
|
||||
|
||||
#include "i2c-designware-core.h"
|
||||
|
||||
static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
/* Configure Tx/Rx FIFO threshold levels. */
|
||||
regmap_write(dev->map, DW_IC_TX_TL, 0);
|
||||
regmap_write(dev->map, DW_IC_RX_TL, 0);
|
||||
|
||||
/* Configure the I2C slave. */
|
||||
regmap_write(dev->map, DW_IC_CON, dev->slave_cfg);
|
||||
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_SLAVE_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* i2c_dw_init_slave() - Initialize the DesignWare i2c slave hardware
|
||||
* @dev: device private data
|
||||
*
|
||||
* This function configures and enables the I2C in slave mode.
|
||||
* This function is called during I2C init function, and in case of timeout at
|
||||
* run time.
|
||||
*
|
||||
* Return: 0 on success, or negative errno otherwise.
|
||||
*/
|
||||
static int i2c_dw_init_slave(struct dw_i2c_dev *dev)
|
||||
int i2c_dw_reg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
|
||||
int ret;
|
||||
|
||||
if (!i2c_check_functionality(slave->adapter, I2C_FUNC_SLAVE))
|
||||
return -EOPNOTSUPP;
|
||||
if (dev->slave)
|
||||
return -EBUSY;
|
||||
if (slave->flags & I2C_CLIENT_TEN)
|
||||
return -EAFNOSUPPORT;
|
||||
|
||||
ret = i2c_dw_acquire_lock(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Disable the adapter. */
|
||||
__i2c_dw_disable(dev);
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
dev->slave = slave;
|
||||
i2c_dw_set_mode(dev, DW_IC_SLAVE);
|
||||
|
||||
/* Write SDA hold time if supported */
|
||||
if (dev->sda_hold_time)
|
||||
regmap_write(dev->map, DW_IC_SDA_HOLD, dev->sda_hold_time);
|
||||
|
||||
i2c_dw_configure_fifo_slave(dev);
|
||||
i2c_dw_release_lock(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_dw_reg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
|
||||
|
||||
if (dev->slave)
|
||||
return -EBUSY;
|
||||
if (slave->flags & I2C_CLIENT_TEN)
|
||||
return -EAFNOSUPPORT;
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
/*
|
||||
* Set slave address in the IC_SAR register,
|
||||
* the address to which the DW_apb_i2c responds.
|
||||
*/
|
||||
__i2c_dw_disable_nowait(dev);
|
||||
regmap_write(dev->map, DW_IC_SAR, slave->addr);
|
||||
dev->slave = slave;
|
||||
|
||||
__i2c_dw_enable(dev);
|
||||
|
||||
dev->status = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_dw_unreg_slave(struct i2c_client *slave)
|
||||
int i2c_dw_unreg_slave(struct i2c_client *slave)
|
||||
{
|
||||
struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter);
|
||||
|
||||
@@ -96,6 +55,7 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave)
|
||||
i2c_dw_disable(dev);
|
||||
synchronize_irq(dev->irq);
|
||||
dev->slave = NULL;
|
||||
i2c_dw_set_mode(dev, DW_IC_MASTER);
|
||||
pm_runtime_put_sync_suspend(dev->dev);
|
||||
|
||||
return 0;
|
||||
@@ -152,9 +112,8 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev)
|
||||
* Interrupt service routine. This gets called whenever an I2C slave interrupt
|
||||
* occurs.
|
||||
*/
|
||||
static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
|
||||
irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct dw_i2c_dev *dev = dev_id;
|
||||
unsigned int raw_stat, stat, enabled, tmp;
|
||||
u8 val = 0, slave_activity;
|
||||
|
||||
@@ -217,68 +176,18 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.functionality = i2c_dw_func,
|
||||
.reg_slave = i2c_dw_reg_slave,
|
||||
.unreg_slave = i2c_dw_unreg_slave,
|
||||
};
|
||||
|
||||
void i2c_dw_configure_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
dev->functionality = I2C_FUNC_SLAVE;
|
||||
if (dev->flags & ACCESS_POLLING)
|
||||
return;
|
||||
|
||||
dev->functionality |= I2C_FUNC_SLAVE;
|
||||
|
||||
dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL |
|
||||
DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED;
|
||||
|
||||
dev->mode = DW_IC_SLAVE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_configure_slave);
|
||||
|
||||
int i2c_dw_probe_slave(struct dw_i2c_dev *dev)
|
||||
{
|
||||
struct i2c_adapter *adap = &dev->adapter;
|
||||
int ret;
|
||||
|
||||
dev->init = i2c_dw_init_slave;
|
||||
|
||||
ret = i2c_dw_init_regmap(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_sda_hold(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = i2c_dw_set_fifo_size(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dev->init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
snprintf(adap->name, sizeof(adap->name),
|
||||
"Synopsys DesignWare I2C Slave adapter");
|
||||
adap->retries = 3;
|
||||
adap->algo = &i2c_dw_algo;
|
||||
adap->dev.parent = dev->dev;
|
||||
i2c_set_adapdata(adap, dev);
|
||||
|
||||
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave,
|
||||
IRQF_SHARED, dev_name(dev->dev), dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev->dev, ret,
|
||||
"failure requesting IRQ %i: %d\n",
|
||||
dev->irq, ret);
|
||||
|
||||
ret = i2c_add_numbered_adapter(adap);
|
||||
if (ret)
|
||||
dev_err(dev->dev, "failure adding adapter: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_dw_probe_slave);
|
||||
|
||||
MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -131,6 +131,7 @@
|
||||
#define CHUNK_DATA 256
|
||||
|
||||
#define I2C_PM_TIMEOUT 10 /* ms */
|
||||
#define I2C_PM_LONG_TIMEOUT_MS 1000 /* Avoid dead lock caused by big clock prepare lock */
|
||||
#define I2C_DMA_THRESHOLD 8 /* bytes */
|
||||
|
||||
enum lpi2c_imx_mode {
|
||||
@@ -148,6 +149,11 @@ enum lpi2c_imx_pincfg {
|
||||
FOUR_PIN_PP,
|
||||
};
|
||||
|
||||
struct imx_lpi2c_hwdata {
|
||||
bool need_request_free_irq; /* Needed by irqsteer */
|
||||
bool need_prepare_unprepare_clk; /* Needed by LPCG */
|
||||
};
|
||||
|
||||
struct lpi2c_imx_dma {
|
||||
bool using_pio_mode;
|
||||
u8 rx_cmd_buf_len;
|
||||
@@ -186,6 +192,21 @@ struct lpi2c_imx_struct {
|
||||
bool can_use_dma;
|
||||
struct lpi2c_imx_dma *dma;
|
||||
struct i2c_client *target;
|
||||
int irq;
|
||||
const struct imx_lpi2c_hwdata *hwdata;
|
||||
};
|
||||
|
||||
static const struct imx_lpi2c_hwdata imx7ulp_lpi2c_hwdata = {
|
||||
};
|
||||
|
||||
static const struct imx_lpi2c_hwdata imx8qxp_lpi2c_hwdata = {
|
||||
.need_request_free_irq = true,
|
||||
.need_prepare_unprepare_clk = true,
|
||||
};
|
||||
|
||||
static const struct imx_lpi2c_hwdata imx8qm_lpi2c_hwdata = {
|
||||
.need_request_free_irq = true,
|
||||
.need_prepare_unprepare_clk = true,
|
||||
};
|
||||
|
||||
#define lpi2c_imx_read_msr_poll_timeout(atomic, val, cond) \
|
||||
@@ -1363,7 +1384,9 @@ static const struct i2c_algorithm lpi2c_imx_algo = {
|
||||
};
|
||||
|
||||
static const struct of_device_id lpi2c_imx_of_match[] = {
|
||||
{ .compatible = "fsl,imx7ulp-lpi2c" },
|
||||
{ .compatible = "fsl,imx7ulp-lpi2c", .data = &imx7ulp_lpi2c_hwdata,},
|
||||
{ .compatible = "fsl,imx8qxp-lpi2c", .data = &imx8qxp_lpi2c_hwdata,},
|
||||
{ .compatible = "fsl,imx8qm-lpi2c", .data = &imx8qm_lpi2c_hwdata,},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match);
|
||||
@@ -1374,19 +1397,23 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
dma_addr_t phy_addr;
|
||||
unsigned int temp;
|
||||
int irq, ret;
|
||||
int ret;
|
||||
|
||||
lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
|
||||
if (!lpi2c_imx)
|
||||
return -ENOMEM;
|
||||
|
||||
lpi2c_imx->hwdata = of_device_get_match_data(&pdev->dev);
|
||||
if (!lpi2c_imx->hwdata)
|
||||
return -ENODEV;
|
||||
|
||||
lpi2c_imx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(lpi2c_imx->base))
|
||||
return PTR_ERR(lpi2c_imx->base);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
lpi2c_imx->irq = platform_get_irq(pdev, 0);
|
||||
if (lpi2c_imx->irq < 0)
|
||||
return lpi2c_imx->irq;
|
||||
|
||||
lpi2c_imx->adapter.owner = THIS_MODULE;
|
||||
lpi2c_imx->adapter.algo = &lpi2c_imx_algo;
|
||||
@@ -1406,10 +1433,10 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
ret = devm_request_irq(&pdev->dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
pdev->name, lpi2c_imx);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq);
|
||||
return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", lpi2c_imx->irq);
|
||||
|
||||
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
|
||||
platform_set_drvdata(pdev, lpi2c_imx);
|
||||
@@ -1432,7 +1459,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"can't get I2C peripheral clock rate\n");
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
|
||||
if (lpi2c_imx->hwdata->need_prepare_unprepare_clk)
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_LONG_TIMEOUT_MS);
|
||||
else
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
|
||||
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
@@ -1487,8 +1518,16 @@ static void lpi2c_imx_remove(struct platform_device *pdev)
|
||||
static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
|
||||
bool need_prepare_unprepare_clk = lpi2c_imx->hwdata->need_prepare_unprepare_clk;
|
||||
bool need_request_free_irq = lpi2c_imx->hwdata->need_request_free_irq;
|
||||
|
||||
clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
if (need_request_free_irq)
|
||||
devm_free_irq(dev, lpi2c_imx->irq, lpi2c_imx);
|
||||
|
||||
if (need_prepare_unprepare_clk)
|
||||
clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
else
|
||||
clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
return 0;
|
||||
@@ -1497,13 +1536,32 @@ static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
|
||||
static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
|
||||
bool need_prepare_unprepare_clk = lpi2c_imx->hwdata->need_prepare_unprepare_clk;
|
||||
bool need_request_free_irq = lpi2c_imx->hwdata->need_request_free_irq;
|
||||
int ret;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
|
||||
return ret;
|
||||
if (need_prepare_unprepare_clk) {
|
||||
ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clock %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_request_free_irq) {
|
||||
ret = devm_request_irq(dev, lpi2c_imx->irq, lpi2c_imx_isr, IRQF_NO_SUSPEND,
|
||||
dev_name(dev), lpi2c_imx);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't claim irq %d\n", lpi2c_imx->irq);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
/* spacemit i2c registers */
|
||||
#define SPACEMIT_ICR 0x0 /* Control register */
|
||||
@@ -534,6 +535,7 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *of_node = pdev->dev.of_node;
|
||||
struct spacemit_i2c_dev *i2c;
|
||||
struct reset_control *rst;
|
||||
int ret;
|
||||
|
||||
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
|
||||
@@ -578,6 +580,11 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
|
||||
|
||||
rst = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
|
||||
if (IS_ERR(rst))
|
||||
return dev_err_probe(dev, PTR_ERR(rst),
|
||||
"failed to acquire deasserted reset\n");
|
||||
|
||||
spacemit_i2c_reset(i2c);
|
||||
|
||||
i2c_set_adapdata(&i2c->adapt, i2c);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/string_choices.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
/* Defines what functionality is present. */
|
||||
#define MLXBF_I2C_FUNC_SMBUS_BLOCK \
|
||||
@@ -65,15 +66,13 @@
|
||||
* strongly dependent on the core clock frequency of the SMBus
|
||||
* Master. Default value is set to 400MHz.
|
||||
*/
|
||||
#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000)
|
||||
#define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * HZ_PER_MHZ)
|
||||
/* Reference clock for Bluefield - 156 MHz. */
|
||||
#define MLXBF_I2C_PLL_IN_FREQ 156250000ULL
|
||||
|
||||
/* Constant used to determine the PLL frequency. */
|
||||
#define MLNXBF_I2C_COREPLL_CONST 16384ULL
|
||||
|
||||
#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000ULL
|
||||
|
||||
/* PLL registers. */
|
||||
#define MLXBF_I2C_CORE_PLL_REG1 0x4
|
||||
#define MLXBF_I2C_CORE_PLL_REG2 0x8
|
||||
@@ -325,12 +324,6 @@
|
||||
.name = (str) \
|
||||
}
|
||||
|
||||
enum {
|
||||
MLXBF_I2C_TIMING_100KHZ = 100000,
|
||||
MLXBF_I2C_TIMING_400KHZ = 400000,
|
||||
MLXBF_I2C_TIMING_1000KHZ = 1000000,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLXBF_I2C_F_READ = BIT(0),
|
||||
MLXBF_I2C_F_WRITE = BIT(1),
|
||||
@@ -1083,7 +1076,7 @@ static u32 mlxbf_i2c_get_ticks(struct mlxbf_i2c_priv *priv, u64 nanoseconds,
|
||||
* Frequency
|
||||
*/
|
||||
frequency = priv->frequency;
|
||||
ticks = div_u64(nanoseconds * frequency, MLXBF_I2C_FREQUENCY_1GHZ);
|
||||
ticks = div_u64(nanoseconds * frequency, HZ_PER_GHZ);
|
||||
/*
|
||||
* The number of ticks is rounded down and if minimum is equal to 1
|
||||
* then add one tick.
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define I2C_RS_TRANSFER (1 << 4)
|
||||
#define I2C_ARB_LOST (1 << 3)
|
||||
@@ -685,7 +686,7 @@ static int mtk_i2c_get_clk_div_restri(struct mtk_i2c *i2c,
|
||||
* Check and Calculate i2c ac-timing
|
||||
*
|
||||
* Hardware design:
|
||||
* sample_ns = (1000000000 * (sample_cnt + 1)) / clk_src
|
||||
* sample_ns = (HZ_PER_GHZ * (sample_cnt + 1)) / clk_src
|
||||
* xxx_cnt_div = spec->min_xxx_ns / sample_ns
|
||||
*
|
||||
* Sample_ns is rounded down for xxx_cnt_div would be greater
|
||||
@@ -701,9 +702,8 @@ static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
|
||||
{
|
||||
const struct i2c_spec_values *spec;
|
||||
unsigned int su_sta_cnt, low_cnt, high_cnt, max_step_cnt;
|
||||
unsigned int sda_max, sda_min, clk_ns, max_sta_cnt = 0x3f;
|
||||
unsigned int sample_ns = div_u64(1000000000ULL * (sample_cnt + 1),
|
||||
clk_src);
|
||||
unsigned int sda_max, sda_min, max_sta_cnt = 0x3f;
|
||||
unsigned int clk_ns, sample_ns;
|
||||
|
||||
if (!i2c->dev_comp->timing_adjust)
|
||||
return 0;
|
||||
@@ -713,8 +713,9 @@ static int mtk_i2c_check_ac_timing(struct mtk_i2c *i2c,
|
||||
|
||||
spec = mtk_i2c_get_spec(check_speed);
|
||||
|
||||
sample_ns = div_u64(1ULL * HZ_PER_GHZ * (sample_cnt + 1), clk_src);
|
||||
if (i2c->dev_comp->ltiming_adjust)
|
||||
clk_ns = 1000000000 / clk_src;
|
||||
clk_ns = HZ_PER_GHZ / clk_src;
|
||||
else
|
||||
clk_ns = sample_ns / 2;
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define DRIVER_NAME "nmk-i2c"
|
||||
|
||||
@@ -419,10 +420,10 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv)
|
||||
* modes are 250ns, 100ns, 10ns respectively.
|
||||
*
|
||||
* As the time for one cycle T in nanoseconds is
|
||||
* T = (1/f) * 1000000000 =>
|
||||
* slsu = cycles / (1000000000 / f) + 1
|
||||
* T = (1/f) * HZ_PER_GHZ =>
|
||||
* slsu = cycles / (HZ_PER_GHZ / f) + 1
|
||||
*/
|
||||
ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
|
||||
ns = DIV_ROUND_UP(HZ_PER_GHZ, i2c_clk);
|
||||
switch (priv->sm) {
|
||||
case I2C_FREQ_MODE_FAST:
|
||||
case I2C_FREQ_MODE_FAST_PLUS:
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/units.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
@@ -896,13 +897,12 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
|
||||
|
||||
clk_disable(i2c->pclk);
|
||||
|
||||
t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
|
||||
t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
|
||||
clk_rate);
|
||||
t_low_ns = div_u64(8ULL * HZ_PER_GHZ * (calc.div_low + 1), clk_rate);
|
||||
t_high_ns = div_u64(8ULL * HZ_PER_GHZ * (calc.div_high + 1), clk_rate);
|
||||
dev_dbg(i2c->dev,
|
||||
"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
|
||||
clk_rate / 1000,
|
||||
1000000000 / t->bus_freq_hz,
|
||||
"CLK %lukHz, Req %luns, Act low %lluns high %lluns\n",
|
||||
clk_rate / HZ_PER_KHZ,
|
||||
HZ_PER_GHZ / t->bus_freq_hz,
|
||||
t_low_ns, t_high_ns);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
|
||||
|
||||
static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
|
||||
{
|
||||
struct rtl9300_i2c_drv_data *drv_data;
|
||||
const struct rtl9300_i2c_drv_data *drv_data;
|
||||
int ret;
|
||||
|
||||
if (i2c->sda_num == chan->sda_num)
|
||||
@@ -139,7 +139,7 @@ static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
|
||||
drv_data = device_get_match_data(i2c->dev);
|
||||
ret = drv_data->select_scl(i2c, i2c->scl_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -371,8 +371,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rtl9300_i2c *i2c;
|
||||
struct fwnode_handle *child;
|
||||
struct rtl9300_i2c_drv_data *drv_data;
|
||||
const struct rtl9300_i2c_drv_data *drv_data;
|
||||
struct reg_field fields[F_NUM_FIELDS];
|
||||
u32 clock_freq, scl_num, sda_num;
|
||||
int ret, i = 0;
|
||||
@@ -399,7 +398,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, i2c);
|
||||
|
||||
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
|
||||
drv_data = device_get_match_data(i2c->dev);
|
||||
if (device_get_child_node_count(dev) > drv_data->max_nchan)
|
||||
return dev_err_probe(dev, -EINVAL, "Too many channels\n");
|
||||
|
||||
@@ -415,15 +414,15 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
i = 0;
|
||||
device_for_each_child_node(dev, child) {
|
||||
for_each_child_of_node_scoped(dev->of_node, child) {
|
||||
struct rtl9300_i2c_chan *chan = &i2c->chans[i];
|
||||
struct i2c_adapter *adap = &chan->adap;
|
||||
|
||||
ret = fwnode_property_read_u32(child, "reg", &sda_num);
|
||||
ret = of_property_read_u32(child, "reg", &sda_num);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq);
|
||||
ret = of_property_read_u32(child, "clock-frequency", &clock_freq);
|
||||
if (ret)
|
||||
clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
|
||||
|
||||
@@ -449,7 +448,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
|
||||
adap->retries = 3;
|
||||
adap->dev.parent = dev;
|
||||
i2c_set_adapdata(adap, chan);
|
||||
adap->dev.of_node = to_of_node(child);
|
||||
adap->dev.of_node = child;
|
||||
snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num);
|
||||
i++;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
/* SSC registers */
|
||||
#define SSC_BRG 0x000
|
||||
@@ -285,7 +286,7 @@ static void st_i2c_hw_config(struct st_i2c_dev *i2c_dev)
|
||||
writel_relaxed(val, i2c_dev->base + SSC_CTL);
|
||||
|
||||
rate = clk_get_rate(i2c_dev->clk);
|
||||
ns_per_clk = 1000000000 / rate;
|
||||
ns_per_clk = HZ_PER_GHZ / rate;
|
||||
|
||||
/* Baudrate */
|
||||
val = rate / (2 * t->rate);
|
||||
|
||||
@@ -18,9 +18,10 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define WAIT_PCLK(n, rate) \
|
||||
ndelay(DIV_ROUND_UP(DIV_ROUND_UP(1000000000, rate), n) + 10)
|
||||
ndelay(DIV_ROUND_UP(DIV_ROUND_UP(HZ_PER_GHZ, rate), n) + 10)
|
||||
|
||||
/* I2C register address definitions */
|
||||
#define SYNQUACER_I2C_REG_BSR (0x00 << 2) // Bus Status
|
||||
|
||||
@@ -264,7 +264,6 @@ struct tegra_i2c_hw_feature {
|
||||
* @div_clk: clock reference for div clock of I2C controller
|
||||
* @clocks: array of I2C controller clocks
|
||||
* @nclocks: number of clocks in the array
|
||||
* @rst: reset control for the I2C controller
|
||||
* @base: ioremapped registers cookie
|
||||
* @base_phys: physical base address of the I2C controller
|
||||
* @cont_id: I2C controller ID, used for packet header
|
||||
@@ -293,7 +292,6 @@ struct tegra_i2c_dev {
|
||||
struct i2c_adapter adapter;
|
||||
|
||||
const struct tegra_i2c_hw_feature *hw;
|
||||
struct reset_control *rst;
|
||||
unsigned int cont_id;
|
||||
unsigned int irq;
|
||||
|
||||
|
||||
@@ -25,9 +25,12 @@
|
||||
#define MICROHZ_PER_HZ 1000000UL
|
||||
#define MILLIHZ_PER_HZ 1000UL
|
||||
|
||||
/* Hz based multipliers */
|
||||
#define HZ_PER_KHZ 1000UL
|
||||
#define HZ_PER_MHZ 1000000UL
|
||||
#define HZ_PER_GHZ 1000000000UL
|
||||
|
||||
/* kHz based multipliers */
|
||||
#define KHZ_PER_MHZ 1000UL
|
||||
#define KHZ_PER_GHZ 1000000UL
|
||||
|
||||
|
||||
Reference in New Issue
Block a user