Commit 7671c14e authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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)
  ...
parents 926b02d3 81482d13
...@@ -27,6 +27,7 @@ Required properties: ...@@ -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 { ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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 ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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 : ...@@ -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 : ...@@ -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: ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev) ...@@ -337,17 +347,9 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
// 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>
......
/* // 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){ ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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 @@ static int owl_i2c_probe(struct platform_device *pdev) ...@@ -475,6 +475,7 @@ static int owl_i2c_probe(struct platform_device *pdev)
} }
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, ...@@ -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, ...@@ -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, ...@@ -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 = { ...@@ -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[] = { ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, &reg);
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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,11 +1986,50 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) ...@@ -1936,11 +1986,50 @@ 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;
}
#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; 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 = { ...@@ -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,
......
// 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 { ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) ...@@ -670,7 +674,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
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;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment