Merge branch 'i2c/for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:

 - the I2C core gained helpers to assist drivers in handling their
   suspended state, and drivers were converted to use it

 - two new fault-injectors for stress-testing

 - bigger refactoring and feature improvements for the ocores,
   sh_mobile, and tegra drivers

 - platform_data removal for the at24 EEPROM driver

 - ... and various improvements and bugfixes all over the subsystem

* 'i2c/for-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (69 commits)
  i2c: Allow recovery of the initial IRQ by an I2C client device.
  i2c: ocores: turn incomplete kdoc into a comment
  i2c: designware: Do not allow i2c_dw_xfer() calls while suspended
  i2c: tegra: Only display error messages if DMA setup fails
  i2c: gpio: fault-injector: add 'inject_panic' injector
  i2c: gpio: fault-injector: add 'lose_arbitration' injector
  i2c: tegra: remove multi-master support
  i2c: tegra: remove master fifo support on tegra186
  i2c: tegra: change phrasing, "fallbacking" to "falling back"
  i2c: expand minor range when registering chrdev region
  i2c: aspeed: Add multi-master use case support
  i2c: core-smbus: don't trace smbus_reply data on errors
  i2c: ocores: Add support for bus clock via platform data
  i2c: ocores: Add support for IO mapper registers.
  i2c: ocores: checkpatch fixes
  i2c: ocores: add SPDX tag
  i2c: ocores: add polling interface
  i2c: ocores: do not handle IRQ if IF is not set
  i2c: ocores: stop transfer on timeout
  i2c: tegra: add i2c interface timing support
  ...
This commit is contained in:
Linus Torvalds 2019-03-08 09:27:33 -08:00
commit 6c3f98fadd
40 changed files with 1562 additions and 662 deletions

View File

@ -75,6 +75,8 @@ Optional properties:
- address-width: number of address bits (one of 8, 16).
- num-addresses: total number of i2c slave addresses this device takes
Example:
eeprom@52 {
@ -82,4 +84,5 @@ eeprom@52 {
reg = <0x52>;
pagesize = <32>;
wp-gpios = <&gpio1 3 0>;
num-addresses = <8>;
};

View File

@ -10,6 +10,7 @@ Required properties:
"mediatek,mt6589-i2c": for MediaTek MT6589
"mediatek,mt7622-i2c": for MediaTek MT7622
"mediatek,mt7623-i2c", "mediatek,mt6577-i2c": for MediaTek MT7623
"mediatek,mt7629-i2c", "mediatek,mt2712-i2c": for MediaTek MT7629
"mediatek,mt8173-i2c": for MediaTek MT8173
- reg: physical base address of the controller and dma base, length of memory
mapped region.

View File

@ -0,0 +1,20 @@
i2c Controller on XScale platforms such as IOP3xx and IXP4xx
Required properties:
- compatible : Must be one of
"intel,iop3xx-i2c"
"intel,ixp4xx-i2c";
- reg
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties:
- Child nodes conforming to i2c bus binding
Example:
i2c@c8011000 {
compatible = "intel,ixp4xx-i2c";
reg = <0xc8011000 0x18>;
interrupts = <33 IRQ_TYPE_LEVEL_LOW>;
};

View File

@ -112,6 +112,10 @@ EPROTO
case is when the length of an SMBus block data response
(from the SMBus slave) is outside the range 1-32 bytes.
ESHUTDOWN
Returned when a transfer was requested using an adapter
which is already suspended.
ETIMEDOUT
This is returned by drivers when an operation took too much
time, and was aborted before it completed.

View File

@ -1,3 +1,4 @@
=========================
Linux I2C fault injection
=========================
@ -13,6 +14,9 @@ mounted at /sys/kernel/debug. There will be a separate subdirectory per GPIO
driven I2C bus. Each subdirectory will contain files to trigger the fault
injection. They will be described now along with their intended use-cases.
Wire states
===========
"scl"
-----
@ -34,10 +38,10 @@ I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C
core (see 'struct bus_recovery_info'). However, the bus recovery will not
succeed because SDA is still pinned low until you manually release it again
with "echo 1 > sda". A test with an automatic release can be done with the
following class of fault injectors.
"incomplete transfers" class of fault injectors.
Introduction to incomplete transfers
------------------------------------
Incomplete transfers
====================
The following fault injectors create situations where SDA will be held low by a
device. Bus recovery should be able to fix these situations. But please note:
@ -79,3 +83,54 @@ This is why bus recovery (up to 9 clock pulses) must either check SDA or send
additional STOP conditions to ensure the bus has been released. Otherwise
random data will be written to a device!
Lost arbitration
================
Here, we want to simulate the condition where the master under test loses the
bus arbitration against another master in a multi-master setup.
"lose_arbitration"
------------------
This file is write only and you need to write the duration of the arbitration
intereference (in µs, maximum is 100ms). The calling process will then sleep
and wait for the next bus clock. The process is interruptible, though.
Arbitration lost is achieved by waiting for SCL going down by the master under
test and then pulling SDA low for some time. So, the I2C address sent out
should be corrupted and that should be detected properly. That means that the
address sent out should have a lot of '1' bits to be able to detect corruption.
There doesn't need to be a device at this address because arbitration lost
should be detected beforehand. Also note, that SCL going down is monitored
using interrupts, so the interrupt latency might cause the first bits to be not
corrupted. A good starting point for using this fault injector on an otherwise
idle bus is:
# echo 200 > lose_arbitration &
# i2cget -y <bus_to_test> 0x3f
Panic during transfer
=====================
This fault injector will create a Kernel panic once the master under test
started a transfer. This usually means that the state machine of the bus master
driver will be ungracefully interrupted and the bus may end up in an unusual
state. Use this to check if your shutdown/reboot/boot code can handle this
scenario.
"inject_panic"
--------------
This file is write only and you need to write the delay between the detected
start of a transmission and the induced Kernel panic (in µs, maximum is 100ms).
The calling process will then sleep and wait for the next bus clock. The
process is interruptible, though.
Start of a transfer is detected by waiting for SCL going down by the master
under test. A good starting point for using this fault injector is:
# echo 0 > inject_panic &
# i2cget -y <bus_to_test> <some_address>
Note that there doesn't need to be a device listening to the address you are
using. Results may vary depending on that, though.

View File

@ -2554,7 +2554,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
S: Maintained
F: Documentation/devicetree/bindings/eeprom/at24.txt
F: drivers/misc/eeprom/at24.c
F: include/linux/platform_data/at24.h
ATA OVER ETHERNET (AOE) DRIVER
M: "Ed L. Cashin" <ed.cashin@acm.org>

View File

@ -10,6 +10,7 @@
#include <linux/clkdev.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mutex.h>
@ -25,7 +26,6 @@
#include <linux/platform_data/keypad-omap.h>
#include <linux/platform_data/lcd-mipid.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/i2c-cbus-gpio.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@ -217,18 +217,19 @@ static inline void nokia770_mmc_init(void)
#endif
#if IS_ENABLED(CONFIG_I2C_CBUS_GPIO)
static struct i2c_cbus_platform_data nokia770_cbus_data = {
.clk_gpio = OMAP_MPUIO(9),
.dat_gpio = OMAP_MPUIO(10),
.sel_gpio = OMAP_MPUIO(11),
static struct gpiod_lookup_table nokia770_cbus_gpio_table = {
.dev_id = "i2c-cbus-gpio.2",
.table = {
GPIO_LOOKUP_IDX("mpuio", 9, NULL, 0, 0), /* clk */
GPIO_LOOKUP_IDX("mpuio", 10, NULL, 1, 0), /* dat */
GPIO_LOOKUP_IDX("mpuio", 11, NULL, 2, 0), /* sel */
{ },
},
};
static struct platform_device nokia770_cbus_device = {
.name = "i2c-cbus-gpio",
.id = 2,
.dev = {
.platform_data = &nokia770_cbus_data,
},
};
static struct i2c_board_info nokia770_i2c_board_info_2[] __initdata = {
@ -257,6 +258,7 @@ static void __init nokia770_cbus_init(void)
nokia770_i2c_board_info_2[1].irq = gpio_to_irq(tahvo_irq_gpio);
i2c_register_board_info(2, nokia770_i2c_board_info_2,
ARRAY_SIZE(nokia770_i2c_board_info_2));
gpiod_add_lookup_table(&nokia770_cbus_gpio_table);
platform_device_register(&nokia770_cbus_device);
}
#else /* CONFIG_I2C_CBUS_GPIO */

View File

@ -1,21 +1,12 @@
/* -------------------------------------------------------------------------
* i2c-algo-bit.c i2c driver algorithms for bit-shift adapters
* -------------------------------------------------------------------------
// SPDX-License-Identifier: GPL-2.0+
/*
* i2c-algo-bit.c: i2c driver algorithms for bit-shift adapters
*
* Copyright (C) 1995-2000 Simon G. Vogl
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.
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.
* ------------------------------------------------------------------------- */
/* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
<kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de> */
*
* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
* <kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de>
*/
#include <linux/kernel.h>
#include <linux/module.h>

View File

@ -117,6 +117,7 @@
enum aspeed_i2c_master_state {
ASPEED_I2C_MASTER_INACTIVE,
ASPEED_I2C_MASTER_PENDING,
ASPEED_I2C_MASTER_START,
ASPEED_I2C_MASTER_TX_FIRST,
ASPEED_I2C_MASTER_TX,
@ -126,12 +127,13 @@ enum aspeed_i2c_master_state {
};
enum aspeed_i2c_slave_state {
ASPEED_I2C_SLAVE_STOP,
ASPEED_I2C_SLAVE_INACTIVE,
ASPEED_I2C_SLAVE_START,
ASPEED_I2C_SLAVE_READ_REQUESTED,
ASPEED_I2C_SLAVE_READ_PROCESSED,
ASPEED_I2C_SLAVE_WRITE_REQUESTED,
ASPEED_I2C_SLAVE_WRITE_RECEIVED,
ASPEED_I2C_SLAVE_STOP,
};
struct aspeed_i2c_bus {
@ -156,6 +158,8 @@ struct aspeed_i2c_bus {
int cmd_err;
/* Protected only by i2c_lock_bus */
int master_xfer_result;
/* Multi-master */
bool multi_master;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
struct i2c_client *slave;
enum aspeed_i2c_slave_state slave_state;
@ -251,7 +255,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
}
/* Slave is not currently active, irq was for someone else. */
if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
return irq_handled;
dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
@ -277,16 +281,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
}
if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
}
if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
switch (bus->slave_state) {
case ASPEED_I2C_SLAVE_READ_REQUESTED:
if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))
dev_err(bus->dev, "Unexpected ACK on read request.\n");
bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
@ -294,9 +297,12 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
break;
case ASPEED_I2C_SLAVE_READ_PROCESSED:
if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
dev_err(bus->dev,
"Expected ACK after processed read.\n");
break;
}
irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
@ -310,10 +316,15 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
break;
case ASPEED_I2C_SLAVE_STOP:
i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
break;
case ASPEED_I2C_SLAVE_START:
/* Slave was just started. Waiting for the next event. */;
break;
default:
dev_err(bus->dev, "unhandled slave_state: %d\n",
dev_err(bus->dev, "unknown slave_state: %d\n",
bus->slave_state);
bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
break;
}
@ -329,6 +340,17 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
u8 slave_addr = i2c_8bit_addr_from_msg(msg);
bus->master_state = ASPEED_I2C_MASTER_START;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/*
* If it's requested in the middle of a slave session, set the master
* state to 'pending' then H/W will continue handling this master
* command when the bus comes back to the idle state.
*/
if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
bus->master_state = ASPEED_I2C_MASTER_PENDING;
#endif /* CONFIG_I2C_SLAVE */
bus->buf_index = 0;
if (msg->flags & I2C_M_RD) {
@ -384,10 +406,6 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
goto out_complete;
} else {
/* Master is not currently active, irq was for someone else. */
if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
goto out_no_complete;
}
/*
@ -399,11 +417,32 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
if (ret) {
dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
irq_status);
irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
bus->cmd_err = ret;
bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
goto out_complete;
}
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/*
* A pending master command will be started by H/W when the bus comes
* back to idle state after completing a slave operation so change the
* master state from 'pending' to 'start' at here if slave is inactive.
*/
if (bus->master_state == ASPEED_I2C_MASTER_PENDING) {
if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
goto out_no_complete;
bus->master_state = ASPEED_I2C_MASTER_START;
}
#endif /* CONFIG_I2C_SLAVE */
/* Master is not currently active, irq was for someone else. */
if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE ||
bus->master_state == ASPEED_I2C_MASTER_PENDING)
goto out_no_complete;
/* We are in an invalid state; reset bus to a known state. */
if (!bus->msgs) {
@ -423,6 +462,20 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
* then update the state and handle the new state below.
*/
if (bus->master_state == ASPEED_I2C_MASTER_START) {
#if IS_ENABLED(CONFIG_I2C_SLAVE)
/*
* If a peer master starts a xfer immediately after it queues a
* master command, change its state to 'pending' then H/W will
* continue the queued master xfer just after completing the
* slave mode session.
*/
if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) {
bus->master_state = ASPEED_I2C_MASTER_PENDING;
dev_dbg(bus->dev,
"master goes pending due to a slave start\n");
goto out_no_complete;
}
#endif /* CONFIG_I2C_SLAVE */
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
bus->cmd_err = -ENXIO;
@ -566,7 +619,8 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
* interrupt bits. Each case needs to be handled using corresponding
* handlers depending on the current state.
*/
if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE &&
bus->master_state != ASPEED_I2C_MASTER_PENDING) {
irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
irq_remaining &= ~irq_handled;
if (irq_remaining)
@ -601,15 +655,16 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
{
struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
unsigned long time_left, flags;
int ret = 0;
spin_lock_irqsave(&bus->lock, flags);
bus->cmd_err = 0;
/* If bus is busy, attempt recovery. We assume a single master
* environment.
*/
if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) {
/* If bus is busy in a single master environment, attempt recovery. */
if (!bus->multi_master &&
(readl(bus->base + ASPEED_I2C_CMD_REG) &
ASPEED_I2CD_BUS_BUSY_STS)) {
int ret;
spin_unlock_irqrestore(&bus->lock, flags);
ret = aspeed_i2c_recover_bus(bus);
if (ret)
@ -629,9 +684,19 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
time_left = wait_for_completion_timeout(&bus->cmd_complete,
bus->adap.timeout);
if (time_left == 0)
if (time_left == 0) {
/*
* If timed out and bus is still busy in a multi master
* environment, attempt recovery at here.
*/
if (bus->multi_master &&
(readl(bus->base + ASPEED_I2C_CMD_REG) &
ASPEED_I2CD_BUS_BUSY_STS))
aspeed_i2c_recover_bus(bus);
return -ETIMEDOUT;
else
}
return bus->master_xfer_result;
}
@ -672,7 +737,7 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client)
__aspeed_i2c_reg_slave(bus, client->addr);
bus->slave = client;
bus->slave_state = ASPEED_I2C_SLAVE_STOP;
bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
spin_unlock_irqrestore(&bus->lock, flags);
return 0;
@ -827,7 +892,9 @@ static int aspeed_i2c_init(struct aspeed_i2c_bus *bus,
if (ret < 0)
return ret;
if (!of_property_read_bool(pdev->dev.of_node, "multi-master"))
if (of_property_read_bool(pdev->dev.of_node, "multi-master"))
bus->multi_master = true;
else
fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS;
/* Enable Master Mode */
@ -930,7 +997,6 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev)
init_completion(&bus->cmd_complete);
bus->adap.owner = THIS_MODULE;
bus->adap.retries = 0;
bus->adap.timeout = 5 * HZ;
bus->adap.algo = &aspeed_i2c_algo;
bus->adap.dev.parent = &pdev->dev;
bus->adap.dev.of_node = pdev->dev.of_node;

View File

@ -170,7 +170,6 @@ struct brcmstb_i2c_dev {
struct bsc_regs *bsc_regmap;
struct i2c_adapter adapter;
struct completion done;
bool is_suspended;
u32 clk_freq_hz;
int data_regsz;
};
@ -467,9 +466,6 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
int xfersz = brcmstb_i2c_get_xfersz(dev);
u32 cond, cond_per_msg;
if (dev->is_suspended)
return -EBUSY;
/* Loop through all messages */
for (i = 0; i < num; i++) {
pmsg = &msgs[i];
@ -689,10 +685,7 @@ static int brcmstb_i2c_suspend(struct device *dev)
{
struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = true;
i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
i2c_mark_adapter_suspended(&i2c_dev->adapter);
return 0;
}
@ -700,10 +693,8 @@ static int brcmstb_i2c_resume(struct device *dev)
{
struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev);
i2c_lock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
brcmstb_i2c_set_bsc_reg_defaults(i2c_dev);
i2c_dev->is_suspended = false;
i2c_unlock_bus(&i2c_dev->adapter, I2C_LOCK_ROOT_ADAPTER);
i2c_mark_adapter_resumed(&i2c_dev->adapter);
return 0;
}

View File

@ -18,16 +18,14 @@
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-cbus-gpio.h>
/*
* Bit counts are derived from Nokia implementation. These should be checked
@ -39,9 +37,9 @@
struct cbus_host {
spinlock_t lock; /* host lock */
struct device *dev;
int clk_gpio;
int dat_gpio;
int sel_gpio;
struct gpio_desc *clk;
struct gpio_desc *dat;
struct gpio_desc *sel;
};
/**
@ -51,9 +49,9 @@ struct cbus_host {
*/
static void cbus_send_bit(struct cbus_host *host, unsigned bit)
{
gpio_set_value(host->dat_gpio, bit ? 1 : 0);
gpio_set_value(host->clk_gpio, 1);
gpio_set_value(host->clk_gpio, 0);
gpiod_set_value(host->dat, bit ? 1 : 0);
gpiod_set_value(host->clk, 1);
gpiod_set_value(host->clk, 0);
}
/**
@ -78,9 +76,9 @@ static int cbus_receive_bit(struct cbus_host *host)
{
int ret;
gpio_set_value(host->clk_gpio, 1);
ret = gpio_get_value(host->dat_gpio);
gpio_set_value(host->clk_gpio, 0);
gpiod_set_value(host->clk, 1);
ret = gpiod_get_value(host->dat);
gpiod_set_value(host->clk, 0);
return ret;
}
@ -123,10 +121,10 @@ static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
spin_lock_irqsave(&host->lock, flags);
/* Reset state and start of transfer, SEL stays down during transfer */
gpio_set_value(host->sel_gpio, 0);
gpiod_set_value(host->sel, 0);
/* Set the DAT pin to output */
gpio_direction_output(host->dat_gpio, 1);
gpiod_direction_output(host->dat, 1);
/* Send the device address */
cbus_send_data(host, dev, CBUS_ADDR_BITS);
@ -141,12 +139,12 @@ static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
cbus_send_data(host, data, 16);
ret = 0;
} else {
ret = gpio_direction_input(host->dat_gpio);
ret = gpiod_direction_input(host->dat);
if (ret) {
dev_dbg(host->dev, "failed setting direction\n");
goto out;
}
gpio_set_value(host->clk_gpio, 1);
gpiod_set_value(host->clk, 1);
ret = cbus_receive_word(host);
if (ret < 0) {
@ -156,9 +154,9 @@ static int cbus_transfer(struct cbus_host *host, char rw, unsigned dev,
}
/* Indicate end of transfer, SEL goes up until next transfer */
gpio_set_value(host->sel_gpio, 1);
gpio_set_value(host->clk_gpio, 1);
gpio_set_value(host->clk_gpio, 0);
gpiod_set_value(host->sel, 1);
gpiod_set_value(host->clk, 1);
gpiod_set_value(host->clk, 0);
out:
spin_unlock_irqrestore(&host->lock, flags);
@ -214,7 +212,6 @@ static int cbus_i2c_probe(struct platform_device *pdev)
{
struct i2c_adapter *adapter;
struct cbus_host *chost;
int ret;
adapter = devm_kzalloc(&pdev->dev, sizeof(struct i2c_adapter),
GFP_KERNEL);
@ -225,22 +222,20 @@ static int cbus_i2c_probe(struct platform_device *pdev)
if (!chost)
return -ENOMEM;
if (pdev->dev.of_node) {
struct device_node *dnode = pdev->dev.of_node;
if (of_gpio_count(dnode) != 3)
if (gpiod_count(&pdev->dev, NULL) != 3)
return -ENODEV;
chost->clk_gpio = of_get_gpio(dnode, 0);
chost->dat_gpio = of_get_gpio(dnode, 1);
chost->sel_gpio = of_get_gpio(dnode, 2);
} else if (dev_get_platdata(&pdev->dev)) {
struct i2c_cbus_platform_data *pdata =
dev_get_platdata(&pdev->dev);
chost->clk_gpio = pdata->clk_gpio;
chost->dat_gpio = pdata->dat_gpio;
chost->sel_gpio = pdata->sel_gpio;
} else {
return -ENODEV;
}
chost->clk = devm_gpiod_get_index(&pdev->dev, NULL, 0, GPIOD_OUT_LOW);
if (IS_ERR(chost->clk))
return PTR_ERR(chost->clk);
chost->dat = devm_gpiod_get_index(&pdev->dev, NULL, 1, GPIOD_IN);
if (IS_ERR(chost->dat))
return PTR_ERR(chost->dat);
chost->sel = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_OUT_HIGH);
if (IS_ERR(chost->sel))
return PTR_ERR(chost->sel);
gpiod_set_consumer_name(chost->clk, "CBUS clk");
gpiod_set_consumer_name(chost->dat, "CBUS dat");
gpiod_set_consumer_name(chost->sel, "CBUS sel");
adapter->owner = THIS_MODULE;
adapter->class = I2C_CLASS_HWMON;
@ -254,21 +249,6 @@ static int cbus_i2c_probe(struct platform_device *pdev)
spin_lock_init(&chost->lock);
chost->dev = &pdev->dev;
ret = devm_gpio_request_one(&pdev->dev, chost->clk_gpio,
GPIOF_OUT_INIT_LOW, "CBUS clk");
if (ret)
return ret;
ret = devm_gpio_request_one(&pdev->dev, chost->dat_gpio, GPIOF_IN,
"CBUS data");
if (ret)
return ret;
ret = devm_gpio_request_one(&pdev->dev, chost->sel_gpio,
GPIOF_OUT_INIT_HIGH, "CBUS sel");
if (ret)
return ret;
i2c_set_adapdata(adapter, chost);
platform_set_drvdata(pdev, adapter);

View File

@ -215,6 +215,7 @@
* @disable_int: function to disable all interrupts
* @init: function to initialize the I2C hardware
* @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE
* @suspended: set to true if the controller is suspended
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@ -270,6 +271,7 @@ struct dw_i2c_dev {
int (*set_sda_hold_time)(struct dw_i2c_dev *dev);
int mode;
struct i2c_bus_recovery_info rinfo;
bool suspended;
};
#define ACCESS_SWAP 0x00000001

View File

@ -426,6 +426,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
pm_runtime_get_sync(dev->dev);
if (dev->suspended) {
dev_err(dev->dev, "Error %s call while suspended\n", __func__);
ret = -ESHUTDOWN;
goto done_nolock;
}
reinit_completion(&dev->cmd_complete);
dev->msgs = msgs;
dev->msgs_num = num;

View File

@ -176,6 +176,7 @@ static int i2c_dw_pci_suspend(struct device *dev)
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
i_dev->suspended = true;
i_dev->disable(i_dev);
return 0;
@ -185,8 +186,12 @@ static int i2c_dw_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct dw_i2c_dev *i_dev = pci_get_drvdata(pdev);
int ret;
return i_dev->init(i_dev);
ret = i_dev->init(i_dev);
i_dev->suspended = false;
return ret;
}
#endif

View File

@ -454,6 +454,8 @@ static int dw_i2c_plat_suspend(struct device *dev)
{
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
i_dev->suspended = true;
if (i_dev->shared_with_punit)
return 0;
@ -471,6 +473,7 @@ static int dw_i2c_plat_resume(struct device *dev)
i2c_dw_prepare_clk(i_dev, true);
i_dev->init(i_dev);
i_dev->suspended = false;
return 0;
}

View File

@ -183,7 +183,6 @@ enum i2c_type_exynos {
struct exynos5_i2c {
struct i2c_adapter adap;
unsigned int suspended:1;
struct i2c_msg *msg;
struct completion msg_complete;
@ -715,11 +714,6 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap,
struct exynos5_i2c *i2c = adap->algo_data;
int i, ret;
if (i2c->suspended) {
dev_err(i2c->dev, "HS-I2C is not initialized.\n");
return -EIO;
}
ret = clk_enable(i2c->clk);
if (ret)
return ret;
@ -847,8 +841,7 @@ static int exynos5_i2c_suspend_noirq(struct device *dev)
{
struct exynos5_i2c *i2c = dev_get_drvdata(dev);
i2c->suspended = 1;
i2c_mark_adapter_suspended(&i2c->adap);
clk_unprepare(i2c->clk);
return 0;
@ -871,7 +864,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
exynos5_i2c_init(i2c);
clk_disable(i2c->clk);
i2c->suspended = 0;
i2c_mark_adapter_resumed(&i2c->adap);
return 0;
}

View File

@ -7,17 +7,19 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/completion.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c-algo-bit.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/i2c-gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
struct i2c_gpio_private_data {
struct gpio_desc *sda;
@ -27,6 +29,9 @@ struct i2c_gpio_private_data {
struct i2c_gpio_platform_data pdata;
#ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR
struct dentry *debug_dir;
/* these must be protected by bus lock */
struct completion scl_irq_completion;
u64 scl_irq_data;
#endif
};
@ -162,6 +167,96 @@ static int fops_incomplete_write_byte_set(void *data, u64 addr)
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_incomplete_write_byte, NULL, fops_incomplete_write_byte_set, "%llu\n");
static int i2c_gpio_fi_act_on_scl_irq(struct i2c_gpio_private_data *priv,
irqreturn_t handler(int, void*))
{
int ret, irq = gpiod_to_irq(priv->scl);
if (irq < 0)
return irq;
i2c_lock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
ret = gpiod_direction_input(priv->scl);
if (ret)
goto unlock;
reinit_completion(&priv->scl_irq_completion);
ret = request_irq(irq, handler, IRQF_TRIGGER_FALLING,
"i2c_gpio_fault_injector_scl_irq", priv);
if (ret)
goto output;
wait_for_completion_interruptible(&priv->scl_irq_completion);
free_irq(irq, priv);
output:
ret = gpiod_direction_output(priv->scl, 1) ?: ret;
unlock:
i2c_unlock_bus(&priv->adap, I2C_LOCK_ROOT_ADAPTER);
return ret;
}
static irqreturn_t lose_arbitration_irq(int irq, void *dev_id)
{
struct i2c_gpio_private_data *priv = dev_id;
setsda(&priv->bit_data, 0);
udelay(priv->scl_irq_data);
setsda(&priv->bit_data, 1);
complete(&priv->scl_irq_completion);
return IRQ_HANDLED;
}
static int fops_lose_arbitration_set(void *data, u64 duration)
{
struct i2c_gpio_private_data *priv = data;
if (duration > 100 * 1000)
return -EINVAL;
priv->scl_irq_data = duration;
/*
* Interrupt on falling SCL. This ensures that the master under test has
* really started the transfer. Interrupt on falling SDA did only
* exercise 'bus busy' detection on some HW but not 'arbitration lost'.
* Note that the interrupt latency may cause the first bits to be
* transmitted correctly.
*/
return i2c_gpio_fi_act_on_scl_irq(priv, lose_arbitration_irq);
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_lose_arbitration, NULL, fops_lose_arbitration_set, "%llu\n");
static irqreturn_t inject_panic_irq(int irq, void *dev_id)
{
struct i2c_gpio_private_data *priv = dev_id;
udelay(priv->scl_irq_data);
panic("I2C fault injector induced panic");
return IRQ_HANDLED;
}
static int fops_inject_panic_set(void *data, u64 duration)
{
struct i2c_gpio_private_data *priv = data;
if (duration > 100 * 1000)
return -EINVAL;
priv->scl_irq_data = duration;
/*
* Interrupt on falling SCL. This ensures that the master under test has
* really started the transfer.
*/
return i2c_gpio_fi_act_on_scl_irq(priv, inject_panic_irq);
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_inject_panic, NULL, fops_inject_panic_set, "%llu\n");
static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
{
struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev);
@ -181,12 +276,20 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev)
if (!priv->debug_dir)
return;
debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);
debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda);
init_completion(&priv->scl_irq_completion);
debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir,
priv, &fops_incomplete_addr_phase);
debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir,
priv, &fops_incomplete_write_byte);
if (priv->bit_data.getscl) {
debugfs_create_file_unsafe("inject_panic", 0200, priv->debug_dir,
priv, &fops_inject_panic);
debugfs_create_file_unsafe("lose_arbitration", 0200, priv->debug_dir,
priv, &fops_lose_arbitration);
}
debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl);
debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda);
}
static void i2c_gpio_fault_injector_exit(struct platform_device *pdev)
@ -286,11 +389,11 @@ static int i2c_gpio_probe(struct platform_device *pdev)
/*
* First get the GPIO pins; if it fails, we'll defer the probe.
* If the SDA line is marked from platform data or device tree as
* "open drain" it means something outside of our control is making
* this line being handled as open drain, and we should just handle
* it as any other output. Else we enforce open drain as this is
* required for an I2C bus.
* If the SCL/SDA lines are marked "open drain" by platform data or
* device tree then this means that something outside of our control is
* marking these lines to be handled as open drain, and we should just
* handle them as we handle any other output. Else we enforce open
* drain as this is required for an I2C bus.
*/
if (pdata->sda_is_open_drain)
gflags = GPIOD_OUT_HIGH;
@ -300,13 +403,6 @@ static int i2c_gpio_probe(struct platform_device *pdev)
if (IS_ERR(priv->sda))
return PTR_ERR(priv->sda);
/*
* If the SCL line is marked from platform data or device tree as
* "open drain" it means something outside of our control is making
* this line being handled as open drain, and we should just handle
* it as any other output. Else we enforce open drain as this is
* required for an I2C bus.
*/
if (pdata->scl_is_open_drain)
gflags = GPIOD_OUT_HIGH;
else

View File

@ -273,7 +273,7 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
}
/* Functions for DMA support */
static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_addr_t phy_addr)
{
struct imx_i2c_dma *dma;
@ -283,11 +283,13 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL);
if (!dma)
return;
return -ENOMEM;
dma->chan_tx = dma_request_slave_channel(dev, "tx");
if (!dma->chan_tx) {
dev_dbg(dev, "can't request DMA tx channel\n");
dma->chan_tx = dma_request_chan(dev, "tx");
if (IS_ERR(dma->chan_tx)) {
ret = PTR_ERR(dma->chan_tx);
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(dev, "can't request DMA tx channel (%d)\n", ret);
goto fail_al;
}
@ -298,13 +300,15 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_sconfig.direction = DMA_MEM_TO_DEV;
ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig);
if (ret < 0) {
dev_dbg(dev, "can't configure tx channel\n");
dev_err(dev, "can't configure tx channel (%d)\n", ret);
goto fail_tx;
}
dma->chan_rx = dma_request_slave_channel(dev, "rx");
if (!dma->chan_rx) {
dev_dbg(dev, "can't request DMA rx channel\n");
dma->chan_rx = dma_request_chan(dev, "rx");
if (IS_ERR(dma->chan_rx)) {
ret = PTR_ERR(dma->chan_rx);
if (ret != -ENODEV && ret != -EPROBE_DEFER)
dev_err(dev, "can't request DMA rx channel (%d)\n", ret);
goto fail_tx;
}
@ -315,7 +319,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_sconfig.direction = DMA_DEV_TO_MEM;
ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig);
if (ret < 0) {
dev_dbg(dev, "can't configure rx channel\n");
dev_err(dev, "can't configure rx channel (%d)\n", ret);
goto fail_rx;
}
@ -324,7 +328,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n",
dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx));
return;
return 0;
fail_rx:
dma_release_channel(dma->chan_rx);
@ -332,7 +336,8 @@ fail_tx:
dma_release_channel(dma->chan_tx);
fail_al:
devm_kfree(dev, dma);
dev_info(dev, "can't use DMA, using PIO instead.\n");
/* return successfully if there is no dma support */
return ret == -ENODEV ? 0 : ret;
}
static void i2c_imx_dma_callback(void *arg)
@ -1160,11 +1165,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res);
dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",
i2c_imx->adapter.name);
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
/* Init DMA config if supported */
i2c_imx_dma_request(i2c_imx, phy_addr);
ret = i2c_imx_dma_request(i2c_imx, phy_addr);
if (ret < 0)
goto clk_notifier_unregister;
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
return 0; /* Return OK */
clk_notifier_unregister:

View File

@ -471,6 +471,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
new_adapter->owner = THIS_MODULE;
new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
new_adapter->dev.parent = &pdev->dev;
new_adapter->dev.of_node = pdev->dev.of_node;
new_adapter->nr = pdev->id;
/*
@ -508,12 +509,19 @@ out:
return ret;
}
static const struct of_device_id i2c_iop3xx_match[] = {
{ .compatible = "intel,iop3xx-i2c", },
{ .compatible = "intel,ixp4xx-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, i2c_iop3xx_match);
static struct platform_driver iop3xx_i2c_driver = {
.probe = iop3xx_i2c_probe,
.remove = iop3xx_i2c_remove,
.driver = {
.name = "IOP3xx-I2C",
.of_match_table = i2c_iop3xx_match,
},
};

View File

@ -456,7 +456,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
control_reg = readw(i2c->base + OFFSET_CONTROL) &
~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS);
if ((i2c->speed_hz > 400000) || (left_num >= 1))
if ((i2c->speed_hz > MAX_FS_MODE_SPEED) || (left_num >= 1))
control_reg |= I2C_CONTROL_RS;
if (i2c->op == I2C_MASTER_WRRD)
@ -465,7 +465,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
writew(control_reg, i2c->base + OFFSET_CONTROL);
/* set start condition */
if (i2c->speed_hz <= 100000)
if (i2c->speed_hz <= I2C_DEFAULT_SPEED)
writew(I2C_ST_START_CON, i2c->base + OFFSET_EXT_CONF);
else
writew(I2C_FS_START_CON, i2c->base + OFFSET_EXT_CONF);
@ -642,8 +642,6 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs,
return -ETIMEDOUT;
}
completion_done(&i2c->msg_complete);
if (i2c->irq_stat & (I2C_HS_NACKERR | I2C_ACKERR)) {
dev_dbg(i2c->dev, "addr: %x, transfer ACK error\n", msgs->addr);
mtk_i2c_init_hw(i2c);

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* i2c-ocores.c: I2C bus driver for OpenCores I2C controller
* (https://opencores.org/project/i2c/overview)
@ -6,13 +7,10 @@
*
* Support for the GRLIB port of the controller by
* Andreas Larsson <andreas@gaisler.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
@ -25,17 +23,28 @@
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/log2.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#define OCORES_FLAG_POLL BIT(0)
/*
* 'process_lock' exists because ocores_process() and ocores_process_timeout()
* can't run in parallel.
*/
struct ocores_i2c {
void __iomem *base;
int iobase;
u32 reg_shift;
u32 reg_io_width;
unsigned long flags;
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_msg *msg;
int pos;
int nmsgs;
int state; /* see STATE_ */
spinlock_t process_lock;
struct clk *clk;
int ip_clock_khz;
int bus_clock_khz;
@ -127,6 +136,16 @@ static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
return ioread32be(i2c->base + (reg << i2c->reg_shift));
}
static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value)
{
outb(value, i2c->iobase + reg);
}
static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg)
{
return inb(i2c->iobase + reg);
}
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
{
i2c->setreg(i2c, reg, value);
@ -137,23 +156,29 @@ static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg)
return i2c->getreg(i2c, reg);
}
static void ocores_process(struct ocores_i2c *i2c)
static void ocores_process(struct ocores_i2c *i2c, u8 stat)
{
struct i2c_msg *msg = i2c->msg;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
unsigned long flags;
/*
* If we spin here is because we are in timeout, so we are going
* to be in STATE_ERROR. See ocores_process_timeout()
*/
spin_lock_irqsave(&i2c->process_lock, flags);
if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {
/* stop has been sent */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
wake_up(&i2c->wait);
return;
goto out;
}
/* error? */
if (stat & OCI2C_STAT_ARBLOST) {
i2c->state = STATE_ERROR;
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
return;
goto out;
}
if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {
@ -163,10 +188,11 @@ static void ocores_process(struct ocores_i2c *i2c)
if (stat & OCI2C_STAT_NACK) {
i2c->state = STATE_ERROR;
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
return;
goto out;
}
} else
} else {
msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);
}
/* end of msg? */
if (i2c->pos == msg->len) {
@ -184,14 +210,14 @@ static void ocores_process(struct ocores_i2c *i2c)
oc_setreg(i2c, OCI2C_DATA, addr);
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
return;
} else
goto out;
}
i2c->state = (msg->flags & I2C_M_RD)
? STATE_READ : STATE_WRITE;
} else {
i2c->state = STATE_DONE;
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
return;
goto out;
}
}
@ -202,20 +228,148 @@ static void ocores_process(struct ocores_i2c *i2c)
oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);
}
out:
spin_unlock_irqrestore(&i2c->process_lock, flags);
}
static irqreturn_t ocores_isr(int irq, void *dev_id)
{
struct ocores_i2c *i2c = dev_id;
u8 stat = oc_getreg(i2c, OCI2C_STATUS);
ocores_process(i2c);
if (!(stat & OCI2C_STAT_IF))
return IRQ_NONE;
ocores_process(i2c, stat);
return IRQ_HANDLED;
}
static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
/**
* Process timeout event
* @i2c: ocores I2C device instance
*/
static void ocores_process_timeout(struct ocores_i2c *i2c)
{
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
unsigned long flags;
spin_lock_irqsave(&i2c->process_lock, flags);
i2c->state = STATE_ERROR;
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);
spin_unlock_irqrestore(&i2c->process_lock, flags);
}
/**
* Wait until something change in a given register
* @i2c: ocores I2C device instance
* @reg: register to query
* @mask: bitmask to apply on register value
* @val: expected result
* @timeout: timeout in jiffies
*
* Timeout is necessary to avoid to stay here forever when the chip
* does not answer correctly.
*
* Return: 0 on success, -ETIMEDOUT on timeout
*/
static int ocores_wait(struct ocores_i2c *i2c,
int reg, u8 mask, u8 val,
const unsigned long timeout)
{
unsigned long j;
j = jiffies + timeout;
while (1) {
u8 status = oc_getreg(i2c, reg);
if ((status & mask) == val)
break;
if (time_after(jiffies, j))
return -ETIMEDOUT;
}
return 0;
}
/**
* Wait until is possible to process some data
* @i2c: ocores I2C device instance
*
* Used when the device is in polling mode (interrupts disabled).
*
* Return: 0 on success, -ETIMEDOUT on timeout
*/
static int ocores_poll_wait(struct ocores_i2c *i2c)
{
u8 mask;
int err;
if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
/* transfer is over */
mask = OCI2C_STAT_BUSY;
} else {
/* on going transfer */
mask = OCI2C_STAT_TIP;
/*
* We wait for the data to be transferred (8bit),
* then we start polling on the ACK/NACK bit
*/
udelay((8 * 1000) / i2c->bus_clock_khz);
}
/*
* once we are here we expect to get the expected result immediately
* so if after 1ms we timeout then something is broken.
*/
err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(1));
if (err)
dev_warn(i2c->adap.dev.parent,
"%s: STATUS timeout, bit 0x%x did not clear in 1ms\n",
__func__, mask);
return err;
}
/**
* It handles an IRQ-less transfer
* @i2c: ocores I2C device instance
*
* Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same
* (only that IRQ are not produced). This means that we can re-use entirely
* ocores_isr(), we just add our polling code around it.
*
* It can run in atomic context
*/
static void ocores_process_polling(struct ocores_i2c *i2c)
{
while (1) {
irqreturn_t ret;
int err;
err = ocores_poll_wait(i2c);
if (err) {
i2c->state = STATE_ERROR;
break; /* timeout */
}
ret = ocores_isr(-1, i2c);
if (ret == IRQ_NONE)
break; /* all messages have been transferred */
}
}
static int ocores_xfer_core(struct ocores_i2c *i2c,
struct i2c_msg *msgs, int num,
bool polling)
{
int ret;
u8 ctrl;
ctrl = oc_getreg(i2c, OCI2C_CONTROL);
if (polling)
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN);
else
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN);
i2c->msg = msgs;
i2c->pos = 0;
@ -225,12 +379,36 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);
if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
(i2c->state == STATE_DONE), HZ))
return (i2c->state == STATE_DONE) ? num : -EIO;
else
if (polling) {
ocores_process_polling(i2c);
} else {
ret = wait_event_timeout(i2c->wait,
(i2c->state == STATE_ERROR) ||
(i2c->state == STATE_DONE), HZ);
if (ret == 0) {
ocores_process_timeout(i2c);
return -ETIMEDOUT;
}
}
return (i2c->state == STATE_DONE) ? num : -EIO;
}
static int ocores_xfer_polling(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true);
}
static int ocores_xfer(struct i2c_adapter *adap,
struct i2c_msg *msgs, int num)
{
struct ocores_i2c *i2c = i2c_get_adapdata(adap);
if (i2c->flags & OCORES_FLAG_POLL)
return ocores_xfer_polling(adap, msgs, num);
return ocores_xfer_core(i2c, msgs, num, false);
}
static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
{
@ -239,7 +417,8 @@ static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);
oc_setreg(i2c, OCI2C_CONTROL, ctrl);
prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
prescale = clamp(prescale, 0, 0xffff);
@ -257,7 +436,7 @@ static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
/* Init the device */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN);
return 0;
}
@ -294,13 +473,16 @@ static const struct of_device_id ocores_i2c_match[] = {
MODULE_DEVICE_TABLE(of, ocores_i2c_match);
#ifdef CONFIG_OF
/* Read and write functions for the GRLIB port of the controller. Registers are
/*
* Read and write functions for the GRLIB port of the controller. Registers are
* 32-bit big endian and the PRELOW and PREHIGH registers are merged into one
* register. The subsequent registers has their offset decreased accordingly. */
* register. The subsequent registers have their offsets decreased accordingly.
*/
static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg)
{
u32 rd;
int rreg = reg;
if (reg != OCI2C_PRELOW)
rreg--;
rd = ioread32be(i2c->base + (rreg << i2c->reg_shift));
@ -314,6 +496,7 @@ static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value)
{
u32 curr, wr;
int rreg = reg;
if (reg != OCI2C_PRELOW)
rreg--;
if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) {
@ -414,24 +597,40 @@ static int ocores_i2c_probe(struct platform_device *pdev)
int ret;
int i;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
spin_lock_init(&i2c->process_lock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res) {
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
} else {
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EINVAL;
i2c->iobase = res->start;
if (!devm_request_region(&pdev->dev, res->start,
resource_size(res),
pdev->name)) {
dev_err(&pdev->dev, "Can't get I/O resource.\n");
return -EBUSY;
}
i2c->setreg = oc_setreg_io_8;
i2c->getreg = oc_getreg_io_8;
}
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
i2c->reg_shift = pdata->reg_shift;
i2c->reg_io_width = pdata->reg_io_width;
i2c->ip_clock_khz = pdata->clock_khz;
if (pdata->bus_khz)
i2c->bus_clock_khz = pdata->bus_khz;
else
i2c->bus_clock_khz = 100;
} else {
ret = ocores_i2c_of_probe(pdev, i2c);
@ -470,17 +669,28 @@ static int ocores_i2c_probe(struct platform_device *pdev)
}
}
ret = ocores_init(&pdev->dev, i2c);
if (ret)
goto err_clk;
init_waitqueue_head(&i2c->wait);
irq = platform_get_irq(pdev, 0);
if (irq == -ENXIO) {
i2c->flags |= OCORES_FLAG_POLL;
} else {
if (irq < 0)
return irq;
}
if (!(i2c->flags & OCORES_FLAG_POLL)) {
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
pdev->name, i2c);
if (ret) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
goto err_clk;
}
}
ret = ocores_init(&pdev->dev, i2c);
if (ret)
goto err_clk;
/* hook up driver to tree */
platform_set_drvdata(pdev, i2c);
@ -510,10 +720,11 @@ err_clk:
static int ocores_i2c_remove(struct platform_device *pdev)
{
struct ocores_i2c *i2c = platform_get_drvdata(pdev);
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* disable i2c logic */
oc_setreg(i2c, OCI2C_CONTROL, oc_getreg(i2c, OCI2C_CONTROL)
& ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);
oc_setreg(i2c, OCI2C_CONTROL, ctrl);
/* remove adapter & data */
i2c_del_adapter(&i2c->adap);
@ -531,7 +742,8 @@ static int ocores_i2c_suspend(struct device *dev)
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);
oc_setreg(i2c, OCI2C_CONTROL, ctrl);
if (!IS_ERR(i2c->clk))
clk_disable_unprepare(i2c->clk);

View File

@ -2,8 +2,8 @@
/*
* Driver for the Renesas R-Car I2C unit
*
* Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
* Copyright (C) 2011-2015 Renesas Electronics Corporation
* Copyright (C) 2014-19 Wolfram Sang <wsa@sang-engineering.com>
* Copyright (C) 2011-2019 Renesas Electronics Corporation
*
* Copyright (C) 2012-14 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
@ -39,8 +39,8 @@
#define ICSAR 0x1C /* slave address */
#define ICMAR 0x20 /* master address */
#define ICRXTX 0x24 /* data port */
#define ICDMAER 0x3c /* DMA enable */
#define ICFBSCR 0x38 /* first bit setup cycle */
#define ICFBSCR 0x38 /* first bit setup cycle (Gen3) */
#define ICDMAER 0x3c /* DMA enable (Gen3) */
/* ICSCR */
#define SDBS (1 << 3) /* slave data buffer select */
@ -83,7 +83,6 @@
#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
/* ICFBSCR */
#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
@ -212,6 +211,10 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv)
rcar_i2c_write(priv, ICMSR, 0);
/* start clock */
rcar_i2c_write(priv, ICCCR, priv->icccr);
if (priv->devtype == I2C_RCAR_GEN3)
rcar_i2c_write(priv, ICFBSCR, TCYC17);
}
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
@ -355,9 +358,6 @@ static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
rcar_i2c_prepare_msg(priv);
}
/*
* interrupt functions
*/
static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
{
struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
@ -366,9 +366,6 @@ static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
/* Disable DMA Master Received/Transmitted */
rcar_i2c_write(priv, ICDMAER, 0);
/* Reset default delay */
rcar_i2c_write(priv, ICFBSCR, TCYC06);
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
sg_dma_len(&priv->sg), priv->dma_direction);
@ -464,9 +461,6 @@ static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
return;
}
/* Set delay for DMA operations */
rcar_i2c_write(priv, ICFBSCR, TCYC17);
/* Enable DMA Master Received/Transmitted */
if (read)
rcar_i2c_write(priv, ICDMAER, RMDMAE);
@ -1017,10 +1011,37 @@ static int rcar_i2c_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rcar_i2c_suspend(struct device *dev)
{
struct rcar_i2c_priv *priv = dev_get_drvdata(dev);
i2c_mark_adapter_suspended(&priv->adap);
return 0;
}
static int rcar_i2c_resume(struct device *dev)
{
struct rcar_i2c_priv *priv = dev_get_drvdata(dev);
i2c_mark_adapter_resumed(&priv->adap);
return 0;
}
static const struct dev_pm_ops rcar_i2c_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume)
};
#define DEV_PM_OPS (&rcar_i2c_pm_ops)
#else
#define DEV_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
static struct platform_driver rcar_i2c_driver = {
.driver = {
.name = "i2c-rcar",
.of_match_table = rcar_i2c_dt_ids,
.pm = DEV_PM_OPS,
},
.probe = rcar_i2c_probe,
.remove = rcar_i2c_remove,

View File

@ -104,7 +104,6 @@ enum s3c24xx_i2c_state {
struct s3c24xx_i2c {
wait_queue_head_t wait;
kernel_ulong_t quirks;
unsigned int suspended:1;
struct i2c_msg *msg;
unsigned int msg_num;
@ -703,9 +702,6 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
unsigned long timeout;
int ret;
if (i2c->suspended)
return -EIO;
ret = s3c24xx_i2c_set_master(i2c);
if (ret != 0) {
dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);
@ -1246,7 +1242,7 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
{
struct s3c24xx_i2c *i2c = dev_get_drvdata(dev);
i2c->suspended = 1;
i2c_mark_adapter_suspended(&i2c->adap);
if (!IS_ERR(i2c->sysreg))
regmap_read(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, &i2c->sys_i2c_cfg);
@ -1267,7 +1263,7 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
return ret;
s3c24xx_i2c_init(i2c);
clk_disable(i2c->clk);
i2c->suspended = 0;
i2c_mark_adapter_resumed(&i2c->adap);
return 0;
}

View File

@ -2,8 +2,7 @@
/*
* SuperH Mobile I2C Controller
*
* Copyright (C) 2014 Wolfram Sang <wsa@sang-engineering.com>
*
* Copyright (C) 2014-19 Wolfram Sang <wsa@sang-engineering.com>
* Copyright (C) 2008 Magnus Damm
*
* Portions of the code based on out-of-tree driver i2c-sh7343.c
@ -303,13 +302,12 @@ static int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd)
return sh_mobile_i2c_check_timing(pd);
}
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
enum sh_mobile_i2c_op op, unsigned char data)
static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op)
{
unsigned char ret = 0;
unsigned long flags;
dev_dbg(pd->dev, "op %d, data in 0x%02x\n", op, data);
dev_dbg(pd->dev, "op %d\n", op);
spin_lock_irqsave(&pd->lock, flags);
@ -317,12 +315,12 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
case OP_START: /* issue start and trigger DTE interrupt */
iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY);
break;
case OP_TX_FIRST: /* disable DTE interrupt and write data */
case OP_TX_FIRST: /* disable DTE interrupt and write client address */
iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
iic_wr(pd, ICDR, data);
iic_wr(pd, ICDR, i2c_8bit_addr_from_msg(pd->msg));
break;
case OP_TX: /* write data */
iic_wr(pd, ICDR, data);
iic_wr(pd, ICDR, pd->msg->buf[pd->pos]);
break;
case OP_TX_STOP: /* issue a stop (or rep_start) */
iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
@ -353,34 +351,17 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
return ret;
}
static bool sh_mobile_i2c_is_first_byte(struct sh_mobile_i2c_data *pd)
{
return pd->pos == -1;
}
static void sh_mobile_i2c_get_data(struct sh_mobile_i2c_data *pd,
unsigned char *buf)
{
switch (pd->pos) {
case -1:
*buf = i2c_8bit_addr_from_msg(pd->msg);
break;
default:
*buf = pd->msg->buf[pd->pos];
}
}
static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
{
unsigned char data;
if (pd->pos == pd->msg->len) {
i2c_op(pd, OP_TX_STOP, 0);
i2c_op(pd, OP_TX_STOP);
return 1;
}
sh_mobile_i2c_get_data(pd, &data);
i2c_op(pd, sh_mobile_i2c_is_first_byte(pd) ? OP_TX_FIRST : OP_TX, data);
if (pd->pos == -1)
i2c_op(pd, OP_TX_FIRST);
else
i2c_op(pd, OP_TX);
pd->pos++;
return 0;
@ -391,45 +372,32 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
unsigned char data;
int real_pos;
do {
if (pd->pos <= -1) {
sh_mobile_i2c_get_data(pd, &data);
if (sh_mobile_i2c_is_first_byte(pd))
i2c_op(pd, OP_TX_FIRST, data);
else
i2c_op(pd, OP_TX, data);
break;
}
if (pd->pos == 0) {
i2c_op(pd, OP_TX_TO_RX, 0);
break;
}
/* switch from TX (address) to RX (data) adds two interrupts */
real_pos = pd->pos - 2;
if (pd->pos == pd->msg->len) {
if (pd->pos == -1) {
i2c_op(pd, OP_TX_FIRST);
} else if (pd->pos == 0) {
i2c_op(pd, OP_TX_TO_RX);
} else if (pd->pos == pd->msg->len) {
if (pd->stop_after_dma) {
/* Simulate PIO end condition after DMA transfer */
i2c_op(pd, OP_RX_STOP, 0);
i2c_op(pd, OP_RX_STOP);
pd->pos++;
break;
goto done;
}
if (real_pos < 0) {
i2c_op(pd, OP_RX_STOP, 0);
break;
}
data = i2c_op(pd, OP_RX_STOP_DATA, 0);
if (real_pos < 0)
i2c_op(pd, OP_RX_STOP);
else
data = i2c_op(pd, OP_RX_STOP_DATA);
} else if (real_pos >= 0) {
data = i2c_op(pd, OP_RX, 0);
data = i2c_op(pd, OP_RX);
}
if (real_pos >= 0)
pd->msg->buf[real_pos] = data;
} while (0);
done:
pd->pos++;
return pd->pos == (pd->msg->len + 2);
}
@ -698,7 +666,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
start_ch(pd, msg, do_start);
if (do_start)
i2c_op(pd, OP_START, 0);
i2c_op(pd, OP_START);
/* The interrupt handler takes care of the rest... */
timeout = wait_event_timeout(pd->wait,
@ -749,8 +717,7 @@ static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
};
/*
* r8a7740 chip has lasting errata on I2C I/O pad reset.
* this is work-around for it.
* r8a7740 has an errata regarding I2C I/O pad reset needing this workaround.
*/
static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
{
@ -802,15 +769,15 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .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 },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7794", .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,rcar-gen3-iic", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
{ .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
{},
};

View File

@ -86,7 +86,6 @@ struct sprd_i2c {
u32 count;
int irq;
int err;
bool is_suspended;
};
static void sprd_i2c_set_count(struct sprd_i2c *i2c_dev, u32 count)
@ -284,9 +283,6 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap,
struct sprd_i2c *i2c_dev = i2c_adap->algo_data;
int im, ret;
if (i2c_dev->is_suspended)
return -EBUSY;
ret = pm_runtime_get_sync(i2c_dev->dev);
if (ret < 0)
return ret;
@ -586,40 +582,34 @@ static int sprd_i2c_remove(struct platform_device *pdev)
return 0;
}
static int __maybe_unused sprd_i2c_suspend_noirq(struct device *pdev)
static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev)
{
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
struct sprd_i2c *i2c_dev = dev_get_drvdata(dev);
i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = true;
i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
return pm_runtime_force_suspend(pdev);
i2c_mark_adapter_suspended(&i2c_dev->adap);
return pm_runtime_force_suspend(dev);
}
static int __maybe_unused sprd_i2c_resume_noirq(struct device *pdev)
static int __maybe_unused sprd_i2c_resume_noirq(struct device *dev)
{
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
struct sprd_i2c *i2c_dev = dev_get_drvdata(dev);
i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
i2c_dev->is_suspended = false;
i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER);
return pm_runtime_force_resume(pdev);
i2c_mark_adapter_resumed(&i2c_dev->adap);
return pm_runtime_force_resume(dev);
}
static int __maybe_unused sprd_i2c_runtime_suspend(struct device *pdev)
static int __maybe_unused sprd_i2c_runtime_suspend(struct device *dev)
{
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
struct sprd_i2c *i2c_dev = dev_get_drvdata(dev);
clk_disable_unprepare(i2c_dev->clk);
return 0;
}
static int __maybe_unused sprd_i2c_runtime_resume(struct device *pdev)
static int __maybe_unused sprd_i2c_runtime_resume(struct device *dev)
{
struct sprd_i2c *i2c_dev = dev_get_drvdata(pdev);
struct sprd_i2c *i2c_dev = dev_get_drvdata(dev);
int ret;
ret = clk_prepare_enable(i2c_dev->clk);

View File

@ -144,8 +144,6 @@ struct synquacer_i2c {
u32 timeout_ms;
enum i2c_state state;
struct i2c_adapter adapter;
bool is_suspended;
};
static inline int is_lastmsg(struct synquacer_i2c *i2c)
@ -316,9 +314,6 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c,
unsigned long timeout;
int ret;
if (i2c->is_suspended)
return -EBUSY;
synquacer_i2c_hw_init(i2c);
bsr = readb(i2c->base + SYNQUACER_I2C_REG_BSR);
if (bsr & SYNQUACER_I2C_BSR_BB) {

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,6 @@ struct zx2967_i2c {
int msg_rd;
u8 *cur_trans;
u8 access_cnt;
bool is_suspended;
int error;
};
@ -313,9 +312,6 @@ static int zx2967_i2c_xfer(struct i2c_adapter *adap,
int ret;
int i;
if (i2c->is_suspended)
return -EBUSY;
zx2967_set_addr(i2c, msgs->addr);
for (i = 0; i < num; i++) {
@ -470,7 +466,7 @@ static int __maybe_unused zx2967_i2c_suspend(struct device *dev)
{
struct zx2967_i2c *i2c = dev_get_drvdata(dev);
i2c->is_suspended = true;
i2c_mark_adapter_suspended(&i2c->adap);
clk_disable_unprepare(i2c->clk);
return 0;
@ -480,8 +476,8 @@ static int __maybe_unused zx2967_i2c_resume(struct device *dev)
{
struct zx2967_i2c *i2c = dev_get_drvdata(dev);
i2c->is_suspended = false;
clk_prepare_enable(i2c->clk);
i2c_mark_adapter_resumed(&i2c->adap);
return 0;
}

View File

@ -430,7 +430,7 @@ static int i2c_device_remove(struct device *dev)
dev_pm_clear_wake_irq(&client->dev);
device_init_wakeup(&client->dev, false);
client->irq = 0;
client->irq = client->init_irq;
return status;
}
@ -741,10 +741,11 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
client->flags = info->flags;
client->addr = info->addr;
client->irq = info->irq;
if (!client->irq)
client->irq = i2c_dev_irq_from_resources(info->resources,
client->init_irq = info->irq;
if (!client->init_irq)
client->init_irq = i2c_dev_irq_from_resources(info->resources,
info->num_resources);
client->irq = client->init_irq;
strlcpy(client->name, info->type, sizeof(client->name));
@ -1232,6 +1233,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
if (!adap->lock_ops)
adap->lock_ops = &i2c_adapter_lock_ops;
adap->locked_flags = 0;
rt_mutex_init(&adap->bus_lock);
rt_mutex_init(&adap->mux_lock);
mutex_init(&adap->userspace_clients_lock);
@ -1865,6 +1867,8 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
if (WARN_ON(!msgs || num < 1))
return -EINVAL;
if (WARN_ON(test_bit(I2C_ALF_IS_SUSPENDED, &adap->locked_flags)))
return -ESHUTDOWN;
if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
return -EOPNOTSUPP;

View File

@ -121,6 +121,17 @@ static int of_dev_node_match(struct device *dev, void *data)
return dev->of_node == data;
}
static int of_dev_or_parent_node_match(struct device *dev, void *data)
{
if (dev->of_node == data)
return 1;
if (dev->parent)
return dev->parent->of_node == data;
return 0;
}
/* must call put_device() when done with returned i2c_client device */
struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
{
@ -145,7 +156,8 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
struct device *dev;
struct i2c_adapter *adapter;
dev = bus_find_device(&i2c_bus_type, NULL, node, of_dev_node_match);
dev = bus_find_device(&i2c_bus_type, NULL, node,
of_dev_or_parent_node_match);
if (!dev)
return NULL;

View File

@ -585,7 +585,7 @@ s32 __i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
trace:
/* If enabled, the reply tracepoint is conditional on read_write. */
trace_smbus_reply(adapter, addr, flags, read_write,
command, protocol, data);
command, protocol, data, res);
trace_smbus_result(adapter, addr, flags, read_write,
command, protocol, res);

View File

@ -52,7 +52,7 @@ struct i2c_dev {
struct cdev cdev;
};
#define I2C_MINORS MINORMASK
#define I2C_MINORS (MINORMASK + 1)
static LIST_HEAD(i2c_dev_list);
static DEFINE_SPINLOCK(i2c_dev_list_lock);

View File

@ -22,10 +22,24 @@
#include <linux/i2c.h>
#include <linux/nvmem-provider.h>
#include <linux/regmap.h>
#include <linux/platform_data/at24.h>
#include <linux/pm_runtime.h>
#include <linux/gpio/consumer.h>
/* Address pointer is 16 bit. */
#define AT24_FLAG_ADDR16 BIT(7)
/* sysfs-entry will be read-only. */
#define AT24_FLAG_READONLY BIT(6)
/* sysfs-entry will be world-readable. */
#define AT24_FLAG_IRUGO BIT(5)
/* Take always 8 addresses (24c00). */
#define AT24_FLAG_TAKE8ADDR BIT(4)
/* Factory-programmed serial number. */
#define AT24_FLAG_SERIAL BIT(3)
/* Factory-programmed mac address. */
#define AT24_FLAG_MAC BIT(2)
/* Does not auto-rollover reads to the next slave address. */
#define AT24_FLAG_NO_RDROL BIT(1)
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
* Differences between different vendor product lines (like Atmel AT24C or
@ -107,10 +121,6 @@ module_param_named(write_timeout, at24_write_timeout, uint, 0);
MODULE_PARM_DESC(at24_write_timeout, "Time (in ms) to try writes (default 25)");
struct at24_chip_data {
/*
* these fields mirror their equivalents in
* struct at24_platform_data
*/
u32 byte_len;
u8 flags;
};
@ -471,63 +481,11 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
return 0;
}
static void at24_properties_to_pdata(struct device *dev,
struct at24_platform_data *chip)
{
int err;
u32 val;
if (device_property_present(dev, "read-only"))
chip->flags |= AT24_FLAG_READONLY;
if (device_property_present(dev, "no-read-rollover"))
chip->flags |= AT24_FLAG_NO_RDROL;
err = device_property_read_u32(dev, "address-width", &val);
if (!err) {
switch (val) {
case 8:
if (chip->flags & AT24_FLAG_ADDR16)
dev_warn(dev, "Override address width to be 8, while default is 16\n");
chip->flags &= ~AT24_FLAG_ADDR16;
break;
case 16:
chip->flags |= AT24_FLAG_ADDR16;
break;
default:
dev_warn(dev, "Bad \"address-width\" property: %u\n",
val);
}
}
err = device_property_read_u32(dev, "size", &val);
if (!err)
chip->byte_len = val;
err = device_property_read_u32(dev, "pagesize", &val);
if (!err) {
chip->page_size = val;
} else {
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
chip->page_size = 1;
}
}
static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata)
static const struct at24_chip_data *at24_get_chip_data(struct device *dev)
{
struct device_node *of_node = dev->of_node;
const struct at24_chip_data *cdata;
const struct i2c_device_id *id;
struct at24_platform_data *pd;
pd = dev_get_platdata(dev);
if (pd) {
memcpy(pdata, pd, sizeof(*pdata));
return 0;
}
id = i2c_match_id(at24_ids, to_i2c_client(dev));
@ -544,13 +502,9 @@ static int at24_get_pdata(struct device *dev, struct at24_platform_data *pdata)
cdata = acpi_device_get_match_data(dev);
if (!cdata)
return -ENODEV;
return ERR_PTR(-ENODEV);
pdata->byte_len = cdata->byte_len;
pdata->flags = cdata->flags;
at24_properties_to_pdata(dev, pdata);
return 0;
return cdata;
}
static void at24_remove_dummy_clients(struct at24_data *at24)
@ -619,7 +573,8 @@ static int at24_probe(struct i2c_client *client)
{
struct regmap_config regmap_config = { };
struct nvmem_config nvmem_config = { };
struct at24_platform_data pdata = { };
u32 byte_len, page_size, flags, addrw;
const struct at24_chip_data *cdata;
struct device *dev = &client->dev;
bool i2c_fn_i2c, i2c_fn_block;
unsigned int i, num_addresses;
@ -634,35 +589,75 @@ static int at24_probe(struct i2c_client *client)
i2c_fn_block = i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK);
err = at24_get_pdata(dev, &pdata);
cdata = at24_get_chip_data(dev);
if (IS_ERR(cdata))
return PTR_ERR(cdata);
err = device_property_read_u32(dev, "pagesize", &page_size);
if (err)
return err;
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
page_size = 1;
flags = cdata->flags;
if (device_property_present(dev, "read-only"))
flags |= AT24_FLAG_READONLY;
if (device_property_present(dev, "no-read-rollover"))
flags |= AT24_FLAG_NO_RDROL;
err = device_property_read_u32(dev, "address-width", &addrw);
if (!err) {
switch (addrw) {
case 8:
if (flags & AT24_FLAG_ADDR16)
dev_warn(dev,
"Override address width to be 8, while default is 16\n");
flags &= ~AT24_FLAG_ADDR16;
break;
case 16:
flags |= AT24_FLAG_ADDR16;
break;
default:
dev_warn(dev, "Bad \"address-width\" property: %u\n",
addrw);
}
}
err = device_property_read_u32(dev, "size", &byte_len);
if (err)
byte_len = cdata->byte_len;
if (!i2c_fn_i2c && !i2c_fn_block)
pdata.page_size = 1;
page_size = 1;
if (!pdata.page_size) {
if (!page_size) {
dev_err(dev, "page_size must not be 0!\n");
return -EINVAL;
}
if (!is_power_of_2(pdata.page_size))
if (!is_power_of_2(page_size))
dev_warn(dev, "page_size looks suspicious (no power of 2)!\n");
if (pdata.flags & AT24_FLAG_TAKE8ADDR)
err = device_property_read_u32(dev, "num-addresses", &num_addresses);
if (err) {
if (flags & AT24_FLAG_TAKE8ADDR)
num_addresses = 8;
else
num_addresses = DIV_ROUND_UP(pdata.byte_len,
(pdata.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
num_addresses = DIV_ROUND_UP(byte_len,
(flags & AT24_FLAG_ADDR16) ? 65536 : 256);
}
if ((pdata.flags & AT24_FLAG_SERIAL) && (pdata.flags & AT24_FLAG_MAC)) {
if ((flags & AT24_FLAG_SERIAL) && (flags & AT24_FLAG_MAC)) {
dev_err(dev,
"invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC.");
return -EINVAL;
}
regmap_config.val_bits = 8;
regmap_config.reg_bits = (pdata.flags & AT24_FLAG_ADDR16) ? 16 : 8;
regmap_config.reg_bits = (flags & AT24_FLAG_ADDR16) ? 16 : 8;
regmap_config.disable_locking = true;
regmap = devm_regmap_init_i2c(client, &regmap_config);
@ -675,11 +670,11 @@ static int at24_probe(struct i2c_client *client)
return -ENOMEM;
mutex_init(&at24->lock);
at24->byte_len = pdata.byte_len;
at24->page_size = pdata.page_size;
at24->flags = pdata.flags;
at24->byte_len = byte_len;
at24->page_size = page_size;
at24->flags = flags;
at24->num_addresses = num_addresses;
at24->offset_adj = at24_get_offset_adj(pdata.flags, pdata.byte_len);
at24->offset_adj = at24_get_offset_adj(flags, byte_len);
at24->client[0].client = client;
at24->client[0].regmap = regmap;
@ -687,10 +682,10 @@ static int at24_probe(struct i2c_client *client)
if (IS_ERR(at24->wp_gpio))
return PTR_ERR(at24->wp_gpio);
writable = !(pdata.flags & AT24_FLAG_READONLY);
writable = !(flags & AT24_FLAG_READONLY);
if (writable) {
at24->write_max = min_t(unsigned int,
pdata.page_size, at24_io_limit);
page_size, at24_io_limit);
if (!i2c_fn_i2c && at24->write_max > I2C_SMBUS_BLOCK_MAX)
at24->write_max = I2C_SMBUS_BLOCK_MAX;
}
@ -733,7 +728,7 @@ static int at24_probe(struct i2c_client *client)
nvmem_config.priv = at24;
nvmem_config.stride = 1;
nvmem_config.word_size = 1;
nvmem_config.size = pdata.byte_len;
nvmem_config.size = byte_len;
at24->nvmem = devm_nvmem_register(dev, &nvmem_config);
if (IS_ERR(at24->nvmem)) {
@ -742,13 +737,9 @@ static int at24_probe(struct i2c_client *client)
}
dev_info(dev, "%u byte %s EEPROM, %s, %u bytes/write\n",
pdata.byte_len, client->name,
byte_len, client->name,
writable ? "writable" : "read-only", at24->write_max);
/* export data to kernel code */
if (pdata.setup)
pdata.setup(at24->nvmem, pdata.context);
return 0;
err_clients:

View File

@ -1061,17 +1061,6 @@ static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
}
#endif
#if defined(CONFIG_ACPI) && IS_ENABLED(CONFIG_I2C)
bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
struct acpi_resource_i2c_serialbus **i2c);
#else
static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
struct acpi_resource_i2c_serialbus **i2c)
{
return false;
}
#endif
/* Device properties */
#ifdef CONFIG_ACPI

View File

@ -1,30 +1,17 @@
/* ------------------------------------------------------------------------- */
/* i2c-algo-bit.h i2c driver algorithms for bit-shift adapters */
/* ------------------------------------------------------------------------- */
/* Copyright (C) 1995-99 Simon G. Vogl
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.
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA. */
/* ------------------------------------------------------------------------- */
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* i2c-algo-bit.h: i2c driver algorithms for bit-shift adapters
*
* Copyright (C) 1995-99 Simon G. Vogl
* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
* Frodo Looijaard <frodol@dds.nl>
*/
#ifndef _LINUX_I2C_ALGO_BIT_H
#define _LINUX_I2C_ALGO_BIT_H
#include <linux/i2c.h>
/* --- Defines for bit-adapters --------------------------------------- */
/*
* This struct contains the hw-dependent functions of bit-style adapters to

View File

@ -333,6 +333,7 @@ struct i2c_client {
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct device dev; /* the device structure */
int init_irq; /* irq set at initialization */
int irq; /* irq issued by device */
struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
@ -680,6 +681,8 @@ struct i2c_adapter {
int timeout; /* in jiffies */
int retries;
struct device dev; /* the adapter device */
unsigned long locked_flags; /* owned by the I2C core */
#define I2C_ALF_IS_SUSPENDED 0
int nr;
char name[48];
@ -762,6 +765,38 @@ i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
adapter->lock_ops->unlock_bus(adapter, flags);
}
/**
* i2c_mark_adapter_suspended - Report suspended state of the adapter to the core
* @adap: Adapter to mark as suspended
*
* When using this helper to mark an adapter as suspended, the core will reject
* further transfers to this adapter. The usage of this helper is optional but
* recommended for devices having distinct handlers for system suspend and
* runtime suspend. More complex devices are free to implement custom solutions
* to reject transfers when suspended.
*/
static inline void i2c_mark_adapter_suspended(struct i2c_adapter *adap)
{
i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER);
set_bit(I2C_ALF_IS_SUSPENDED, &adap->locked_flags);
i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER);
}
/**
* i2c_mark_adapter_resumed - Report resumed state of the adapter to the core
* @adap: Adapter to mark as resumed
*
* When using this helper to mark an adapter as resumed, the core will allow
* further transfers to this adapter. See also further notes to
* @i2c_mark_adapter_suspended().
*/
static inline void i2c_mark_adapter_resumed(struct i2c_adapter *adap)
{
i2c_lock_bus(adap, I2C_LOCK_ROOT_ADAPTER);
clear_bit(I2C_ALF_IS_SUSPENDED, &adap->locked_flags);
i2c_unlock_bus(adap, I2C_LOCK_ROOT_ADAPTER);
}
/*flags for the client struct: */
#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
@ -933,11 +968,21 @@ static inline int of_i2c_get_board_info(struct device *dev,
#endif /* CONFIG_OF */
struct acpi_resource;
struct acpi_resource_i2c_serialbus;
#if IS_ENABLED(CONFIG_ACPI)
bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
struct acpi_resource_i2c_serialbus **i2c);
u32 i2c_acpi_find_bus_speed(struct device *dev);
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
struct i2c_board_info *info);
#else
static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
struct acpi_resource_i2c_serialbus **i2c)
{
return false;
}
static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
{
return 0;

View File

@ -1,60 +0,0 @@
/*
* at24.h - platform_data for the at24 (generic eeprom) driver
* (C) Copyright 2008 by Pengutronix
* (C) Copyright 2012 by Wolfram Sang
* same license as the driver
*/
#ifndef _LINUX_AT24_H
#define _LINUX_AT24_H
#include <linux/types.h>
#include <linux/nvmem-consumer.h>
#include <linux/bitops.h>
/**
* struct at24_platform_data - data to set up at24 (generic eeprom) driver
* @byte_len: size of eeprom in byte
* @page_size: number of byte which can be written in one go
* @flags: tunable options, check AT24_FLAG_* defines
* @setup: an optional callback invoked after eeprom is probed; enables kernel
code to access eeprom via nvmem, see example
* @context: optional parameter passed to setup()
*
* If you set up a custom eeprom type, please double-check the parameters.
* Especially page_size needs extra care, as you risk data loss if your value
* is bigger than what the chip actually supports!
*
* An example in pseudo code for a setup() callback:
*
* void get_mac_addr(struct nvmem_device *nvmem, void *context)
* {
* u8 *mac_addr = ethernet_pdata->mac_addr;
* off_t offset = context;
*
* // Read MAC addr from EEPROM
* if (nvmem_device_read(nvmem, offset, ETH_ALEN, mac_addr) == ETH_ALEN)
* pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr);
* }
*
* This function pointer and context can now be set up in at24_platform_data.
*/
struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
u8 flags;
#define AT24_FLAG_ADDR16 BIT(7) /* address pointer is 16 bit */
#define AT24_FLAG_READONLY BIT(6) /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO BIT(5) /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR BIT(4) /* take always 8 addresses (24c00) */
#define AT24_FLAG_SERIAL BIT(3) /* factory-programmed serial number */
#define AT24_FLAG_MAC BIT(2) /* factory-programmed mac address */
#define AT24_FLAG_NO_RDROL BIT(1) /* does not auto-rollover reads to */
/* the next slave address */
void (*setup)(struct nvmem_device *nvmem, void *context);
void *context;
};
#endif /* _LINUX_AT24_H */

View File

@ -1,27 +0,0 @@
/*
* i2c-cbus-gpio.h - CBUS I2C platform_data definition
*
* Copyright (C) 2004-2009 Nokia Corporation
*
* Written by Felipe Balbi and Aaro Koskinen.
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file "COPYING" in the main directory of this
* archive for more details.
*
* 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.
*/
#ifndef __INCLUDE_LINUX_I2C_CBUS_GPIO_H
#define __INCLUDE_LINUX_I2C_CBUS_GPIO_H
struct i2c_cbus_platform_data {
int dat_gpio;
int clk_gpio;
int sel_gpio;
};
#endif /* __INCLUDE_LINUX_I2C_CBUS_GPIO_H */

View File

@ -1,11 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* i2c-ocores.h - definitions for the i2c-ocores interface
*
* Peter Korsgaard <peter@korsgaard.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef _LINUX_I2C_OCORES_H
@ -15,6 +12,7 @@ struct ocores_i2c_platform_data {
u32 reg_shift; /* register offset shift value */
u32 reg_io_width; /* register io read/write width */
u32 clock_khz; /* input clock in kHz */
u32 bus_khz; /* bus clock in kHz */
bool big_endian; /* registers are big endian */
u8 num_devices; /* number of devices in the devices list */
struct i2c_board_info const *devices; /* devices connected to the bus */

View File

@ -138,9 +138,9 @@ TRACE_EVENT_CONDITION(smbus_reply,
TP_PROTO(const struct i2c_adapter *adap,
u16 addr, unsigned short flags,
char read_write, u8 command, int protocol,
const union i2c_smbus_data *data),
TP_ARGS(adap, addr, flags, read_write, command, protocol, data),
TP_CONDITION(read_write == I2C_SMBUS_READ),
const union i2c_smbus_data *data, int res),
TP_ARGS(adap, addr, flags, read_write, command, protocol, data, res),
TP_CONDITION(res >= 0 && read_write == I2C_SMBUS_READ),
TP_STRUCT__entry(
__field(int, adapter_nr )
__field(__u16, addr )