i2c-for-6.17-rc1

I2C Core:
 
 - prevent double-free of an fwnode if it is a software node
 - use recent helpers instead of custom ACPI or outdated OF ones
 - add a more elaborate description of a message flag
 
 I2C Host drivers, part 1:
 
 Cleanups and refactorings:
 - lpi2c, riic, st, stm32f7: general improvements
 - riic: support more flexible IRQ configurations
 - tegra: fix documentation
 
 Improvements:
 - lpi2c: improve register polling and add atomic transfer
 - imx: use guarded spinlocks
 
 New hardware support:
 - Samsung Exynos 2200
 - Renesas RZ/T2H (R9A09G077), RZ/N2H (R9A09G087)
 
 DT binding:
 - rk3x: enable power domains
 - nxp: support clock property
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEOZGx6rniZ1Gk92RdFA3kzBSgKbYFAmiIhtcACgkQFA3kzBSg
 KbZ/zw//Q5R4BCW6ohE/YZ7LM66cz/eno0epS+qBUBlmQfz0XQtizIG1Ji63b8l1
 Cre+lghHQrveItJKWhCZyG1Ugym4PeXDL+tjgLN3Jy44DEdgtinl8bg/x4GjyKAW
 fXtCrPxV71+w9UTHU2bGmk744vEVkpy7d/zf0bRj1kCNd94IMZI5XEryQpa2qMnT
 pNVON/dPSKhEVMh3FrJxr6ZoZOeiUOGoycrnJCRjfOoc5Cgq6OdlNHik/mY4Hrhq
 1/jlA0eNMkOWFl7RDN6IdjySLctHdXIAJ03Ggv/3fQoGTF6i741VQU0OsF1zGVVh
 2fPapVGYdGDJ+ORhzGufytH63do5ATaxZr/5kATYmWBxzhAcVzG55p5YrdFfGfxj
 HkkYuiQ95CN3eTL1GmnIxPn1VtruxpEqkB6Jk0pj+PafeYjQeJB3Hy15ctdXPPz6
 TTg9ChIqkT/0oZJQEOsl+KP3iuxlaun+DDJ2MTecYc75Z7HqTFwqrTY0rx/Q52ry
 kg+ac6MdNEZtFz2VSrCqGndh1bCDCcjXqj7Yv7psRnX+kMYQBT1hVKys8/VOQh+/
 fOeaoL+vDdFO++P+0toAK76PEIg2ixBr/iqULcbgOZyz8RzTJJqyl3u3vktNB1Bb
 9wJfIr8R/MhhizfDrJxQS+cYoAjD9ByiiodMX1EBnSKbD/8U9lA=
 =qGAm
 -----END PGP SIGNATURE-----

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

Pull i2c updates from Wolfram Sang:
 "I2C Core:
   - prevent double-free of an fwnode if it is a software node
   - use recent helpers instead of custom ACPI or outdated OF ones
   - add a more elaborate description of a message flag

  Cleanups and refactorings:
   - lpi2c, riic, st, stm32f7: general improvements
   - riic: support more flexible IRQ configurations
   - tegra: fix documentation

  Improvements:
   - lpi2c: improve register polling and add atomic transfer
   - imx: use guarded spinlocks

  New hardware support:
   - Samsung Exynos 2200
   - Renesas RZ/T2H (R9A09G077), RZ/N2H (R9A09G087)

  DT binding:
   - rk3x: enable power domains
   - nxp: support clock property"

* tag 'i2c-for-6.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
  i2c: core: Fix double-free of fwnode in i2c_unregister_device()
  i2c: lpi2c: implement xfer_atomic callback
  i2c: lpi2c: use readl_poll_timeout() for register polling
  dt-bindings: i2c: i2c-rk3x: Allow use of a power-domain
  dt-bindings: i2c: exynos5: add samsung,exynos2200-hsi2c compatible
  i2c: lpi2c: convert to use secs_to_jiffies()
  i2c: st: Use min() to improve code
  i2c: imx: use guard to take spinlock
  i2c: stm32f7: Use str_on_off() helper
  dt-bindings: i2c: nxp,pnx-i2c: allow clocks property
  i2c: riic: Add support for RZ/T2H SoC
  i2c: riic: Move generic compatible string to end of array
  i2c: riic: Pass IRQ desc array as part of OF data
  dt-bindings: i2c: renesas,riic: Document RZ/T2H and RZ/N2H support
  dt-bindings: i2c: renesas,riic: Move ref for i2c-controller.yaml to the end
  i2c: tegra: Add missing kernel-doc for dma_dev member
  i2c: Clarify behavior of I2C_M_RD flag
  i2c: mux: pca954x: Use dev_fwnode()
  i2c: acpi: Replace custom code with device_match_acpi_handle()
This commit is contained in:
Linus Torvalds 2025-07-29 11:35:24 -07:00
commit 0ae982df67
14 changed files with 333 additions and 165 deletions

View File

@ -36,6 +36,7 @@ properties:
- items:
- enum:
- google,gs101-hsi2c
- samsung,exynos2200-hsi2c
- samsung,exynos850-hsi2c
- const: samsung,exynosautov9-hsi2c
- const: samsung,exynos5-hsi2c # Exynos5250 and Exynos5420

View File

@ -105,6 +105,9 @@ properties:
(t(f) in the I2C specification). If not specified we will use the SCL
value since they are the same in nearly all cases.
power-domains:
maxItems: 1
required:
- compatible
- reg

View File

@ -22,6 +22,9 @@ properties:
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-frequency:
default: 100000

View File

@ -10,9 +10,6 @@ maintainers:
- Chris Brandt <chris.brandt@renesas.com>
- Wolfram Sang <wsa+renesas@sang-engineering.com>
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
properties:
compatible:
oneOf:
@ -32,32 +29,50 @@ properties:
- renesas,riic-r9a09g056 # RZ/V2N
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
- const: renesas,riic-r9a09g057 # RZ/V2H(P)
- enum:
- renesas,riic-r9a09g057 # RZ/V2H(P)
- renesas,riic-r9a09g077 # RZ/T2H
- items:
- const: renesas,riic-r9a09g087 # RZ/N2H
- const: renesas,riic-r9a09g077 # RZ/T2H
reg:
maxItems: 1
interrupts:
items:
- description: Transmit End Interrupt
- description: Receive Data Full Interrupt
- description: Transmit Data Empty Interrupt
- description: Stop Condition Detection Interrupt
- description: Start Condition Detection Interrupt
- description: NACK Reception Interrupt
- description: Arbitration-Lost Interrupt
- description: Timeout Interrupt
oneOf:
- items:
- description: Transmit End Interrupt
- description: Receive Data Full Interrupt
- description: Transmit Data Empty Interrupt
- description: Stop Condition Detection Interrupt
- description: Start Condition Detection Interrupt
- description: NACK Reception Interrupt
- description: Arbitration-Lost Interrupt
- description: Timeout Interrupt
- items:
- description: Transfer Error Or Event Generation
- description: Receive Data Full Interrupt
- description: Transmit Data Empty Interrupt
- description: Transmit End Interrupt
interrupt-names:
items:
- const: tei
- const: ri
- const: ti
- const: spi
- const: sti
- const: naki
- const: ali
- const: tmoi
oneOf:
- items:
- const: tei
- const: ri
- const: ti
- const: spi
- const: sti
- const: naki
- const: ali
- const: tmoi
- items:
- const: eei
- const: rxi
- const: txi
- const: tei
clock-frequency:
description:
@ -84,18 +99,40 @@ required:
- '#address-cells'
- '#size-cells'
if:
properties:
compatible:
contains:
enum:
- renesas,riic-r9a07g043
- renesas,riic-r9a07g044
- renesas,riic-r9a07g054
- renesas,riic-r9a09g057
then:
required:
- resets
allOf:
- $ref: /schemas/i2c/i2c-controller.yaml#
- if:
properties:
compatible:
contains:
const: renesas,riic-r9a09g077
then:
properties:
interrupts:
maxItems: 4
interrupt-names:
maxItems: 4
resets: false
else:
properties:
interrupts:
minItems: 8
interrupt-names:
minItems: 8
- if:
properties:
compatible:
contains:
enum:
- renesas,riic-r9a07g043
- renesas,riic-r9a07g044
- renesas,riic-r9a07g054
- renesas,riic-r9a09g057
then:
required:
- resets
unevaluatedProperties: false

View File

@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
@ -187,41 +188,48 @@ struct lpi2c_imx_struct {
struct i2c_client *target;
};
#define lpi2c_imx_read_msr_poll_timeout(atomic, val, cond) \
(atomic ? readl_poll_timeout_atomic(lpi2c_imx->base + LPI2C_MSR, val, \
cond, 0, 500000) : \
readl_poll_timeout(lpi2c_imx->base + LPI2C_MSR, val, cond, \
0, 500000))
static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
unsigned int enable)
{
writel(enable, lpi2c_imx->base + LPI2C_MIER);
}
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
int err;
while (1) {
temp = readl(lpi2c_imx->base + LPI2C_MSR);
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp,
temp & (MSR_ALF | MSR_BBF | MSR_MBF));
/* check for arbitration lost, clear if set */
if (temp & MSR_ALF) {
writel(temp, lpi2c_imx->base + LPI2C_MSR);
return -EAGAIN;
}
/* check for arbitration lost, clear if set */
if (temp & MSR_ALF) {
writel(temp, lpi2c_imx->base + LPI2C_MSR);
return -EAGAIN;
}
if (temp & (MSR_BBF | MSR_MBF))
break;
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
schedule();
/* check for bus not busy */
if (err) {
dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
return 0;
}
static u32 lpi2c_imx_txfifo_cnt(struct lpi2c_imx_struct *lpi2c_imx)
{
return readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
}
static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned int bitrate = lpi2c_imx->bitrate;
@ -242,7 +250,7 @@ static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
}
static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
struct i2c_msg *msgs, bool atomic)
{
unsigned int temp;
@ -254,30 +262,23 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
return lpi2c_imx_bus_busy(lpi2c_imx);
return lpi2c_imx_bus_busy(lpi2c_imx, atomic);
}
static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned long orig_jiffies = jiffies;
unsigned int temp;
int err;
writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
do {
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if (temp & MSR_SDF)
break;
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp, temp & MSR_SDF);
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
break;
}
schedule();
} while (1);
if (err) {
dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
}
}
/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
@ -391,28 +392,25 @@ static int lpi2c_imx_pio_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
return time_left ? 0 : -ETIMEDOUT;
}
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned long orig_jiffies = jiffies;
u32 txcnt;
unsigned int temp;
int err;
do {
txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff;
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp,
(temp & MSR_NDF) || !lpi2c_imx_txfifo_cnt(lpi2c_imx));
if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) {
dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
return -EIO;
}
if (temp & MSR_NDF) {
dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n");
return -EIO;
}
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
schedule();
} while (txcnt);
if (err) {
dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
return 0;
}
@ -436,7 +434,7 @@ static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
}
static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
static bool lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned int data, txcnt;
@ -451,13 +449,19 @@ static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
txcnt++;
}
if (lpi2c_imx->delivered < lpi2c_imx->msglen)
lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
else
if (lpi2c_imx->delivered < lpi2c_imx->msglen) {
if (!atomic)
lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
return false;
}
if (!atomic)
complete(&lpi2c_imx->complete);
return true;
}
static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
{
unsigned int blocklen, remaining;
unsigned int temp, data;
@ -482,8 +486,9 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
if (!remaining) {
complete(&lpi2c_imx->complete);
return;
if (!atomic)
complete(&lpi2c_imx->complete);
return true;
}
/* not finished, still waiting for rx data */
@ -501,7 +506,10 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
}
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
if (!atomic)
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
return false;
}
static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
@ -509,11 +517,29 @@ static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
{
lpi2c_imx->tx_buf = msgs->buf;
lpi2c_imx_set_tx_watermark(lpi2c_imx);
lpi2c_imx_write_txfifo(lpi2c_imx);
lpi2c_imx_write_txfifo(lpi2c_imx, false);
}
static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
static int lpi2c_imx_write_atomic(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
u32 temp;
int err;
lpi2c_imx->tx_buf = msgs->buf;
err = lpi2c_imx_read_msr_poll_timeout(true, temp,
(temp & MSR_NDF) ||
lpi2c_imx_write_txfifo(lpi2c_imx, true));
if (temp & MSR_NDF)
return -EIO;
return err;
}
static void lpi2c_imx_read_init(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
unsigned int temp;
@ -524,8 +550,43 @@ static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
temp |= (RECV_DATA << 8);
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
}
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
static bool lpi2c_imx_read_chunk_atomic(struct lpi2c_imx_struct *lpi2c_imx)
{
u32 rxcnt;
rxcnt = (readl(lpi2c_imx->base + LPI2C_MFSR) >> 16) & 0xFF;
if (!rxcnt)
return false;
if (!lpi2c_imx_read_rxfifo(lpi2c_imx, true))
return false;
return true;
}
static int lpi2c_imx_read_atomic(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msgs)
{
u32 temp;
int tmo_us;
tmo_us = 1000000;
do {
if (lpi2c_imx_read_chunk_atomic(lpi2c_imx))
return 0;
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if (temp & MSR_NDF)
return -EIO;
udelay(100);
tmo_us -= 100;
} while (tmo_us > 0);
return -ETIMEDOUT;
}
static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg)
@ -545,14 +606,27 @@ static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx,
{
reinit_completion(&lpi2c_imx->complete);
if (msg->flags & I2C_M_RD)
lpi2c_imx_read(lpi2c_imx, msg);
else
if (msg->flags & I2C_M_RD) {
lpi2c_imx_read_init(lpi2c_imx, msg);
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
} else {
lpi2c_imx_write(lpi2c_imx, msg);
}
return lpi2c_imx_pio_msg_complete(lpi2c_imx);
}
static int lpi2c_imx_pio_xfer_atomic(struct lpi2c_imx_struct *lpi2c_imx,
struct i2c_msg *msg)
{
if (msg->flags & I2C_M_RD) {
lpi2c_imx_read_init(lpi2c_imx, msg);
return lpi2c_imx_read_atomic(lpi2c_imx, msg);
}
return lpi2c_imx_write_atomic(lpi2c_imx, msg);
}
static int lpi2c_imx_dma_timeout_calculate(struct lpi2c_imx_struct *lpi2c_imx)
{
unsigned long time = 0;
@ -563,7 +637,7 @@ static int lpi2c_imx_dma_timeout_calculate(struct lpi2c_imx_struct *lpi2c_imx)
time += 1;
/* Double calculated time */
return msecs_to_jiffies(time * MSEC_PER_SEC);
return secs_to_jiffies(time);
}
static int lpi2c_imx_alloc_rx_cmd_buf(struct lpi2c_imx_struct *lpi2c_imx)
@ -947,8 +1021,8 @@ static int lpi2c_imx_dma_xfer(struct lpi2c_imx_struct *lpi2c_imx,
return ret;
}
static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
static int lpi2c_imx_xfer_common(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num, bool atomic)
{
struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter);
unsigned int temp;
@ -959,7 +1033,7 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
return result;
for (i = 0; i < num; i++) {
result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
result = lpi2c_imx_start(lpi2c_imx, &msgs[i], atomic);
if (result)
goto disable;
@ -971,28 +1045,33 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
lpi2c_imx->tx_buf = NULL;
lpi2c_imx->delivered = 0;
lpi2c_imx->msglen = msgs[i].len;
init_completion(&lpi2c_imx->complete);
if (is_use_dma(lpi2c_imx, &msgs[i])) {
result = lpi2c_imx_dma_xfer(lpi2c_imx, &msgs[i]);
if (result && lpi2c_imx->dma->using_pio_mode)
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
if (atomic) {
result = lpi2c_imx_pio_xfer_atomic(lpi2c_imx, &msgs[i]);
} else {
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
init_completion(&lpi2c_imx->complete);
if (is_use_dma(lpi2c_imx, &msgs[i])) {
result = lpi2c_imx_dma_xfer(lpi2c_imx, &msgs[i]);
if (result && lpi2c_imx->dma->using_pio_mode)
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
} else {
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
}
}
if (result)
goto stop;
if (!(msgs[i].flags & I2C_M_RD)) {
result = lpi2c_imx_txfifo_empty(lpi2c_imx);
result = lpi2c_imx_txfifo_empty(lpi2c_imx, atomic);
if (result)
goto stop;
}
}
stop:
lpi2c_imx_stop(lpi2c_imx);
lpi2c_imx_stop(lpi2c_imx, atomic);
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if ((temp & MSR_NDF) && !result)
@ -1008,6 +1087,16 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
return (result < 0) ? result : num;
}
static int lpi2c_imx_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
return lpi2c_imx_xfer_common(adapter, msgs, num, false);
}
static int lpi2c_imx_xfer_atomic(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
{
return lpi2c_imx_xfer_common(adapter, msgs, num, true);
}
static irqreturn_t lpi2c_imx_target_isr(struct lpi2c_imx_struct *lpi2c_imx,
u32 ssr, u32 sier_filter)
{
@ -1070,9 +1159,9 @@ static irqreturn_t lpi2c_imx_master_isr(struct lpi2c_imx_struct *lpi2c_imx)
if (temp & MSR_NDF)
complete(&lpi2c_imx->complete);
else if (temp & MSR_RDF)
lpi2c_imx_read_rxfifo(lpi2c_imx);
lpi2c_imx_read_rxfifo(lpi2c_imx, false);
else if (temp & MSR_TDF)
lpi2c_imx_write_txfifo(lpi2c_imx);
lpi2c_imx_write_txfifo(lpi2c_imx, false);
return IRQ_HANDLED;
}
@ -1269,6 +1358,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
static const struct i2c_algorithm lpi2c_imx_algo = {
.xfer = lpi2c_imx_xfer,
.xfer_atomic = lpi2c_imx_xfer_atomic,
.functionality = lpi2c_imx_func,
.reg_target = lpi2c_imx_register_target,
.unreg_target = lpi2c_imx_unregister_target,

View File

@ -23,6 +23,7 @@
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@ -891,13 +892,13 @@ static enum hrtimer_restart i2c_imx_slave_timeout(struct hrtimer *t)
struct imx_i2c_struct *i2c_imx = container_of(t, struct imx_i2c_struct,
slave_timer);
unsigned int ctl, status;
unsigned long flags;
spin_lock_irqsave(&i2c_imx->slave_lock, flags);
guard(spinlock_irqsave)(&i2c_imx->slave_lock);
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
i2c_imx_slave_handle(i2c_imx, status, ctl);
spin_unlock_irqrestore(&i2c_imx->slave_lock, flags);
return HRTIMER_NORESTART;
}
@ -1126,32 +1127,26 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
struct imx_i2c_struct *i2c_imx = dev_id;
unsigned int ctl, status;
unsigned long flags;
spin_lock_irqsave(&i2c_imx->slave_lock, flags);
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (!(status & I2SR_IIF))
return IRQ_NONE;
if (status & I2SR_IIF) {
i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
if (i2c_imx->slave) {
if (!(ctl & I2CR_MSTA)) {
irqreturn_t ret;
ret = i2c_imx_slave_handle(i2c_imx,
status, ctl);
spin_unlock_irqrestore(&i2c_imx->slave_lock,
flags);
return ret;
}
if (i2c_imx->slave) {
if (!(ctl & I2CR_MSTA))
return i2c_imx_slave_handle(i2c_imx,
status, ctl);
i2c_imx_slave_finish_op(i2c_imx);
}
spin_unlock_irqrestore(&i2c_imx->slave_lock, flags);
return i2c_imx_master_isr(i2c_imx, status);
}
spin_unlock_irqrestore(&i2c_imx->slave_lock, flags);
return IRQ_NONE;
return i2c_imx_master_isr(i2c_imx, status);
}
static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,

View File

@ -79,6 +79,7 @@
#define ICIER_SPIE BIT(3)
#define ICSR2_NACKF BIT(4)
#define ICSR2_STOP BIT(3)
#define ICBR_RESERVED GENMASK(7, 5) /* Should be 1 on writes */
@ -102,6 +103,8 @@ enum riic_reg_list {
struct riic_of_data {
const u8 *regs;
const struct riic_irq_desc *irqs;
u8 num_irqs;
bool fast_mode_plus;
};
@ -324,6 +327,19 @@ static irqreturn_t riic_stop_isr(int irq, void *data)
return IRQ_HANDLED;
}
static irqreturn_t riic_eei_isr(int irq, void *data)
{
u8 icsr2 = riic_readb(data, RIIC_ICSR2);
if (icsr2 & ICSR2_NACKF)
return riic_tend_isr(irq, data);
if (icsr2 & ICSR2_STOP)
return riic_stop_isr(irq, data);
return IRQ_NONE;
}
static u32 riic_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@ -495,6 +511,13 @@ static const struct riic_irq_desc riic_irqs[] = {
{ .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" },
};
static const struct riic_irq_desc riic_rzt2h_irqs[] = {
{ .res_num = 0, .isr = riic_eei_isr, .name = "riic-eei" },
{ .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rxi" },
{ .res_num = 2, .isr = riic_tdre_isr, .name = "riic-txi" },
{ .res_num = 3, .isr = riic_tend_isr, .name = "riic-tei" },
};
static int riic_i2c_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -520,21 +543,23 @@ static int riic_i2c_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(riic->rstc),
"failed to acquire deasserted reset\n");
for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) {
riic->info = of_device_get_match_data(dev);
for (i = 0; i < riic->info->num_irqs; i++) {
const struct riic_irq_desc *irq_desc;
int irq;
irq = platform_get_irq(pdev, riic_irqs[i].res_num);
irq_desc = &riic->info->irqs[i];
irq = platform_get_irq(pdev, irq_desc->res_num);
if (irq < 0)
return irq;
ret = devm_request_irq(dev, irq, riic_irqs[i].isr,
0, riic_irqs[i].name, riic);
ret = devm_request_irq(dev, irq, irq_desc->isr, 0, irq_desc->name, riic);
if (ret)
return dev_err_probe(dev, ret, "failed to request irq %s\n",
riic_irqs[i].name);
irq_desc->name);
}
riic->info = of_device_get_match_data(dev);
adap = &riic->adapter;
i2c_set_adapdata(adap, riic);
@ -606,11 +631,15 @@ static const u8 riic_rz_a_regs[RIIC_REG_END] = {
static const struct riic_of_data riic_rz_a_info = {
.regs = riic_rz_a_regs,
.irqs = riic_irqs,
.num_irqs = ARRAY_SIZE(riic_irqs),
.fast_mode_plus = true,
};
static const struct riic_of_data riic_rz_a1h_info = {
.regs = riic_rz_a_regs,
.irqs = riic_irqs,
.num_irqs = ARRAY_SIZE(riic_irqs),
};
static const u8 riic_rz_v2h_regs[RIIC_REG_END] = {
@ -630,9 +659,17 @@ static const u8 riic_rz_v2h_regs[RIIC_REG_END] = {
static const struct riic_of_data riic_rz_v2h_info = {
.regs = riic_rz_v2h_regs,
.irqs = riic_irqs,
.num_irqs = ARRAY_SIZE(riic_irqs),
.fast_mode_plus = true,
};
static const struct riic_of_data riic_rz_t2h_info = {
.regs = riic_rz_v2h_regs,
.irqs = riic_rzt2h_irqs,
.num_irqs = ARRAY_SIZE(riic_rzt2h_irqs),
};
static int riic_i2c_suspend(struct device *dev)
{
struct riic_dev *riic = dev_get_drvdata(dev);
@ -683,10 +720,11 @@ static const struct dev_pm_ops riic_i2c_pm_ops = {
};
static const struct of_device_id riic_i2c_dt_ids[] = {
{ .compatible = "renesas,riic-rz", .data = &riic_rz_a_info },
{ .compatible = "renesas,riic-r7s72100", .data = &riic_rz_a1h_info, },
{ .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info },
{ /* Sentinel */ },
{ .compatible = "renesas,riic-r9a09g077", .data = &riic_rz_t2h_info },
{ .compatible = "renesas,riic-rz", .data = &riic_rz_a_info },
{ /* Sentinel */ }
};
static struct platform_driver riic_i2c_driver = {

View File

@ -13,6 +13,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@ -422,12 +423,8 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev)
tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT);
tx_fstat &= SSC_TX_FSTAT_STATUS;
if (c->count < (SSC_TXFIFO_SIZE - tx_fstat))
i = c->count;
else
i = SSC_TXFIFO_SIZE - tx_fstat;
for (; i > 0; i--, c->count--, c->buf++)
for (i = min(c->count, SSC_TXFIFO_SIZE - tx_fstat);
i > 0; i--, c->count--, c->buf++)
st_i2c_write_tx_fifo(i2c_dev, *c->buf);
}
@ -439,7 +436,7 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev)
* This functions fills the Tx FIFO with fixed pattern when
* in read mode to trigger clock.
*/
static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max)
static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, u32 max)
{
struct st_i2c_client *c = &i2c_dev->client;
u32 tx_fstat, sta;
@ -452,12 +449,8 @@ static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max)
tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT);
tx_fstat &= SSC_TX_FSTAT_STATUS;
if (max < (SSC_TXFIFO_SIZE - tx_fstat))
i = max;
else
i = SSC_TXFIFO_SIZE - tx_fstat;
for (; i > 0; i--, c->xfered++)
for (i = min(max, SSC_TXFIFO_SIZE - tx_fstat);
i > 0; i--, c->xfered++)
st_i2c_write_tx_fifo(i2c_dev, 0xff);
}

View File

@ -34,6 +34,7 @@
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/string_choices.h>
#include "i2c-stm32.h"
@ -722,7 +723,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
setup->rise_time, setup->fall_time);
dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
(i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf);
str_on_off(i2c_dev->analog_filter), i2c_dev->dnf);
i2c_dev->bus_rate = setup->speed_freq;

View File

@ -253,6 +253,7 @@ struct tegra_i2c_hw_feature {
* @dma_phys: handle to DMA resources
* @dma_buf: pointer to allocated DMA buffer
* @dma_buf_size: DMA buffer size
* @dma_dev: DMA device used for transfers
* @dma_mode: indicates active DMA transfer
* @dma_complete: DMA completion notifier
* @atomic_mode: indicates active atomic transfer

View File

@ -250,7 +250,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
if (adapter) {
/* The adapter must match the one in I2cSerialBus() connector */
if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle)
if (!device_match_acpi_handle(&adapter->dev, lookup.adapter_handle))
return -ENODEV;
} else {
struct acpi_device *adapter_adev;

View File

@ -1066,7 +1066,13 @@ void i2c_unregister_device(struct i2c_client *client)
of_node_clear_flag(to_of_node(fwnode), OF_POPULATED);
else if (is_acpi_device_node(fwnode))
acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
fwnode_handle_put(fwnode);
/*
* If the primary fwnode is a software node it is free-ed by
* device_remove_software_node() below, avoid double-free.
*/
if (!is_software_node(fwnode))
fwnode_handle_put(fwnode);
device_remove_software_node(&client->dev);
device_unregister(&client->dev);

View File

@ -442,8 +442,7 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc)
raw_spin_lock_init(&data->lock);
data->irq = irq_domain_create_linear(of_fwnode_handle(client->dev.of_node),
data->chip->nchans,
data->irq = irq_domain_create_linear(dev_fwnode(&client->dev), data->chip->nchans,
&irq_domain_simple_ops, data);
if (!data->irq)
return -ENODEV;

View File

@ -21,7 +21,8 @@
*
* @flags:
* Supported by all adapters:
* %I2C_M_RD: read data (from slave to master). Guaranteed to be 0x0001!
* %I2C_M_RD: read data (from slave to master). Guaranteed to be 0x0001! If
* not set, the transaction is interpreted as write.
*
* Optional:
* %I2C_M_DMA_SAFE: the buffer of this message is DMA safe. Makes only sense