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:
Linus Torvalds 2019-01-05 18:13:35 -08:00
commit 7671c14e6a
22 changed files with 346 additions and 137 deletions

View File

@ -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.

View File

@ -33,7 +33,7 @@ i2c0: i2c@fff84000 {
clock-frequency = <400000>;
24c512@50 {
compatible = "24c512";
compatible = "atmel,24c512";
reg = <0x50>;
pagesize = <128>;
}

View File

@ -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>;
};
};

View File

@ -54,7 +54,7 @@ Example:
reg = <2>;
eeprom@54 {
compatible = "at,24c08";
compatible = "atmel,24c08";
reg = <0x54>;
};
};

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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>;
};

View File

@ -22,7 +22,7 @@ Example:
#size-cells = <0>;
eeprom@54 {
compatible = "at,24c08";
compatible = "atmel,24c08";
reg = <0x54>;
};
};

View File

@ -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 @@ out:
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)

View File

@ -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>

View File

@ -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>

View File

@ -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;

View File

@ -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);
}

View File

@ -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, }

View File

@ -475,6 +475,7 @@ disable_clk:
}
static const struct of_device_id owl_i2c_of_match[] = {
{ .compatible = "actions,s700-i2c" },
{ .compatible = "actions,s900-i2c" },
{ /* sentinel */ }
};

View File

@ -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) {

View File

@ -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 },
{},

View File

@ -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, &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)
{
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,

View File

@ -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 @@ err:
complete(&i2c_dev->msg_complete);
done:
spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
spin_unlock(&i2c_dev->xfer_lock);
return IRQ_HANDLED;
}

View File

@ -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

View File

@ -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);