i2c-for-7.0-rc1

- core: cleaner fwnode usage
 - tegra: timing improvements and Tegra264 support
 - lpi2c: fix SMBus block read NACK after byte count
 - 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
 
 at24 updates for v7.0-rc1
 
 - add a set of new compatibles to DT bindings
 - use dev_err_probe() consistently in the driver
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmmRmeMACgkQFA3kzBSg
 KbbLLA//XoOh4GtD6LA7Uh9GNgeTcLNJf08UehPby+8w6urx0yieGk0YVggmJtqH
 Uav8jDxyVGMZsGHIksnF/a5olFzvCfy6rUQEYHL9I+EWaufLCmQRk8lcjWUv6Z+s
 6q50r8WXIFZTc+h4V0chHf4L5TLjJNvV+TBHm3maAxhJy+UloF3kdS6QlczAmbD9
 gigilvZrpkqRC4FPPLdqM8v7losA9TRQDCYAyghcGf7AAxj+FFjpWPSSLEa9eb7d
 QszFS3+d3H5EfJ4ONs818XSxrQNJr/gdlgBAdENskJPfTwcgdTZV8ySRxRC/BnFq
 Z1kostoABrhHYvK72Z+nOaLD+sFwPHM/XIUHXuMsQNkr4yj+R+aDUs4JB4BV8LX1
 Fc03u8r9vSUszpcIgk38t5gTdXLt6eybertv5HJ9WDHvZq1TCMw97Lk7zdWN6Q9A
 pmG4RNZnpG/OMrCkzhX/gA0nOBZMWOOplKNV6uhy+k78g6pSy772iBAY5YkW0VFZ
 E+GYHeFlEsSPh37zbjWcfZl3r0eEk3BY/19t4drxS9WknUcu8dY3QQPC8TXOYMwA
 gx42HudGD4Yq2lbFekiAcz0rx5p399ihRPrjKm8E8S8TR8Slrk6tAh2ZHq/TMi9R
 arELjn6EMMuAjRIlsd0LYJn4suGILPFiLQXgRArfGu2zGCmM8rQ=
 =gCyg
 -----END PGP SIGNATURE-----

Merge tag 'i2c-for-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 - core: cleaner fwnode usage
 - tegra: timing improvements and Tegra264 support
 - lpi2c: fix SMBus block read NACK after byte count
 - amd-mp2, designware, mlxbf, rtl9300, spacemit, tegra: cleanups
 - designware:
    - use a dedicated algorithm for AMD Navi
    - replace magic numbers with named constants
    - replace min_t() with min() to avoid u8 truncation
    - 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
 - at24 i2c eeprom:
    - add a set of new compatibles to DT bindings
    - use dev_err_probe() consistently in the driver

* tag 'i2c-for-7.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (46 commits)
  i2c: imx-lpi2c: fix SMBus block read NACK after byte count
  i2c: designware: Remove an unnecessary condition
  i2c: designware: Enable mode swapping
  i2c: designware: Combine the init functions
  i2c: designware: Combine some of the common functions
  i2c: designware: Use device_is_compatible() instead of custom approach
  dt-bindings: eeprom: at24: Add compatible for Puya P24C128F
  drivers/i2c/busses: use min() instead of min_t()
  i2c: imx-lpi2c: Add runtime PM support for IRQ and clock management on i.MX8QXP/8QM
  i2c: amd-mp2: clean up amd_mp2_find_device()
  i2c: designware: Replace magic numbers with named constants
  i2c: rtl9300: use of instead of fwnode
  i2c: rtl9300: remove const cast
  i2c: tegra: remove unused rst
  i2c: designware: Remove not-going-to-be-supported code for Baikal SoC
  i2c: spacemit: drop useless spaces
  i2c: mlxbf: Use HZ_PER_KHZ in the driver
  i2c: mlxbf: Remove unused bus speed definitions
  i2c: core: Use dev_fwnode()
  i2c: core: Replace custom implementation of device_match_fwnode()
  ...
This commit is contained in:
Linus Torvalds 2026-02-15 08:29:26 -08:00
commit bb7a3fc2c9
26 changed files with 783 additions and 542 deletions

View file

@ -116,6 +116,7 @@ properties:
- const: atmel,24c02
- items:
- enum:
- belling,bl24c04a
- giantec,gt24c04a
- onnn,cat24c04
- onnn,cat24c05
@ -124,6 +125,7 @@ properties:
- items:
- enum:
- belling,bl24c16a
- belling,bl24c16f
- renesas,r1ex24016
- const: atmel,24c16
- items:
@ -132,6 +134,7 @@ properties:
- items:
- enum:
- belling,bl24s64
- giantec,gt24p64a
- onnn,n24s64b
- puya,p24c64f
- const: atmel,24c64
@ -139,6 +142,7 @@ properties:
- enum:
- giantec,gt24p128e
- giantec,gt24p128f
- puya,p24c128f
- renesas,r1ex24128
- samsung,s524ad0xd1
- const: atmel,24c128

View file

@ -26,6 +26,7 @@ properties:
- microchip,sam9x60-i2c
- items:
- enum:
- microchip,lan9691-i2c
- microchip,sama7d65-i2c
- microchip,sama7g5-i2c
- microchip,sam9x7-i2c

View file

@ -54,6 +54,7 @@ properties:
- enum:
- mediatek,mt6878-i2c
- mediatek,mt6991-i2c
- mediatek,mt8189-i2c
- mediatek,mt8196-i2c
- const: mediatek,mt8188-i2c
- items:

View file

@ -41,6 +41,9 @@ properties:
default: 400000
maximum: 3300000
resets:
maxItems: 1
required:
- compatible
- reg

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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");

View file

@ -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);

View file

@ -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");

View file

@ -5,6 +5,7 @@
* Copyright 2016 Freescale Semiconductor, Inc.
*/
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@ -90,6 +91,7 @@
#define MRDR_RXEMPTY BIT(14)
#define MDER_TDDE BIT(0)
#define MDER_RDDE BIT(1)
#define MSR_RDF_ASSERTED(x) FIELD_GET(MSR_RDF, (x))
#define SCR_SEN BIT(0)
#define SCR_RST BIT(1)
@ -131,6 +133,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 +151,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 +194,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) \
@ -461,7 +484,7 @@ static bool lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atom
static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned int blocklen, remaining;
unsigned int remaining;
unsigned int temp, data;
do {
@ -472,15 +495,6 @@ static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomi
lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
} while (1);
/*
* First byte is the length of remaining packet in the SMBus block
* data read. Add it to msgs->len.
*/
if (lpi2c_imx->block_data) {
blocklen = lpi2c_imx->rx_buf[0];
lpi2c_imx->msglen += blocklen;
}
remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
if (!remaining) {
@ -493,12 +507,7 @@ static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomi
lpi2c_imx_set_rx_watermark(lpi2c_imx);
/* multiple receive commands */
if (lpi2c_imx->block_data) {
lpi2c_imx->block_data = 0;
temp = remaining;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
} else if (!(lpi2c_imx->delivered & 0xff)) {
if (!(lpi2c_imx->delivered & 0xff)) {
temp = (remaining > CHUNK_DATA ? CHUNK_DATA : remaining) - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
@ -536,18 +545,77 @@ static int lpi2c_imx_write_atomic(struct lpi2c_imx_struct *lpi2c_imx,
return err;
}
static void lpi2c_imx_read_init(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
static unsigned int lpi2c_SMBus_block_read_length_byte(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int temp;
unsigned int data;
data = readl(lpi2c_imx->base + LPI2C_MRDR);
lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff;
return data;
}
static int lpi2c_imx_read_init(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
unsigned int temp, val, block_len;
int ret;
lpi2c_imx->rx_buf = msgs->buf;
lpi2c_imx->block_data = msgs->flags & I2C_M_RECV_LEN;
lpi2c_imx_set_rx_watermark(lpi2c_imx);
temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
if (!lpi2c_imx->block_data) {
temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
} else {
/*
* The LPI2C controller automatically sends a NACK after the last byte of a
* receive command, unless the next command in MTDR is also a receive command.
* If MTDR is empty when a receive completes, a NACK is sent by default.
*
* To comply with the SMBus block read spec, we start with a 2-byte read:
* The first byte in RXFIFO is the block length. Once this byte arrives, the
* controller immediately updates MTDR with the next read command, ensuring
* continuous ACK instead of NACK.
*
* The second byte is the first block data byte. Therefore, the subsequent
* read command should request (block_len - 1) bytes, since one data byte
* has already been read.
*/
writel((RECV_DATA << 8) | 0x01, lpi2c_imx->base + LPI2C_MTDR);
ret = readl_poll_timeout(lpi2c_imx->base + LPI2C_MSR, val,
MSR_RDF_ASSERTED(val), 1, 1000);
if (ret) {
dev_err(&lpi2c_imx->adapter.dev, "SMBus read count failed %d\n", ret);
return ret;
}
/* Read block length byte and confirm this SMBus transfer meets protocol */
block_len = lpi2c_SMBus_block_read_length_byte(lpi2c_imx);
if (block_len == 0 || block_len > I2C_SMBUS_BLOCK_MAX) {
dev_err(&lpi2c_imx->adapter.dev, "Invalid SMBus block read length\n");
return -EPROTO;
}
/*
* When block_len shows more bytes need to be read, update second read command to
* keep MTDR non-empty and ensuring continuous ACKs. Only update command register
* here. All block bytes will be read out at IRQ handler or lpi2c_imx_read_atomic()
* function.
*/
if (block_len > 1)
writel((RECV_DATA << 8) | (block_len - 2), lpi2c_imx->base + LPI2C_MTDR);
lpi2c_imx->msglen += block_len;
msgs->len += block_len;
}
return 0;
}
static bool lpi2c_imx_read_chunk_atomic(struct lpi2c_imx_struct *lpi2c_imx)
@ -592,6 +660,10 @@ static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg)
if (!lpi2c_imx->can_use_dma)
return false;
/* DMA is not suitable for SMBus block read */
if (msg->flags & I2C_M_RECV_LEN)
return false;
/*
* A system-wide suspend or resume transition is in progress. LPI2C should use PIO to
* transfer data to avoid issue caused by no ready DMA HW resource.
@ -609,10 +681,14 @@ static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg)
static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msg)
{
int ret;
reinit_completion(&lpi2c_imx->complete);
if (msg->flags & I2C_M_RD) {
lpi2c_imx_read_init(lpi2c_imx, msg);
ret = lpi2c_imx_read_init(lpi2c_imx, msg);
if (ret)
return ret;
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
} else {
lpi2c_imx_write(lpi2c_imx, msg);
@ -624,8 +700,12 @@ static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx,
static int lpi2c_imx_pio_xfer_atomic(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msg)
{
int ret;
if (msg->flags & I2C_M_RD) {
lpi2c_imx_read_init(lpi2c_imx, msg);
ret = lpi2c_imx_read_init(lpi2c_imx, msg);
if (ret)
return ret;
return lpi2c_imx_read_atomic(lpi2c_imx, msg);
}
@ -1370,7 +1450,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);
@ -1381,19 +1463,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;
@ -1413,10 +1499,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);
@ -1439,7 +1525,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);
@ -1494,8 +1584,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;
@ -1504,13 +1602,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;

View file

@ -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);

View file

@ -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.

View file

@ -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;

View file

@ -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:

View file

@ -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);
}

View file

@ -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++;

View file

@ -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);

View file

@ -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

View file

@ -85,6 +85,7 @@
#define PACKET_HEADER0_PROTOCOL GENMASK(7, 4)
#define PACKET_HEADER0_PROTOCOL_I2C 1
#define I2C_HEADER_HS_MODE BIT(22)
#define I2C_HEADER_CONT_ON_NAK BIT(21)
#define I2C_HEADER_READ BIT(19)
#define I2C_HEADER_10BIT_ADDR BIT(18)
@ -136,6 +137,14 @@
#define I2C_MASTER_RESET_CNTRL 0x0a8
#define I2C_SW_MUTEX 0x0ec
#define I2C_SW_MUTEX_REQUEST GENMASK(3, 0)
#define I2C_SW_MUTEX_GRANT GENMASK(7, 4)
#define I2C_SW_MUTEX_ID_CCPLEX 9
/* SW mutex acquire timeout value in microseconds. */
#define I2C_SW_MUTEX_TIMEOUT_US (25 * USEC_PER_MSEC)
/* configuration load timeout in microseconds */
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
@ -196,16 +205,24 @@ enum msg_end_type {
* @has_apb_dma: Support of APBDMA on corresponding Tegra chip.
* @tlow_std_mode: Low period of the clock in standard mode.
* @thigh_std_mode: High period of the clock in standard mode.
* @tlow_fast_fastplus_mode: Low period of the clock in fast/fast-plus modes.
* @thigh_fast_fastplus_mode: High period of the clock in fast/fast-plus modes.
* @tlow_fast_mode: Low period of the clock in fast mode.
* @thigh_fast_mode: High period of the clock in fast mode.
* @tlow_fastplus_mode: Low period of the clock in fast-plus mode.
* @thigh_fastplus_mode: High period of the clock in fast-plus mode.
* @tlow_hs_mode: Low period of the clock in HS mode.
* @thigh_hs_mode: High period of the clock in HS mode.
* @setup_hold_time_std_mode: Setup and hold time for start and stop conditions
* in standard mode.
* @setup_hold_time_fast_fast_plus_mode: Setup and hold time for start and stop
* conditions in fast/fast-plus modes.
* @setup_hold_time_fast_mode: Setup and hold time for start and stop
* conditions in fast mode.
* @setup_hold_time_fastplus_mode: Setup and hold time for start and stop
* conditions in fast-plus mode.
* @setup_hold_time_hs_mode: Setup and hold time for start and stop conditions
* in HS mode.
* @has_interface_timing_reg: Has interface timing register to program the tuned
* timing settings.
* @enable_hs_mode_support: Enable support for high speed (HS) mode transfers.
* @has_mutex: Has mutex register for mutual exclusion with other firmwares or VMs.
*/
struct tegra_i2c_hw_feature {
bool has_continue_xfer_support;
@ -224,12 +241,19 @@ struct tegra_i2c_hw_feature {
bool has_apb_dma;
u32 tlow_std_mode;
u32 thigh_std_mode;
u32 tlow_fast_fastplus_mode;
u32 thigh_fast_fastplus_mode;
u32 tlow_fast_mode;
u32 thigh_fast_mode;
u32 tlow_fastplus_mode;
u32 thigh_fastplus_mode;
u32 tlow_hs_mode;
u32 thigh_hs_mode;
u32 setup_hold_time_std_mode;
u32 setup_hold_time_fast_fast_plus_mode;
u32 setup_hold_time_fast_mode;
u32 setup_hold_time_fastplus_mode;
u32 setup_hold_time_hs_mode;
bool has_interface_timing_reg;
bool enable_hs_mode_support;
bool has_mutex;
};
/**
@ -240,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
@ -269,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;
@ -374,6 +396,76 @@ static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data,
readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len);
}
static bool tegra_i2c_mutex_acquired(struct tegra_i2c_dev *i2c_dev)
{
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
u32 val, id;
val = readl(i2c_dev->base + reg);
id = FIELD_GET(I2C_SW_MUTEX_GRANT, val);
return id == I2C_SW_MUTEX_ID_CCPLEX;
}
static bool tegra_i2c_mutex_trylock(struct tegra_i2c_dev *i2c_dev)
{
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
u32 val, id;
val = readl(i2c_dev->base + reg);
id = FIELD_GET(I2C_SW_MUTEX_GRANT, val);
if (id != 0 && id != I2C_SW_MUTEX_ID_CCPLEX)
return false;
val = FIELD_PREP(I2C_SW_MUTEX_REQUEST, I2C_SW_MUTEX_ID_CCPLEX);
writel(val, i2c_dev->base + reg);
return tegra_i2c_mutex_acquired(i2c_dev);
}
static int tegra_i2c_mutex_lock(struct tegra_i2c_dev *i2c_dev)
{
bool locked;
int ret;
if (!i2c_dev->hw->has_mutex)
return 0;
if (i2c_dev->atomic_mode)
ret = read_poll_timeout_atomic(tegra_i2c_mutex_trylock, locked, locked,
USEC_PER_MSEC, I2C_SW_MUTEX_TIMEOUT_US,
false, i2c_dev);
else
ret = read_poll_timeout(tegra_i2c_mutex_trylock, locked, locked, USEC_PER_MSEC,
I2C_SW_MUTEX_TIMEOUT_US, false, i2c_dev);
if (ret)
dev_warn(i2c_dev->dev, "failed to acquire mutex\n");
return ret;
}
static int tegra_i2c_mutex_unlock(struct tegra_i2c_dev *i2c_dev)
{
unsigned int reg = tegra_i2c_reg_addr(i2c_dev, I2C_SW_MUTEX);
u32 val, id;
if (!i2c_dev->hw->has_mutex)
return 0;
val = readl(i2c_dev->base + reg);
id = FIELD_GET(I2C_SW_MUTEX_GRANT, val);
if (id && id != I2C_SW_MUTEX_ID_CCPLEX) {
dev_warn(i2c_dev->dev, "unable to unlock mutex, mutex is owned by: %u\n", id);
return -EPERM;
}
writel(0, i2c_dev->base + reg);
return 0;
}
static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask)
{
u32 int_mask;
@ -449,6 +541,11 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
if (IS_VI(i2c_dev))
return 0;
if (!of_property_present(i2c_dev->dev->of_node, "dmas")) {
dev_dbg(i2c_dev->dev, "DMA not available, falling back to PIO\n");
return 0;
}
if (i2c_dev->hw->has_apb_dma) {
if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
dev_dbg(i2c_dev->dev, "APB DMA support not enabled\n");
@ -634,6 +731,7 @@ static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev)
static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
{
u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode;
u32 max_bus_freq_hz;
struct i2c_timings *t = &i2c_dev->timings;
int err;
@ -672,25 +770,40 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (IS_VI(i2c_dev))
tegra_i2c_vi_init(i2c_dev);
switch (t->bus_freq_hz) {
case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ:
default:
tlow = i2c_dev->hw->tlow_fast_fastplus_mode;
thigh = i2c_dev->hw->thigh_fast_fastplus_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode;
if (i2c_dev->hw->enable_hs_mode_support)
max_bus_freq_hz = I2C_MAX_HIGH_SPEED_MODE_FREQ;
else
max_bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ;
if (t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ)
non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
else
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
break;
if (WARN_ON(t->bus_freq_hz > max_bus_freq_hz))
t->bus_freq_hz = max_bus_freq_hz;
case 0 ... I2C_MAX_STANDARD_MODE_FREQ:
if (t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) {
tlow = i2c_dev->hw->tlow_std_mode;
thigh = i2c_dev->hw->thigh_std_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_std_mode;
non_hs_mode = i2c_dev->hw->clk_divisor_std_mode;
break;
} else if (t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ) {
tlow = i2c_dev->hw->tlow_fast_mode;
thigh = i2c_dev->hw->thigh_fast_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_fast_mode;
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
} else if (t->bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) {
tlow = i2c_dev->hw->tlow_fastplus_mode;
thigh = i2c_dev->hw->thigh_fastplus_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_fastplus_mode;
non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode;
} else {
/*
* When using HS mode, i.e. when the bus frequency is greater than fast plus mode,
* the non-hs timing registers will be used for sending the master code byte for
* transition to HS mode. Configure the non-hs timing registers for Fast Mode to
* send the master code byte at 400kHz.
*/
tlow = i2c_dev->hw->tlow_fast_mode;
thigh = i2c_dev->hw->thigh_fast_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_fast_mode;
non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode;
}
/* make sure clock divisor programmed correctly */
@ -712,6 +825,18 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->hw->has_interface_timing_reg && tsu_thd)
i2c_writel(i2c_dev, tsu_thd, I2C_INTERFACE_TIMING_1);
/* Write HS mode registers. These will get used only for HS mode*/
if (i2c_dev->hw->enable_hs_mode_support) {
tlow = i2c_dev->hw->tlow_hs_mode;
thigh = i2c_dev->hw->thigh_hs_mode;
tsu_thd = i2c_dev->hw->setup_hold_time_hs_mode;
val = FIELD_PREP(I2C_HS_INTERFACE_TIMING_THIGH, thigh) |
FIELD_PREP(I2C_HS_INTERFACE_TIMING_TLOW, tlow);
i2c_writel(i2c_dev, val, I2C_HS_INTERFACE_TIMING_0);
i2c_writel(i2c_dev, tsu_thd, I2C_HS_INTERFACE_TIMING_1);
}
clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1);
err = clk_set_rate(i2c_dev->div_clk,
@ -1209,6 +1334,9 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev,
if (msg->flags & I2C_M_RD)
packet_header |= I2C_HEADER_READ;
if (i2c_dev->timings.bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ)
packet_header |= I2C_HEADER_HS_MODE;
if (i2c_dev->dma_mode && !i2c_dev->msg_read)
*dma_buf++ = packet_header;
else
@ -1393,6 +1521,10 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
return ret;
}
ret = tegra_i2c_mutex_lock(i2c_dev);
if (ret)
return ret;
for (i = 0; i < num; i++) {
enum msg_end_type end_type = MSG_END_STOP;
@ -1422,6 +1554,7 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
break;
}
ret = tegra_i2c_mutex_unlock(i2c_dev);
pm_runtime_put(i2c_dev->dev);
return ret ?: i;
@ -1491,12 +1624,17 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0x0,
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_fast_mode = 0x0,
.setup_hold_time_fastplus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
@ -1516,12 +1654,17 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0x0,
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_fast_mode = 0x0,
.setup_hold_time_fastplus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
@ -1541,12 +1684,17 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0x0,
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_fast_mode = 0x0,
.setup_hold_time_fastplus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = false,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
@ -1566,12 +1714,17 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0x0,
.setup_hold_time_fast_fast_plus_mode = 0x0,
.setup_hold_time_fast_mode = 0x0,
.setup_hold_time_fastplus_mode = 0x0,
.setup_hold_time_hs_mode = 0x0,
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
@ -1591,12 +1744,17 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0,
.setup_hold_time_fast_fast_plus_mode = 0,
.setup_hold_time_fast_mode = 0,
.setup_hold_time_fastplus_mode = 0,
.setup_hold_time_hs_mode = 0,
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
@ -1616,12 +1774,17 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_apb_dma = false,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x3,
.tlow_fast_fastplus_mode = 0x4,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x2,
.setup_hold_time_std_mode = 0,
.setup_hold_time_fast_fast_plus_mode = 0,
.setup_hold_time_fast_mode = 0,
.setup_hold_time_fastplus_mode = 0,
.setup_hold_time_hs_mode = 0,
.has_interface_timing_reg = true,
.enable_hs_mode_support = false,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
@ -1641,21 +1804,28 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
.tlow_fast_fastplus_mode = 0x2,
.thigh_fast_fastplus_mode = 0x2,
.tlow_fast_mode = 0x2,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x2,
.thigh_fastplus_mode = 0x2,
.tlow_hs_mode = 0x8,
.thigh_hs_mode = 0x3,
.setup_hold_time_std_mode = 0x08080808,
.setup_hold_time_fast_fast_plus_mode = 0x02020202,
.setup_hold_time_fast_mode = 0x02020202,
.setup_hold_time_fastplus_mode = 0x02020202,
.setup_hold_time_hs_mode = 0x090909,
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = false,
};
static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.clk_divisor_hs_mode = 7,
.clk_divisor_hs_mode = 9,
.clk_divisor_std_mode = 0x7a,
.clk_divisor_fast_mode = 0x40,
.clk_divisor_fast_plus_mode = 0x19,
.clk_divisor_fast_plus_mode = 0x14,
.has_config_load_reg = true,
.has_multi_master_mode = true,
.has_slcg_override_reg = true,
@ -1666,15 +1836,55 @@ static const struct tegra_i2c_hw_feature tegra256_i2c_hw = {
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
.tlow_fast_fastplus_mode = 0x3,
.thigh_fast_fastplus_mode = 0x3,
.tlow_fast_mode = 0x4,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x4,
.thigh_fastplus_mode = 0x4,
.tlow_hs_mode = 0x3,
.thigh_hs_mode = 0x2,
.setup_hold_time_std_mode = 0x08080808,
.setup_hold_time_fast_fast_plus_mode = 0x02020202,
.setup_hold_time_fast_mode = 0x04010101,
.setup_hold_time_fastplus_mode = 0x04020202,
.setup_hold_time_hs_mode = 0x030303,
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = true,
};
static const struct tegra_i2c_hw_feature tegra264_i2c_hw = {
.has_continue_xfer_support = true,
.has_per_pkt_xfer_complete_irq = true,
.clk_divisor_hs_mode = 1,
.clk_divisor_std_mode = 0x1d,
.clk_divisor_fast_mode = 0x15,
.clk_divisor_fast_plus_mode = 0x8,
.has_config_load_reg = true,
.has_multi_master_mode = true,
.has_slcg_override_reg = true,
.has_mst_fifo = true,
.has_mst_reset = true,
.quirks = &tegra194_i2c_quirks,
.supports_bus_clear = true,
.has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
.tlow_fast_mode = 0x2,
.thigh_fast_mode = 0x2,
.tlow_fastplus_mode = 0x2,
.thigh_fastplus_mode = 0x2,
.tlow_hs_mode = 0x4,
.thigh_hs_mode = 0x2,
.setup_hold_time_std_mode = 0x08080808,
.setup_hold_time_fast_mode = 0x02020202,
.setup_hold_time_fastplus_mode = 0x02020202,
.setup_hold_time_hs_mode = 0x090909,
.has_interface_timing_reg = true,
.enable_hs_mode_support = true,
.has_mutex = true,
};
static const struct of_device_id tegra_i2c_of_match[] = {
{ .compatible = "nvidia,tegra264-i2c", .data = &tegra264_i2c_hw, },
{ .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, },
{ .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, },
{ .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, },

View file

@ -1090,7 +1090,7 @@ struct i2c_client *i2c_find_device_by_fwnode(struct fwnode_handle *fwnode)
struct i2c_client *client;
struct device *dev;
if (!fwnode)
if (IS_ERR_OR_NULL(fwnode))
return NULL;
dev = bus_find_device_by_fwnode(&i2c_bus_type, fwnode);
@ -1476,7 +1476,7 @@ static int i2c_setup_host_notify_irq_domain(struct i2c_adapter *adap)
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY))
return 0;
domain = irq_domain_create_linear(adap->dev.parent->fwnode,
domain = irq_domain_create_linear(dev_fwnode(adap->dev.parent),
I2C_ADDR_7BITS_COUNT,
&i2c_host_notify_irq_ops, adap);
if (!domain)
@ -1852,10 +1852,10 @@ EXPORT_SYMBOL_GPL(devm_i2c_add_adapter);
static int i2c_dev_or_parent_fwnode_match(struct device *dev, const void *data)
{
if (dev_fwnode(dev) == data)
if (device_match_fwnode(dev, data))
return 1;
if (dev->parent && dev_fwnode(dev->parent) == data)
if (dev->parent && device_match_fwnode(dev->parent, data))
return 1;
return 0;
@ -1875,7 +1875,7 @@ struct i2c_adapter *i2c_find_adapter_by_fwnode(struct fwnode_handle *fwnode)
struct i2c_adapter *adapter;
struct device *dev;
if (!fwnode)
if (IS_ERR_OR_NULL(fwnode))
return NULL;
dev = bus_find_device(&i2c_bus_type, NULL, fwnode,

View file

@ -657,10 +657,8 @@ static int at24_probe(struct i2c_client *client)
if (!i2c_fn_i2c && !i2c_fn_block)
page_size = 1;
if (!page_size) {
dev_err(dev, "page_size must not be 0!\n");
return -EINVAL;
}
if (!page_size)
return dev_err_probe(dev, -EINVAL, "page_size must not be 0!\n");
if (!is_power_of_2(page_size))
dev_warn(dev, "page_size looks suspicious (no power of 2)!\n");
@ -674,11 +672,9 @@ static int at24_probe(struct i2c_client *client)
(flags & AT24_FLAG_ADDR16) ? 65536 : 256);
}
if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) {
dev_err(dev,
"invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
return -EINVAL;
}
if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC))
return dev_err_probe(dev, -EINVAL,
"invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
regmap_config.val_bits = 8;
regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8;
@ -759,10 +755,8 @@ static int at24_probe(struct i2c_client *client)
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
err = regulator_enable(at24->vcc_reg);
if (err) {
dev_err(dev, "Failed to enable vcc regulator\n");
return err;
}
if (err)
return dev_err_probe(dev, err, "Failed to enable vcc regulator\n");
pm_runtime_set_active(dev);
}

View file

@ -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