mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
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:
commit
0ae982df67
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ properties:
|
|||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
default: 100000
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user