Merge branch 'i2c/for-5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "I2C has only driver updates for you this time. Mostly new IDs/DT compatibles, also SPDX conversions, small cleanups. STM32F7 got FastMode+ and PM support, Axxia some reliabilty improvements" * 'i2c/for-5.0' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (26 commits) i2c: Add Actions Semiconductor Owl family S700 I2C support dt-bindings: i2c: Add S700 support for Actions Semi Soc's i2c: ismt: Add support for Intel Cedar Fork i2c: tegra: Switch to SPDX identifier i2c: tegra: Add missing kerneldoc for some fields i2c: tegra: Cleanup kerneldoc comments i2c: axxia: support sequence command mode dt-bindings: i2c: rcar: Add r8a774c0 support dt-bindings: i2c: sh_mobile: Add r8a774c0 support i2c: sh_mobile: Add support for r8a774c0 (RZ/G2E) i2c: i2c-cros-ec-tunnel: Switch to SPDX identifier. i2c: powermac: Use of_node_name_eq for node name comparisons i2c-axxia: check for error conditions first i2c-axxia: dedicated function to set client addr dt-bindings: i2c: Use correct vendor prefix for Atmel i2c: tegra: replace spin_lock_irqsave with spin_lock in ISR eeprom: at24: add support for 24c2048 dt-bindings: eeprom: at24: add "atmel,24c2048" compatible string i2c: i2c-stm32f7: add PM Runtime support i2c: sh_mobile: add support for r8a77990 (R-Car E3) ...
This commit is contained in:
commit
7671c14e6a
|
@ -27,6 +27,7 @@ Required properties:
|
||||||
"atmel,24c256",
|
"atmel,24c256",
|
||||||
"atmel,24c512",
|
"atmel,24c512",
|
||||||
"atmel,24c1024",
|
"atmel,24c1024",
|
||||||
|
"atmel,24c2048",
|
||||||
|
|
||||||
If <manufacturer> is not "atmel", then a fallback must be used
|
If <manufacturer> is not "atmel", then a fallback must be used
|
||||||
with the same <model> and "atmel" as manufacturer.
|
with the same <model> and "atmel" as manufacturer.
|
||||||
|
|
|
@ -33,7 +33,7 @@ i2c0: i2c@fff84000 {
|
||||||
clock-frequency = <400000>;
|
clock-frequency = <400000>;
|
||||||
|
|
||||||
24c512@50 {
|
24c512@50 {
|
||||||
compatible = "24c512";
|
compatible = "atmel,24c512";
|
||||||
reg = <0x50>;
|
reg = <0x50>;
|
||||||
pagesize = <128>;
|
pagesize = <128>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ Example:
|
||||||
reg = <0>;
|
reg = <0>;
|
||||||
|
|
||||||
eeprom@50 {
|
eeprom@50 {
|
||||||
compatible = "at,24c02";
|
compatible = "atmel,24c02";
|
||||||
reg = <0x50>;
|
reg = <0x50>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -54,7 +54,7 @@ Example:
|
||||||
reg = <1>;
|
reg = <1>;
|
||||||
|
|
||||||
eeprom@50 {
|
eeprom@50 {
|
||||||
compatible = "at,24c02";
|
compatible = "atmel,24c02";
|
||||||
reg = <0x50>;
|
reg = <0x50>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,7 +54,7 @@ Example:
|
||||||
reg = <2>;
|
reg = <2>;
|
||||||
|
|
||||||
eeprom@54 {
|
eeprom@54 {
|
||||||
compatible = "at,24c08";
|
compatible = "atmel,24c08";
|
||||||
reg = <0x54>;
|
reg = <0x54>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,9 @@ Actions Semiconductor Owl I2C controller
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
|
|
||||||
- compatible : Should be "actions,s900-i2c".
|
- compatible : Should be one of the following:
|
||||||
|
- "actions,s700-i2c" for S700 SoC
|
||||||
|
- "actions,s900-i2c" for S900 SoC
|
||||||
- reg : Offset and length of the register set for the device.
|
- reg : Offset and length of the register set for the device.
|
||||||
- #address-cells : Should be 1.
|
- #address-cells : Should be 1.
|
||||||
- #size-cells : Should be 0.
|
- #size-cells : Should be 0.
|
||||||
|
|
|
@ -7,6 +7,7 @@ Required properties:
|
||||||
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
"renesas,i2c-r8a7745" if the device is a part of a R8A7745 SoC.
|
||||||
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
|
"renesas,i2c-r8a77470" if the device is a part of a R8A77470 SoC.
|
||||||
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
"renesas,i2c-r8a774a1" if the device is a part of a R8A774A1 SoC.
|
||||||
|
"renesas,i2c-r8a774c0" if the device is a part of a R8A774C0 SoC.
|
||||||
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
"renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC.
|
||||||
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
"renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC.
|
||||||
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
"renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC.
|
||||||
|
|
|
@ -8,6 +8,7 @@ Required properties:
|
||||||
- "renesas,iic-r8a7744" (RZ/G1N)
|
- "renesas,iic-r8a7744" (RZ/G1N)
|
||||||
- "renesas,iic-r8a7745" (RZ/G1E)
|
- "renesas,iic-r8a7745" (RZ/G1E)
|
||||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||||
|
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||||
- "renesas,iic-r8a7790" (R-Car H2)
|
- "renesas,iic-r8a7790" (R-Car H2)
|
||||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||||
|
@ -16,6 +17,7 @@ Required properties:
|
||||||
- "renesas,iic-r8a7795" (R-Car H3)
|
- "renesas,iic-r8a7795" (R-Car H3)
|
||||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||||
|
- "renesas,iic-r8a77990" (R-Car E3)
|
||||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
|
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
|
||||||
compatible device)
|
compatible device)
|
||||||
|
@ -28,7 +30,13 @@ Required properties:
|
||||||
the platform first followed by the generic R-Car
|
the platform first followed by the generic R-Car
|
||||||
version.
|
version.
|
||||||
|
|
||||||
renesas,rmobile-iic must always follow.
|
When compatible with "renesas,rmobile-iic" it should
|
||||||
|
be the last compatibility string listed.
|
||||||
|
|
||||||
|
The r8a77990 (R-Car E3) and r8a774c0 (RZ/G2E)
|
||||||
|
controllers are not considered compatible with
|
||||||
|
"renesas,rcar-gen3-iic" or "renesas,rmobile-iic"
|
||||||
|
due to the absence of automatic transmission registers.
|
||||||
|
|
||||||
- reg : address start and address range size of device
|
- reg : address start and address range size of device
|
||||||
- interrupts : interrupt of device
|
- interrupts : interrupt of device
|
||||||
|
|
|
@ -26,6 +26,11 @@ Optional properties :
|
||||||
- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board
|
- i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board
|
||||||
(default: 10)
|
(default: 10)
|
||||||
I2C Timings are derived from these 2 values
|
I2C Timings are derived from these 2 values
|
||||||
|
- st,syscfg-fmp: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG
|
||||||
|
whether Fast Mode Plus speed is selected by slave.
|
||||||
|
1st cell : phandle to syscfg
|
||||||
|
2nd cell : register offset within SYSCFG
|
||||||
|
3rd cell : register bitmask for FMP bit
|
||||||
|
|
||||||
Example :
|
Example :
|
||||||
|
|
||||||
|
@ -53,4 +58,5 @@ Example :
|
||||||
clocks = <&rcc 1 CLK_I2C1>;
|
clocks = <&rcc 1 CLK_I2C1>;
|
||||||
pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
|
pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
|
||||||
pinctrl-names = "default";
|
pinctrl-names = "default";
|
||||||
|
st,syscfg-fmp = <&syscfg 0x4 0x1>;
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@ Example:
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
eeprom@54 {
|
eeprom@54 {
|
||||||
compatible = "at,24c08";
|
compatible = "atmel,24c08";
|
||||||
reg = <0x54>;
|
reg = <0x54>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
*/
|
*/
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/clkdev.h>
|
#include <linux/clkdev.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
#define I2C_XFER_TIMEOUT (msecs_to_jiffies(250))
|
#define I2C_XFER_TIMEOUT (msecs_to_jiffies(250))
|
||||||
#define I2C_STOP_TIMEOUT (msecs_to_jiffies(100))
|
#define I2C_STOP_TIMEOUT (msecs_to_jiffies(100))
|
||||||
#define FIFO_SIZE 8
|
#define FIFO_SIZE 8
|
||||||
|
#define SEQ_LEN 2
|
||||||
|
|
||||||
#define GLOBAL_CONTROL 0x00
|
#define GLOBAL_CONTROL 0x00
|
||||||
#define GLOBAL_MST_EN BIT(0)
|
#define GLOBAL_MST_EN BIT(0)
|
||||||
|
@ -51,6 +53,7 @@
|
||||||
#define CMD_BUSY (1<<3)
|
#define CMD_BUSY (1<<3)
|
||||||
#define CMD_MANUAL (0x00 | CMD_BUSY)
|
#define CMD_MANUAL (0x00 | CMD_BUSY)
|
||||||
#define CMD_AUTO (0x01 | CMD_BUSY)
|
#define CMD_AUTO (0x01 | CMD_BUSY)
|
||||||
|
#define CMD_SEQUENCE (0x02 | CMD_BUSY)
|
||||||
#define MST_RX_XFER 0x2c
|
#define MST_RX_XFER 0x2c
|
||||||
#define MST_TX_XFER 0x30
|
#define MST_TX_XFER 0x30
|
||||||
#define MST_ADDR_1 0x34
|
#define MST_ADDR_1 0x34
|
||||||
|
@ -87,7 +90,9 @@
|
||||||
* axxia_i2c_dev - I2C device context
|
* axxia_i2c_dev - I2C device context
|
||||||
* @base: pointer to register struct
|
* @base: pointer to register struct
|
||||||
* @msg: pointer to current message
|
* @msg: pointer to current message
|
||||||
* @msg_xfrd: number of bytes transferred in msg
|
* @msg_r: pointer to current read message (sequence transfer)
|
||||||
|
* @msg_xfrd: number of bytes transferred in tx_fifo
|
||||||
|
* @msg_xfrd_r: number of bytes transferred in rx_fifo
|
||||||
* @msg_err: error code for completed message
|
* @msg_err: error code for completed message
|
||||||
* @msg_complete: xfer completion object
|
* @msg_complete: xfer completion object
|
||||||
* @dev: device reference
|
* @dev: device reference
|
||||||
|
@ -98,7 +103,9 @@
|
||||||
struct axxia_i2c_dev {
|
struct axxia_i2c_dev {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct i2c_msg *msg;
|
struct i2c_msg *msg;
|
||||||
|
struct i2c_msg *msg_r;
|
||||||
size_t msg_xfrd;
|
size_t msg_xfrd;
|
||||||
|
size_t msg_xfrd_r;
|
||||||
int msg_err;
|
int msg_err;
|
||||||
struct completion msg_complete;
|
struct completion msg_complete;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -227,14 +234,14 @@ static int i2c_m_recv_len(const struct i2c_msg *msg)
|
||||||
*/
|
*/
|
||||||
static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
|
static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
|
||||||
{
|
{
|
||||||
struct i2c_msg *msg = idev->msg;
|
struct i2c_msg *msg = idev->msg_r;
|
||||||
size_t rx_fifo_avail = readl(idev->base + MST_RX_FIFO);
|
size_t rx_fifo_avail = readl(idev->base + MST_RX_FIFO);
|
||||||
int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd);
|
int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd_r);
|
||||||
|
|
||||||
while (bytes_to_transfer-- > 0) {
|
while (bytes_to_transfer-- > 0) {
|
||||||
int c = readl(idev->base + MST_DATA);
|
int c = readl(idev->base + MST_DATA);
|
||||||
|
|
||||||
if (idev->msg_xfrd == 0 && i2c_m_recv_len(msg)) {
|
if (idev->msg_xfrd_r == 0 && i2c_m_recv_len(msg)) {
|
||||||
/*
|
/*
|
||||||
* Check length byte for SMBus block read
|
* Check length byte for SMBus block read
|
||||||
*/
|
*/
|
||||||
|
@ -247,7 +254,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
|
||||||
msg->len = 1 + c;
|
msg->len = 1 + c;
|
||||||
writel(msg->len, idev->base + MST_RX_XFER);
|
writel(msg->len, idev->base + MST_RX_XFER);
|
||||||
}
|
}
|
||||||
msg->buf[idev->msg_xfrd++] = c;
|
msg->buf[idev->msg_xfrd_r++] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -287,7 +294,7 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX FIFO needs service? */
|
/* RX FIFO needs service? */
|
||||||
if (i2c_m_rd(idev->msg) && (status & MST_STATUS_RFL))
|
if (i2c_m_rd(idev->msg_r) && (status & MST_STATUS_RFL))
|
||||||
axxia_i2c_empty_rx_fifo(idev);
|
axxia_i2c_empty_rx_fifo(idev);
|
||||||
|
|
||||||
/* TX FIFO needs service? */
|
/* TX FIFO needs service? */
|
||||||
|
@ -296,22 +303,7 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
||||||
i2c_int_disable(idev, MST_STATUS_TFL);
|
i2c_int_disable(idev, MST_STATUS_TFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & MST_STATUS_SCC) {
|
if (unlikely(status & MST_STATUS_ERR)) {
|
||||||
/* Stop completed */
|
|
||||||
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
|
||||||
complete(&idev->msg_complete);
|
|
||||||
} else if (status & MST_STATUS_SNS) {
|
|
||||||
/* Transfer done */
|
|
||||||
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
|
||||||
if (i2c_m_rd(idev->msg) && idev->msg_xfrd < idev->msg->len)
|
|
||||||
axxia_i2c_empty_rx_fifo(idev);
|
|
||||||
complete(&idev->msg_complete);
|
|
||||||
} else if (status & MST_STATUS_TSS) {
|
|
||||||
/* Transfer timeout */
|
|
||||||
idev->msg_err = -ETIMEDOUT;
|
|
||||||
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
|
||||||
complete(&idev->msg_complete);
|
|
||||||
} else if (unlikely(status & MST_STATUS_ERR)) {
|
|
||||||
/* Transfer error */
|
/* Transfer error */
|
||||||
i2c_int_disable(idev, ~0);
|
i2c_int_disable(idev, ~0);
|
||||||
if (status & MST_STATUS_AL)
|
if (status & MST_STATUS_AL)
|
||||||
|
@ -328,6 +320,24 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
||||||
readl(idev->base + MST_TX_BYTES_XFRD),
|
readl(idev->base + MST_TX_BYTES_XFRD),
|
||||||
readl(idev->base + MST_TX_XFER));
|
readl(idev->base + MST_TX_XFER));
|
||||||
complete(&idev->msg_complete);
|
complete(&idev->msg_complete);
|
||||||
|
} else if (status & MST_STATUS_SCC) {
|
||||||
|
/* Stop completed */
|
||||||
|
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
||||||
|
complete(&idev->msg_complete);
|
||||||
|
} else if (status & MST_STATUS_SNS) {
|
||||||
|
/* Transfer done */
|
||||||
|
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
||||||
|
if (i2c_m_rd(idev->msg_r) && idev->msg_xfrd_r < idev->msg_r->len)
|
||||||
|
axxia_i2c_empty_rx_fifo(idev);
|
||||||
|
complete(&idev->msg_complete);
|
||||||
|
} else if (status & MST_STATUS_SS) {
|
||||||
|
/* Auto/Sequence transfer done */
|
||||||
|
complete(&idev->msg_complete);
|
||||||
|
} else if (status & MST_STATUS_TSS) {
|
||||||
|
/* Transfer timeout */
|
||||||
|
idev->msg_err = -ETIMEDOUT;
|
||||||
|
i2c_int_disable(idev, ~MST_STATUS_TSS);
|
||||||
|
complete(&idev->msg_complete);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -337,17 +347,9 @@ out:
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
static void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
{
|
{
|
||||||
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
|
|
||||||
u32 rx_xfer, tx_xfer;
|
|
||||||
u32 addr_1, addr_2;
|
u32 addr_1, addr_2;
|
||||||
unsigned long time_left;
|
|
||||||
unsigned int wt_value;
|
|
||||||
|
|
||||||
idev->msg = msg;
|
|
||||||
idev->msg_xfrd = 0;
|
|
||||||
reinit_completion(&idev->msg_complete);
|
|
||||||
|
|
||||||
if (i2c_m_ten(msg)) {
|
if (i2c_m_ten(msg)) {
|
||||||
/* 10-bit address
|
/* 10-bit address
|
||||||
|
@ -367,6 +369,90 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
addr_2 = 0;
|
addr_2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writel(addr_1, idev->base + MST_ADDR_1);
|
||||||
|
writel(addr_2, idev->base + MST_ADDR_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The NAK interrupt will be sent _before_ issuing STOP command
|
||||||
|
* so the controller might still be busy processing it. No
|
||||||
|
* interrupt will be sent at the end so we have to poll for it
|
||||||
|
*/
|
||||||
|
static int axxia_i2c_handle_seq_nak(struct axxia_i2c_dev *idev)
|
||||||
|
{
|
||||||
|
unsigned long timeout = jiffies + I2C_XFER_TIMEOUT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((readl(idev->base + MST_COMMAND) & CMD_BUSY) == 0)
|
||||||
|
return 0;
|
||||||
|
usleep_range(1, 100);
|
||||||
|
} while (time_before(jiffies, timeout));
|
||||||
|
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[])
|
||||||
|
{
|
||||||
|
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SS | MST_STATUS_RFL;
|
||||||
|
u32 rlen = i2c_m_recv_len(&msgs[1]) ? I2C_SMBUS_BLOCK_MAX : msgs[1].len;
|
||||||
|
unsigned long time_left;
|
||||||
|
|
||||||
|
axxia_i2c_set_addr(idev, &msgs[0]);
|
||||||
|
|
||||||
|
writel(msgs[0].len, idev->base + MST_TX_XFER);
|
||||||
|
writel(rlen, idev->base + MST_RX_XFER);
|
||||||
|
|
||||||
|
idev->msg = &msgs[0];
|
||||||
|
idev->msg_r = &msgs[1];
|
||||||
|
idev->msg_xfrd = 0;
|
||||||
|
idev->msg_xfrd_r = 0;
|
||||||
|
axxia_i2c_fill_tx_fifo(idev);
|
||||||
|
|
||||||
|
writel(CMD_SEQUENCE, idev->base + MST_COMMAND);
|
||||||
|
|
||||||
|
reinit_completion(&idev->msg_complete);
|
||||||
|
i2c_int_enable(idev, int_mask);
|
||||||
|
|
||||||
|
time_left = wait_for_completion_timeout(&idev->msg_complete,
|
||||||
|
I2C_XFER_TIMEOUT);
|
||||||
|
|
||||||
|
i2c_int_disable(idev, int_mask);
|
||||||
|
|
||||||
|
axxia_i2c_empty_rx_fifo(idev);
|
||||||
|
|
||||||
|
if (idev->msg_err == -ENXIO) {
|
||||||
|
if (axxia_i2c_handle_seq_nak(idev))
|
||||||
|
axxia_i2c_init(idev);
|
||||||
|
} else if (readl(idev->base + MST_COMMAND) & CMD_BUSY) {
|
||||||
|
dev_warn(idev->dev, "busy after xfer\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_left == 0) {
|
||||||
|
idev->msg_err = -ETIMEDOUT;
|
||||||
|
i2c_recover_bus(&idev->adapter);
|
||||||
|
axxia_i2c_init(idev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
|
||||||
|
axxia_i2c_init(idev);
|
||||||
|
|
||||||
|
return idev->msg_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
|
{
|
||||||
|
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
|
||||||
|
u32 rx_xfer, tx_xfer;
|
||||||
|
unsigned long time_left;
|
||||||
|
unsigned int wt_value;
|
||||||
|
|
||||||
|
idev->msg = msg;
|
||||||
|
idev->msg_r = msg;
|
||||||
|
idev->msg_xfrd = 0;
|
||||||
|
idev->msg_xfrd_r = 0;
|
||||||
|
reinit_completion(&idev->msg_complete);
|
||||||
|
|
||||||
|
axxia_i2c_set_addr(idev, msg);
|
||||||
|
|
||||||
if (i2c_m_rd(msg)) {
|
if (i2c_m_rd(msg)) {
|
||||||
/* I2C read transfer */
|
/* I2C read transfer */
|
||||||
rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len;
|
rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len;
|
||||||
|
@ -379,8 +465,6 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
|
||||||
|
|
||||||
writel(rx_xfer, idev->base + MST_RX_XFER);
|
writel(rx_xfer, idev->base + MST_RX_XFER);
|
||||||
writel(tx_xfer, idev->base + MST_TX_XFER);
|
writel(tx_xfer, idev->base + MST_TX_XFER);
|
||||||
writel(addr_1, idev->base + MST_ADDR_1);
|
|
||||||
writel(addr_2, idev->base + MST_ADDR_2);
|
|
||||||
|
|
||||||
if (i2c_m_rd(msg))
|
if (i2c_m_rd(msg))
|
||||||
int_mask |= MST_STATUS_RFL;
|
int_mask |= MST_STATUS_RFL;
|
||||||
|
@ -445,6 +529,18 @@ static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function checks if the msgs[] array contains messages compatible with
|
||||||
|
* Sequence mode of operation. This mode assumes there will be exactly one
|
||||||
|
* write of non-zero length followed by exactly one read of non-zero length,
|
||||||
|
* both targeted at the same client device.
|
||||||
|
*/
|
||||||
|
static bool axxia_i2c_sequence_ok(struct i2c_msg msgs[], int num)
|
||||||
|
{
|
||||||
|
return num == SEQ_LEN && !i2c_m_rd(&msgs[0]) && i2c_m_rd(&msgs[1]) &&
|
||||||
|
msgs[0].len > 0 && msgs[0].len <= FIFO_SIZE &&
|
||||||
|
msgs[1].len > 0 && msgs[0].addr == msgs[1].addr;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||||
{
|
{
|
||||||
|
@ -453,6 +549,12 @@ axxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
idev->msg_err = 0;
|
idev->msg_err = 0;
|
||||||
|
|
||||||
|
if (axxia_i2c_sequence_ok(msgs, num)) {
|
||||||
|
ret = axxia_i2c_xfer_seq(idev, msgs);
|
||||||
|
return ret ? : SEQ_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
i2c_int_enable(idev, MST_STATUS_TSS);
|
i2c_int_enable(idev, MST_STATUS_TSS);
|
||||||
|
|
||||||
for (i = 0; ret == 0 && i < num; ++i)
|
for (i = 0; ret == 0 && i < num; ++i)
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* BCM2835 master mode driver
|
* BCM2835 master mode driver
|
||||||
*
|
|
||||||
* This software is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
|
||||||
* may be copied, distributed, and modified under those terms.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
/*
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
* Copyright (C) 2013 Google, Inc
|
// Expose an I2C passthrough to the ChromeOS EC.
|
||||||
*
|
//
|
||||||
* This program is free software; you can redistribute it and/or modify
|
// Copyright (C) 2013 Google, Inc.
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* Expose an I2C passthrough to the ChromeOS EC.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
|
|
@ -437,7 +437,7 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(signal_pending(current))){
|
if (signal_pending(current)){
|
||||||
DBG("%d: poll interrupted\n", dev->idx);
|
DBG("%d: poll interrupted\n", dev->idx);
|
||||||
ret = -ERESTARTSYS;
|
ret = -ERESTARTSYS;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1090,7 +1090,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
||||||
/* Get I2C clock */
|
/* Get I2C clock */
|
||||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(i2c_imx->clk)) {
|
if (IS_ERR(i2c_imx->clk)) {
|
||||||
dev_err(&pdev->dev, "can't get I2C clock\n");
|
if (PTR_ERR(i2c_imx->clk) != -EPROBE_DEFER)
|
||||||
|
dev_err(&pdev->dev, "can't get I2C clock\n");
|
||||||
return PTR_ERR(i2c_imx->clk);
|
return PTR_ERR(i2c_imx->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@
|
||||||
/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */
|
/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */
|
||||||
#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59
|
#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59
|
||||||
#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a
|
#define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a
|
||||||
|
#define PCI_DEVICE_ID_INTEL_CDF_SMT 0x18ac
|
||||||
#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac
|
#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac
|
||||||
#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15
|
#define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15
|
||||||
|
|
||||||
|
@ -181,6 +182,7 @@ struct ismt_priv {
|
||||||
static const struct pci_device_id ismt_ids[] = {
|
static const struct pci_device_id ismt_ids[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
|
||||||
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMT) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
|
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
|
||||||
{ 0, }
|
{ 0, }
|
||||||
|
|
|
@ -475,6 +475,7 @@ disable_clk:
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id owl_i2c_of_match[] = {
|
static const struct of_device_id owl_i2c_of_match[] = {
|
||||||
|
{ .compatible = "actions,s700-i2c" },
|
||||||
{ .compatible = "actions,s900-i2c" },
|
{ .compatible = "actions,s900-i2c" },
|
||||||
{ /* sentinel */ }
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -229,9 +229,9 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
|
||||||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||||
|
|
||||||
/* Now handle some devices with missing "reg" properties */
|
/* Now handle some devices with missing "reg" properties */
|
||||||
if (!strcmp(node->name, "cereal"))
|
if (of_node_name_eq(node, "cereal"))
|
||||||
return 0x60;
|
return 0x60;
|
||||||
else if (!strcmp(node->name, "deq"))
|
else if (of_node_name_eq(node, "deq"))
|
||||||
return 0x34;
|
return 0x34;
|
||||||
|
|
||||||
dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
|
dev_warn(&adap->dev, "No i2c address for %pOF\n", node);
|
||||||
|
@ -304,7 +304,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now look for known workarounds */
|
/* Now look for known workarounds */
|
||||||
if (!strcmp(node->name, "deq")) {
|
if (of_node_name_eq(node, "deq")) {
|
||||||
/* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
|
/* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
|
||||||
if (addr == 0x34) {
|
if (addr == 0x34) {
|
||||||
snprintf(type, type_size, "MAC,tas3001");
|
snprintf(type, type_size, "MAC,tas3001");
|
||||||
|
@ -331,7 +331,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap,
|
||||||
* case we skip this function completely as the device-tree will
|
* case we skip this function completely as the device-tree will
|
||||||
* not contain anything useful.
|
* not contain anything useful.
|
||||||
*/
|
*/
|
||||||
if (!strcmp(adap->dev.of_node->name, "via-pmu"))
|
if (of_node_name_eq(adap->dev.of_node, "via-pmu"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_child_of_node(adap->dev.of_node, node) {
|
for_each_child_of_node(adap->dev.of_node, node) {
|
||||||
|
|
|
@ -800,6 +800,7 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = {
|
||||||
static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
|
static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
|
||||||
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
|
{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
|
||||||
|
{ .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
|
{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
|
||||||
{ .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
|
||||||
|
@ -808,6 +809,7 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
|
||||||
{ .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
|
||||||
|
{ .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
|
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
|
||||||
{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
|
{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
|
||||||
{},
|
{},
|
||||||
|
|
|
@ -21,12 +21,16 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
@ -163,6 +167,8 @@
|
||||||
#define STM32F7_SCLH_MAX BIT(8)
|
#define STM32F7_SCLH_MAX BIT(8)
|
||||||
#define STM32F7_SCLL_MAX BIT(8)
|
#define STM32F7_SCLL_MAX BIT(8)
|
||||||
|
|
||||||
|
#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct stm32f7_i2c_spec - private i2c specification timing
|
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||||
* @rate: I2C bus speed (Hz)
|
* @rate: I2C bus speed (Hz)
|
||||||
|
@ -276,6 +282,7 @@ struct stm32f7_i2c_msg {
|
||||||
* slave)
|
* slave)
|
||||||
* @dma: dma data
|
* @dma: dma data
|
||||||
* @use_dma: boolean to know if dma is used in the current transfer
|
* @use_dma: boolean to know if dma is used in the current transfer
|
||||||
|
* @regmap: holds SYSCFG phandle for Fast Mode Plus bits
|
||||||
*/
|
*/
|
||||||
struct stm32f7_i2c_dev {
|
struct stm32f7_i2c_dev {
|
||||||
struct i2c_adapter adap;
|
struct i2c_adapter adap;
|
||||||
|
@ -296,6 +303,7 @@ struct stm32f7_i2c_dev {
|
||||||
bool master_mode;
|
bool master_mode;
|
||||||
struct stm32_i2c_dma *dma;
|
struct stm32_i2c_dma *dma;
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
|
struct regmap *regmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1545,15 +1553,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||||
i2c_dev->msg_id = 0;
|
i2c_dev->msg_id = 0;
|
||||||
f7_msg->smbus = false;
|
f7_msg->smbus = false;
|
||||||
|
|
||||||
ret = clk_enable(i2c_dev->clk);
|
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||||
if (ret) {
|
if (ret < 0)
|
||||||
dev_err(i2c_dev->dev, "Failed to enable clock\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
|
|
||||||
stm32f7_i2c_xfer_msg(i2c_dev, msgs);
|
stm32f7_i2c_xfer_msg(i2c_dev, msgs);
|
||||||
|
|
||||||
|
@ -1569,8 +1575,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_free:
|
pm_free:
|
||||||
clk_disable(i2c_dev->clk);
|
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||||
|
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||||
|
|
||||||
return (ret < 0) ? ret : num;
|
return (ret < 0) ? ret : num;
|
||||||
}
|
}
|
||||||
|
@ -1592,39 +1599,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||||
f7_msg->read_write = read_write;
|
f7_msg->read_write = read_write;
|
||||||
f7_msg->smbus = true;
|
f7_msg->smbus = true;
|
||||||
|
|
||||||
ret = clk_enable(i2c_dev->clk);
|
ret = pm_runtime_get_sync(dev);
|
||||||
if (ret) {
|
if (ret < 0)
|
||||||
dev_err(i2c_dev->dev, "Failed to enable clock\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
|
|
||||||
ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
|
ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
|
|
||||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||||
i2c_dev->adap.timeout);
|
i2c_dev->adap.timeout);
|
||||||
ret = f7_msg->result;
|
ret = f7_msg->result;
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
|
|
||||||
if (!timeout) {
|
if (!timeout) {
|
||||||
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
|
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
|
||||||
if (i2c_dev->use_dma)
|
if (i2c_dev->use_dma)
|
||||||
dmaengine_terminate_all(dma->chan_using);
|
dmaengine_terminate_all(dma->chan_using);
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check PEC */
|
/* Check PEC */
|
||||||
if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
|
if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
|
||||||
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
|
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto pm_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (read_write && size != I2C_SMBUS_QUICK) {
|
if (read_write && size != I2C_SMBUS_QUICK) {
|
||||||
|
@ -1649,8 +1654,9 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clk_free:
|
pm_free:
|
||||||
clk_disable(i2c_dev->clk);
|
pm_runtime_mark_last_busy(dev);
|
||||||
|
pm_runtime_put_autosuspend(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1676,13 +1682,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
|
ret = pm_runtime_get_sync(dev);
|
||||||
ret = clk_enable(i2c_dev->clk);
|
if (ret < 0)
|
||||||
if (ret) {
|
return ret;
|
||||||
dev_err(dev, "Failed to enable clock\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
/* Configure Own Address 1 */
|
/* Configure Own Address 1 */
|
||||||
|
@ -1703,7 +1705,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||||
oar2 &= ~STM32F7_I2C_OAR2_MASK;
|
oar2 &= ~STM32F7_I2C_OAR2_MASK;
|
||||||
if (slave->flags & I2C_CLIENT_TEN) {
|
if (slave->flags & I2C_CLIENT_TEN) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto exit;
|
goto pm_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
|
oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr);
|
||||||
|
@ -1712,7 +1714,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||||
writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
|
writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2);
|
||||||
} else {
|
} else {
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto exit;
|
goto pm_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable ACK */
|
/* Enable ACK */
|
||||||
|
@ -1723,11 +1725,10 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
||||||
STM32F7_I2C_CR1_PE;
|
STM32F7_I2C_CR1_PE;
|
||||||
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
|
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
|
||||||
|
|
||||||
return 0;
|
ret = 0;
|
||||||
|
pm_free:
|
||||||
exit:
|
pm_runtime_mark_last_busy(dev);
|
||||||
if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
|
pm_runtime_put_autosuspend(dev);
|
||||||
clk_disable(i2c_dev->clk);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1745,6 +1746,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
|
||||||
|
|
||||||
WARN_ON(!i2c_dev->slave[id]);
|
WARN_ON(!i2c_dev->slave[id]);
|
||||||
|
|
||||||
|
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
mask = STM32F7_I2C_OAR1_OA1EN;
|
mask = STM32F7_I2C_OAR1_OA1EN;
|
||||||
stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
|
stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask);
|
||||||
|
@ -1755,14 +1760,39 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
|
||||||
|
|
||||||
i2c_dev->slave[id] = NULL;
|
i2c_dev->slave[id] = NULL;
|
||||||
|
|
||||||
if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
|
if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
|
||||||
stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
|
stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);
|
||||||
clk_disable(i2c_dev->clk);
|
|
||||||
}
|
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||||
|
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev,
|
||||||
|
struct stm32f7_i2c_dev *i2c_dev)
|
||||||
|
{
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
int ret;
|
||||||
|
u32 reg, mask;
|
||||||
|
|
||||||
|
i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp");
|
||||||
|
if (IS_ERR(i2c_dev->regmap)) {
|
||||||
|
/* Optional */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1, ®);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = of_property_read_u32_index(np, "st,syscfg-fmp", 2, &mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return regmap_update_bits(i2c_dev->regmap, reg, mask, mask);
|
||||||
|
}
|
||||||
|
|
||||||
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
|
return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE |
|
||||||
|
@ -1819,6 +1849,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev, "Error: Missing controller clock\n");
|
dev_err(&pdev->dev, "Error: Missing controller clock\n");
|
||||||
return PTR_ERR(i2c_dev->clk);
|
return PTR_ERR(i2c_dev->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = clk_prepare_enable(i2c_dev->clk);
|
ret = clk_prepare_enable(i2c_dev->clk);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
|
dev_err(&pdev->dev, "Failed to prepare_enable clock\n");
|
||||||
|
@ -1828,12 +1859,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||||
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
||||||
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
|
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
|
||||||
&clk_rate);
|
&clk_rate);
|
||||||
if (!ret && clk_rate >= 1000000)
|
if (!ret && clk_rate >= 1000000) {
|
||||||
i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
|
i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;
|
||||||
else if (!ret && clk_rate >= 400000)
|
ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev);
|
||||||
|
if (ret)
|
||||||
|
goto clk_free;
|
||||||
|
} else if (!ret && clk_rate >= 400000) {
|
||||||
i2c_dev->speed = STM32_I2C_SPEED_FAST;
|
i2c_dev->speed = STM32_I2C_SPEED_FAST;
|
||||||
else if (!ret && clk_rate >= 100000)
|
} else if (!ret && clk_rate >= 100000) {
|
||||||
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
||||||
|
}
|
||||||
|
|
||||||
rst = devm_reset_control_get(&pdev->dev, NULL);
|
rst = devm_reset_control_get(&pdev->dev, NULL);
|
||||||
if (IS_ERR(rst)) {
|
if (IS_ERR(rst)) {
|
||||||
|
@ -1888,8 +1923,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clk_free;
|
goto clk_free;
|
||||||
|
|
||||||
stm32f7_i2c_hw_config(i2c_dev);
|
|
||||||
|
|
||||||
adap = &i2c_dev->adap;
|
adap = &i2c_dev->adap;
|
||||||
i2c_set_adapdata(adap, i2c_dev);
|
i2c_set_adapdata(adap, i2c_dev);
|
||||||
snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
|
snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)",
|
||||||
|
@ -1908,18 +1941,35 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
||||||
STM32F7_I2C_TXDR,
|
STM32F7_I2C_TXDR,
|
||||||
STM32F7_I2C_RXDR);
|
STM32F7_I2C_RXDR);
|
||||||
|
|
||||||
ret = i2c_add_adapter(adap);
|
|
||||||
if (ret)
|
|
||||||
goto clk_free;
|
|
||||||
|
|
||||||
platform_set_drvdata(pdev, i2c_dev);
|
platform_set_drvdata(pdev, i2c_dev);
|
||||||
|
|
||||||
clk_disable(i2c_dev->clk);
|
pm_runtime_set_autosuspend_delay(i2c_dev->dev,
|
||||||
|
STM32F7_AUTOSUSPEND_DELAY);
|
||||||
|
pm_runtime_use_autosuspend(i2c_dev->dev);
|
||||||
|
pm_runtime_set_active(i2c_dev->dev);
|
||||||
|
pm_runtime_enable(i2c_dev->dev);
|
||||||
|
|
||||||
|
pm_runtime_get_noresume(&pdev->dev);
|
||||||
|
|
||||||
|
stm32f7_i2c_hw_config(i2c_dev);
|
||||||
|
|
||||||
|
ret = i2c_add_adapter(adap);
|
||||||
|
if (ret)
|
||||||
|
goto pm_disable;
|
||||||
|
|
||||||
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
|
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
|
||||||
|
|
||||||
|
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||||
|
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
pm_disable:
|
||||||
|
pm_runtime_put_noidle(i2c_dev->dev);
|
||||||
|
pm_runtime_disable(i2c_dev->dev);
|
||||||
|
pm_runtime_set_suspended(i2c_dev->dev);
|
||||||
|
pm_runtime_dont_use_autosuspend(i2c_dev->dev);
|
||||||
|
|
||||||
clk_free:
|
clk_free:
|
||||||
clk_disable_unprepare(i2c_dev->clk);
|
clk_disable_unprepare(i2c_dev->clk);
|
||||||
|
|
||||||
|
@ -1936,12 +1986,51 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_del_adapter(&i2c_dev->adap);
|
i2c_del_adapter(&i2c_dev->adap);
|
||||||
|
pm_runtime_get_sync(i2c_dev->dev);
|
||||||
|
|
||||||
clk_unprepare(i2c_dev->clk);
|
clk_disable_unprepare(i2c_dev->clk);
|
||||||
|
|
||||||
|
pm_runtime_put_noidle(i2c_dev->dev);
|
||||||
|
pm_runtime_disable(i2c_dev->dev);
|
||||||
|
pm_runtime_set_suspended(i2c_dev->dev);
|
||||||
|
pm_runtime_dont_use_autosuspend(i2c_dev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int stm32f7_i2c_runtime_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (!stm32f7_i2c_is_slave_registered(i2c_dev))
|
||||||
|
clk_disable_unprepare(i2c_dev->clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int stm32f7_i2c_runtime_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
|
||||||
|
ret = clk_prepare_enable(i2c_dev->clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to prepare_enable clock\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
|
||||||
|
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
|
||||||
|
stm32f7_i2c_runtime_resume, NULL)
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id stm32f7_i2c_match[] = {
|
static const struct of_device_id stm32f7_i2c_match[] = {
|
||||||
{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
|
{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
|
||||||
{},
|
{},
|
||||||
|
@ -1952,6 +2041,7 @@ static struct platform_driver stm32f7_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "stm32f7-i2c",
|
.name = "stm32f7-i2c",
|
||||||
.of_match_table = stm32f7_i2c_match,
|
.of_match_table = stm32f7_i2c_match,
|
||||||
|
.pm = &stm32f7_i2c_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = stm32f7_i2c_probe,
|
.probe = stm32f7_i2c_probe,
|
||||||
.remove = stm32f7_i2c_remove,
|
.remove = stm32f7_i2c_remove,
|
||||||
|
|
|
@ -1,18 +1,9 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* drivers/i2c/busses/i2c-tegra.c
|
* drivers/i2c/busses/i2c-tegra.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010 Google, Inc.
|
* Copyright (C) 2010 Google, Inc.
|
||||||
* Author: Colin Cross <ccross@android.com>
|
* Author: Colin Cross <ccross@android.com>
|
||||||
*
|
|
||||||
* This software is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
|
||||||
* may be copied, distributed, and modified under those terms.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
@ -145,8 +136,8 @@ enum msg_end_type {
|
||||||
* @has_continue_xfer_support: Continue transfer supports.
|
* @has_continue_xfer_support: Continue transfer supports.
|
||||||
* @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
|
* @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
|
||||||
* complete interrupt per packet basis.
|
* complete interrupt per packet basis.
|
||||||
* @has_single_clk_source: The i2c controller has single clock source. Tegra30
|
* @has_single_clk_source: The I2C controller has single clock source. Tegra30
|
||||||
* and earlier Socs has two clock sources i.e. div-clk and
|
* and earlier SoCs have two clock sources i.e. div-clk and
|
||||||
* fast-clk.
|
* fast-clk.
|
||||||
* @has_config_load_reg: Has the config load register to load the new
|
* @has_config_load_reg: Has the config load register to load the new
|
||||||
* configuration.
|
* configuration.
|
||||||
|
@ -154,8 +145,17 @@ enum msg_end_type {
|
||||||
* @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
|
* @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is
|
||||||
* applicable if there is no fast clock source i.e. single clock
|
* applicable if there is no fast clock source i.e. single clock
|
||||||
* source.
|
* source.
|
||||||
|
* @clk_divisor_fast_plus_mode: Clock divisor in fast mode plus. It is
|
||||||
|
* applicable if there is no fast clock source (i.e. single
|
||||||
|
* clock source).
|
||||||
|
* @has_multi_master_mode: The I2C controller supports running in single-master
|
||||||
|
* or multi-master mode.
|
||||||
|
* @has_slcg_override_reg: The I2C controller supports a register that
|
||||||
|
* overrides the second level clock gating.
|
||||||
|
* @has_mst_fifo: The I2C controller contains the new MST FIFO interface that
|
||||||
|
* provides additional features and allows for longer messages to
|
||||||
|
* be transferred in one go.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct tegra_i2c_hw_feature {
|
struct tegra_i2c_hw_feature {
|
||||||
bool has_continue_xfer_support;
|
bool has_continue_xfer_support;
|
||||||
bool has_per_pkt_xfer_complete_irq;
|
bool has_per_pkt_xfer_complete_irq;
|
||||||
|
@ -170,22 +170,27 @@ struct tegra_i2c_hw_feature {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct tegra_i2c_dev - per device i2c context
|
* struct tegra_i2c_dev - per device I2C context
|
||||||
* @dev: device reference for power management
|
* @dev: device reference for power management
|
||||||
* @hw: Tegra i2c hw feature.
|
* @hw: Tegra I2C HW feature
|
||||||
* @adapter: core i2c layer adapter information
|
* @adapter: core I2C layer adapter information
|
||||||
* @div_clk: clock reference for div clock of i2c controller.
|
* @div_clk: clock reference for div clock of I2C controller
|
||||||
* @fast_clk: clock reference for fast clock of i2c controller.
|
* @fast_clk: clock reference for fast clock of I2C controller
|
||||||
|
* @rst: reset control for the I2C controller
|
||||||
* @base: ioremapped registers cookie
|
* @base: ioremapped registers cookie
|
||||||
* @cont_id: i2c controller id, used for for packet header
|
* @cont_id: I2C controller ID, used for packet header
|
||||||
* @irq: irq number of transfer complete interrupt
|
* @irq: IRQ number of transfer complete interrupt
|
||||||
* @is_dvc: identifies the DVC i2c controller, has a different register layout
|
* @irq_disabled: used to track whether or not the interrupt is enabled
|
||||||
|
* @is_dvc: identifies the DVC I2C controller, has a different register layout
|
||||||
* @msg_complete: transfer completion notifier
|
* @msg_complete: transfer completion notifier
|
||||||
* @msg_err: error code for completed message
|
* @msg_err: error code for completed message
|
||||||
* @msg_buf: pointer to current message data
|
* @msg_buf: pointer to current message data
|
||||||
* @msg_buf_remaining: size of unsent data in the message buffer
|
* @msg_buf_remaining: size of unsent data in the message buffer
|
||||||
* @msg_read: identifies read transfers
|
* @msg_read: identifies read transfers
|
||||||
* @bus_clk_rate: current i2c bus clock rate
|
* @bus_clk_rate: current I2C bus clock rate
|
||||||
|
* @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
|
||||||
|
* @is_multimaster_mode: track if I2C controller is in multi-master mode
|
||||||
|
* @xfer_lock: lock to serialize transfer submission and processing
|
||||||
*/
|
*/
|
||||||
struct tegra_i2c_dev {
|
struct tegra_i2c_dev {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -608,11 +613,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
||||||
u32 status;
|
u32 status;
|
||||||
const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
||||||
struct tegra_i2c_dev *i2c_dev = dev_id;
|
struct tegra_i2c_dev *i2c_dev = dev_id;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
|
||||||
|
|
||||||
spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
|
spin_lock(&i2c_dev->xfer_lock);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
||||||
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
||||||
|
@ -670,7 +674,7 @@ err:
|
||||||
|
|
||||||
complete(&i2c_dev->msg_complete);
|
complete(&i2c_dev->msg_complete);
|
||||||
done:
|
done:
|
||||||
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
|
spin_unlock(&i2c_dev->xfer_lock);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ config EEPROM_AT24
|
||||||
ones like at24c64, 24lc02 or fm24c04:
|
ones like at24c64, 24lc02 or fm24c04:
|
||||||
|
|
||||||
24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
|
24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08,
|
||||||
24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024
|
24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024, 24c2048
|
||||||
|
|
||||||
Unless you like data loss puzzles, always be sure that any chip
|
Unless you like data loss puzzles, always be sure that any chip
|
||||||
you configure as a 24c32 (32 kbit) or larger is NOT really a
|
you configure as a 24c32 (32 kbit) or larger is NOT really a
|
||||||
|
|
|
@ -156,6 +156,7 @@ AT24_CHIP_DATA(at24_data_24c128, 131072 / 8, AT24_FLAG_ADDR16);
|
||||||
AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16);
|
AT24_CHIP_DATA(at24_data_24c256, 262144 / 8, AT24_FLAG_ADDR16);
|
||||||
AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16);
|
AT24_CHIP_DATA(at24_data_24c512, 524288 / 8, AT24_FLAG_ADDR16);
|
||||||
AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16);
|
AT24_CHIP_DATA(at24_data_24c1024, 1048576 / 8, AT24_FLAG_ADDR16);
|
||||||
|
AT24_CHIP_DATA(at24_data_24c2048, 2097152 / 8, AT24_FLAG_ADDR16);
|
||||||
/* identical to 24c08 ? */
|
/* identical to 24c08 ? */
|
||||||
AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
|
AT24_CHIP_DATA(at24_data_INT3499, 8192 / 8, 0);
|
||||||
|
|
||||||
|
@ -182,6 +183,7 @@ static const struct i2c_device_id at24_ids[] = {
|
||||||
{ "24c256", (kernel_ulong_t)&at24_data_24c256 },
|
{ "24c256", (kernel_ulong_t)&at24_data_24c256 },
|
||||||
{ "24c512", (kernel_ulong_t)&at24_data_24c512 },
|
{ "24c512", (kernel_ulong_t)&at24_data_24c512 },
|
||||||
{ "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
|
{ "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
|
||||||
|
{ "24c2048", (kernel_ulong_t)&at24_data_24c2048 },
|
||||||
{ "at24", 0 },
|
{ "at24", 0 },
|
||||||
{ /* END OF LIST */ }
|
{ /* END OF LIST */ }
|
||||||
};
|
};
|
||||||
|
@ -210,6 +212,7 @@ static const struct of_device_id at24_of_match[] = {
|
||||||
{ .compatible = "atmel,24c256", .data = &at24_data_24c256 },
|
{ .compatible = "atmel,24c256", .data = &at24_data_24c256 },
|
||||||
{ .compatible = "atmel,24c512", .data = &at24_data_24c512 },
|
{ .compatible = "atmel,24c512", .data = &at24_data_24c512 },
|
||||||
{ .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
|
{ .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
|
||||||
|
{ .compatible = "atmel,24c2048", .data = &at24_data_24c2048 },
|
||||||
{ /* END OF LIST */ },
|
{ /* END OF LIST */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, at24_of_match);
|
MODULE_DEVICE_TABLE(of, at24_of_match);
|
||||||
|
|
Loading…
Reference in New Issue