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,24c512",
|
||||
"atmel,24c1024",
|
||||
"atmel,24c2048",
|
||||
|
||||
If <manufacturer> is not "atmel", then a fallback must be used
|
||||
with the same <model> and "atmel" as manufacturer.
|
||||
|
|
|
@ -33,7 +33,7 @@ i2c0: i2c@fff84000 {
|
|||
clock-frequency = <400000>;
|
||||
|
||||
24c512@50 {
|
||||
compatible = "24c512";
|
||||
compatible = "atmel,24c512";
|
||||
reg = <0x50>;
|
||||
pagesize = <128>;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ Example:
|
|||
reg = <0>;
|
||||
|
||||
eeprom@50 {
|
||||
compatible = "at,24c02";
|
||||
compatible = "atmel,24c02";
|
||||
reg = <0x50>;
|
||||
};
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ Example:
|
|||
reg = <1>;
|
||||
|
||||
eeprom@50 {
|
||||
compatible = "at,24c02";
|
||||
compatible = "atmel,24c02";
|
||||
reg = <0x50>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -54,7 +54,7 @@ Example:
|
|||
reg = <2>;
|
||||
|
||||
eeprom@54 {
|
||||
compatible = "at,24c08";
|
||||
compatible = "atmel,24c08";
|
||||
reg = <0x54>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,7 +2,9 @@ Actions Semiconductor Owl I2C controller
|
|||
|
||||
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.
|
||||
- #address-cells : Should be 1.
|
||||
- #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-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-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-r8a7779" if the device is a part of a R8A7779 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-r8a7745" (RZ/G1E)
|
||||
- "renesas,iic-r8a774a1" (RZ/G2M)
|
||||
- "renesas,iic-r8a774c0" (RZ/G2E)
|
||||
- "renesas,iic-r8a7790" (R-Car H2)
|
||||
- "renesas,iic-r8a7791" (R-Car M2-W)
|
||||
- "renesas,iic-r8a7792" (R-Car V2H)
|
||||
|
@ -16,6 +17,7 @@ Required properties:
|
|||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-r8a77965" (R-Car M3-N)
|
||||
- "renesas,iic-r8a77990" (R-Car E3)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 or RZ/G1
|
||||
compatible device)
|
||||
|
@ -28,7 +30,13 @@ Required properties:
|
|||
the platform first followed by the generic R-Car
|
||||
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
|
||||
- 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
|
||||
(default: 10)
|
||||
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 :
|
||||
|
||||
|
@ -53,4 +58,5 @@ Example :
|
|||
clocks = <&rcc 1 CLK_I2C1>;
|
||||
pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
|
||||
pinctrl-names = "default";
|
||||
st,syscfg-fmp = <&syscfg 0x4 0x1>;
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ Example:
|
|||
#size-cells = <0>;
|
||||
|
||||
eeprom@54 {
|
||||
compatible = "at,24c08";
|
||||
compatible = "atmel,24c08";
|
||||
reg = <0x54>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -25,6 +26,7 @@
|
|||
#define I2C_XFER_TIMEOUT (msecs_to_jiffies(250))
|
||||
#define I2C_STOP_TIMEOUT (msecs_to_jiffies(100))
|
||||
#define FIFO_SIZE 8
|
||||
#define SEQ_LEN 2
|
||||
|
||||
#define GLOBAL_CONTROL 0x00
|
||||
#define GLOBAL_MST_EN BIT(0)
|
||||
|
@ -51,6 +53,7 @@
|
|||
#define CMD_BUSY (1<<3)
|
||||
#define CMD_MANUAL (0x00 | CMD_BUSY)
|
||||
#define CMD_AUTO (0x01 | CMD_BUSY)
|
||||
#define CMD_SEQUENCE (0x02 | CMD_BUSY)
|
||||
#define MST_RX_XFER 0x2c
|
||||
#define MST_TX_XFER 0x30
|
||||
#define MST_ADDR_1 0x34
|
||||
|
@ -87,7 +90,9 @@
|
|||
* axxia_i2c_dev - I2C device context
|
||||
* @base: pointer to register struct
|
||||
* @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_complete: xfer completion object
|
||||
* @dev: device reference
|
||||
|
@ -98,7 +103,9 @@
|
|||
struct axxia_i2c_dev {
|
||||
void __iomem *base;
|
||||
struct i2c_msg *msg;
|
||||
struct i2c_msg *msg_r;
|
||||
size_t msg_xfrd;
|
||||
size_t msg_xfrd_r;
|
||||
int msg_err;
|
||||
struct completion msg_complete;
|
||||
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)
|
||||
{
|
||||
struct i2c_msg *msg = idev->msg;
|
||||
struct i2c_msg *msg = idev->msg_r;
|
||||
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) {
|
||||
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
|
||||
*/
|
||||
|
@ -247,7 +254,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev)
|
|||
msg->len = 1 + c;
|
||||
writel(msg->len, idev->base + MST_RX_XFER);
|
||||
}
|
||||
msg->buf[idev->msg_xfrd++] = c;
|
||||
msg->buf[idev->msg_xfrd_r++] = c;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -287,7 +294,7 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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) && 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)) {
|
||||
if (unlikely(status & MST_STATUS_ERR)) {
|
||||
/* Transfer error */
|
||||
i2c_int_disable(idev, ~0);
|
||||
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_XFER));
|
||||
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:
|
||||
|
@ -337,17 +347,9 @@ static irqreturn_t axxia_i2c_isr(int irq, void *_dev)
|
|||
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;
|
||||
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)) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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)) {
|
||||
/* I2C read transfer */
|
||||
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(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))
|
||||
int_mask |= MST_STATUS_RFL;
|
||||
|
@ -445,6 +529,18 @@ static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
|
|||
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
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; ret == 0 && i < num; ++i)
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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>
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Google, Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* 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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Expose an I2C passthrough to the ChromeOS EC.
|
||||
//
|
||||
// Copyright (C) 2013 Google, Inc.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
|
|
|
@ -437,7 +437,7 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){
|
|||
break;
|
||||
}
|
||||
|
||||
if (unlikely(signal_pending(current))){
|
||||
if (signal_pending(current)){
|
||||
DBG("%d: poll interrupted\n", dev->idx);
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
|
|
|
@ -1090,7 +1090,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
/* Get I2C clock */
|
||||
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
/* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */
|
||||
#define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59
|
||||
#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_AVOTON_SMT 0x1f15
|
||||
|
||||
|
@ -181,6 +182,7 @@ struct ismt_priv {
|
|||
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_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_AVOTON_SMT) },
|
||||
{ 0, }
|
||||
|
|
|
@ -475,6 +475,7 @@ static int owl_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id owl_i2c_of_match[] = {
|
||||
{ .compatible = "actions,s700-i2c" },
|
||||
{ .compatible = "actions,s900-i2c" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
|
|
@ -229,9 +229,9 @@ static u32 i2c_powermac_get_addr(struct i2c_adapter *adap,
|
|||
return (be32_to_cpup(prop) & 0xff) >> 1;
|
||||
|
||||
/* Now handle some devices with missing "reg" properties */
|
||||
if (!strcmp(node->name, "cereal"))
|
||||
if (of_node_name_eq(node, "cereal"))
|
||||
return 0x60;
|
||||
else if (!strcmp(node->name, "deq"))
|
||||
else if (of_node_name_eq(node, "deq"))
|
||||
return 0x34;
|
||||
|
||||
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 */
|
||||
if (!strcmp(node->name, "deq")) {
|
||||
if (of_node_name_eq(node, "deq")) {
|
||||
/* Apple uses address 0x34 for TAS3001 and 0x35 for TAS3004 */
|
||||
if (addr == 0x34) {
|
||||
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
|
||||
* 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;
|
||||
|
||||
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[] = {
|
||||
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_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-r8a7791", .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,iic-r8a7795", .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,rmobile-iic", .data = &default_dt_config },
|
||||
{},
|
||||
|
|
|
@ -21,12 +21,16 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.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/slab.h>
|
||||
|
||||
|
@ -163,6 +167,8 @@
|
|||
#define STM32F7_SCLH_MAX BIT(8)
|
||||
#define STM32F7_SCLL_MAX BIT(8)
|
||||
|
||||
#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100)
|
||||
|
||||
/**
|
||||
* struct stm32f7_i2c_spec - private i2c specification timing
|
||||
* @rate: I2C bus speed (Hz)
|
||||
|
@ -276,6 +282,7 @@ struct stm32f7_i2c_msg {
|
|||
* slave)
|
||||
* @dma: dma data
|
||||
* @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 i2c_adapter adap;
|
||||
|
@ -296,6 +303,7 @@ struct stm32f7_i2c_dev {
|
|||
bool master_mode;
|
||||
struct stm32_i2c_dma *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;
|
||||
f7_msg->smbus = false;
|
||||
|
||||
ret = clk_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Failed to enable clock\n");
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
|
||||
stm32f7_i2c_xfer_msg(i2c_dev, msgs);
|
||||
|
||||
|
@ -1569,8 +1575,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
|
|||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
clk_free:
|
||||
clk_disable(i2c_dev->clk);
|
||||
pm_free:
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||
|
||||
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->smbus = true;
|
||||
|
||||
ret = clk_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
dev_err(i2c_dev->dev, "Failed to enable clock\n");
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stm32f7_i2c_wait_free_bus(i2c_dev);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
|
||||
ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
|
||||
timeout = wait_for_completion_timeout(&i2c_dev->complete,
|
||||
i2c_dev->adap.timeout);
|
||||
ret = f7_msg->result;
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
|
||||
if (!timeout) {
|
||||
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
|
||||
if (i2c_dev->use_dma)
|
||||
dmaengine_terminate_all(dma->chan_using);
|
||||
ret = -ETIMEDOUT;
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
}
|
||||
|
||||
/* Check PEC */
|
||||
if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) {
|
||||
ret = stm32f7_i2c_smbus_check_pec(i2c_dev);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
goto pm_free;
|
||||
}
|
||||
|
||||
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:
|
||||
clk_disable(i2c_dev->clk);
|
||||
pm_free:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1676,13 +1682,9 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(stm32f7_i2c_is_slave_registered(i2c_dev))) {
|
||||
ret = clk_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (id == 0) {
|
||||
/* Configure Own Address 1 */
|
||||
|
@ -1703,7 +1705,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
|||
oar2 &= ~STM32F7_I2C_OAR2_MASK;
|
||||
if (slave->flags & I2C_CLIENT_TEN) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
goto pm_free;
|
||||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
goto exit;
|
||||
goto pm_free;
|
||||
}
|
||||
|
||||
/* Enable ACK */
|
||||
|
@ -1723,11 +1725,10 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave)
|
|||
STM32F7_I2C_CR1_PE;
|
||||
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
if (!(stm32f7_i2c_is_slave_registered(i2c_dev)))
|
||||
clk_disable(i2c_dev->clk);
|
||||
ret = 0;
|
||||
pm_free:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1745,6 +1746,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave)
|
|||
|
||||
WARN_ON(!i2c_dev->slave[id]);
|
||||
|
||||
ret = pm_runtime_get_sync(i2c_dev->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (id == 0) {
|
||||
mask = STM32F7_I2C_OAR1_OA1EN;
|
||||
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;
|
||||
|
||||
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);
|
||||
clk_disable(i2c_dev->clk);
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||
|
||||
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)
|
||||
{
|
||||
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");
|
||||
return PTR_ERR(i2c_dev->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(i2c_dev->clk);
|
||||
if (ret) {
|
||||
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;
|
||||
ret = device_property_read_u32(&pdev->dev, "clock-frequency",
|
||||
&clk_rate);
|
||||
if (!ret && clk_rate >= 1000000)
|
||||
if (!ret && clk_rate >= 1000000) {
|
||||
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;
|
||||
else if (!ret && clk_rate >= 100000)
|
||||
} else if (!ret && clk_rate >= 100000) {
|
||||
i2c_dev->speed = STM32_I2C_SPEED_STANDARD;
|
||||
}
|
||||
|
||||
rst = devm_reset_control_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(rst)) {
|
||||
|
@ -1888,8 +1923,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto clk_free;
|
||||
|
||||
stm32f7_i2c_hw_config(i2c_dev);
|
||||
|
||||
adap = &i2c_dev->adap;
|
||||
i2c_set_adapdata(adap, i2c_dev);
|
||||
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_RXDR);
|
||||
|
||||
ret = i2c_add_adapter(adap);
|
||||
if (ret)
|
||||
goto clk_free;
|
||||
|
||||
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);
|
||||
|
||||
pm_runtime_mark_last_busy(i2c_dev->dev);
|
||||
pm_runtime_put_autosuspend(i2c_dev->dev);
|
||||
|
||||
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_disable_unprepare(i2c_dev->clk);
|
||||
|
||||
|
@ -1936,12 +1986,51 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#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[] = {
|
||||
{ .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup},
|
||||
{},
|
||||
|
@ -1952,6 +2041,7 @@ static struct platform_driver stm32f7_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "stm32f7-i2c",
|
||||
.of_match_table = stm32f7_i2c_match,
|
||||
.pm = &stm32f7_i2c_pm_ops,
|
||||
},
|
||||
.probe = stm32f7_i2c_probe,
|
||||
.remove = stm32f7_i2c_remove,
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/i2c/busses/i2c-tegra.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
* 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>
|
||||
|
@ -145,8 +136,8 @@ enum msg_end_type {
|
|||
* @has_continue_xfer_support: Continue transfer supports.
|
||||
* @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer
|
||||
* complete interrupt per packet basis.
|
||||
* @has_single_clk_source: The i2c controller has single clock source. Tegra30
|
||||
* and earlier Socs has two clock sources i.e. div-clk and
|
||||
* @has_single_clk_source: The I2C controller has single clock source. Tegra30
|
||||
* and earlier SoCs have two clock sources i.e. div-clk and
|
||||
* fast-clk.
|
||||
* @has_config_load_reg: Has the config load register to load the new
|
||||
* configuration.
|
||||
|
@ -154,8 +145,17 @@ enum msg_end_type {
|
|||
* @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
|
||||
* 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 {
|
||||
bool has_continue_xfer_support;
|
||||
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
|
||||
* @hw: Tegra i2c hw feature.
|
||||
* @adapter: core i2c layer adapter information
|
||||
* @div_clk: clock reference for div clock of i2c controller.
|
||||
* @fast_clk: clock reference for fast clock of i2c controller.
|
||||
* @hw: Tegra I2C HW feature
|
||||
* @adapter: core I2C layer adapter information
|
||||
* @div_clk: clock reference for div 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
|
||||
* @cont_id: i2c controller id, used for for packet header
|
||||
* @irq: irq number of transfer complete interrupt
|
||||
* @is_dvc: identifies the DVC i2c controller, has a different register layout
|
||||
* @cont_id: I2C controller ID, used for packet header
|
||||
* @irq: IRQ number of transfer complete interrupt
|
||||
* @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_err: error code for completed message
|
||||
* @msg_buf: pointer to current message data
|
||||
* @msg_buf_remaining: size of unsent data in the message buffer
|
||||
* @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 device *dev;
|
||||
|
@ -608,11 +613,10 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
u32 status;
|
||||
const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
|
||||
struct tegra_i2c_dev *i2c_dev = dev_id;
|
||||
unsigned long flags;
|
||||
|
||||
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) {
|
||||
dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
|
||||
i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
|
||||
|
@ -670,7 +674,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
|
|||
|
||||
complete(&i2c_dev->msg_complete);
|
||||
done:
|
||||
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
|
||||
spin_unlock(&i2c_dev->xfer_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ config EEPROM_AT24
|
|||
ones like at24c64, 24lc02 or fm24c04:
|
||||
|
||||
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
|
||||
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_24c512, 524288 / 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 ? */
|
||||
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 },
|
||||
{ "24c512", (kernel_ulong_t)&at24_data_24c512 },
|
||||
{ "24c1024", (kernel_ulong_t)&at24_data_24c1024 },
|
||||
{ "24c2048", (kernel_ulong_t)&at24_data_24c2048 },
|
||||
{ "at24", 0 },
|
||||
{ /* 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,24c512", .data = &at24_data_24c512 },
|
||||
{ .compatible = "atmel,24c1024", .data = &at24_data_24c1024 },
|
||||
{ .compatible = "atmel,24c2048", .data = &at24_data_24c2048 },
|
||||
{ /* END OF LIST */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at24_of_match);
|
||||
|
|
Loading…
Reference in New Issue